first commit
This commit is contained in:
commit
4622ba9186
339
LICENSE
Normal file
339
LICENSE
Normal file
@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
13
TMessages.iml
Normal file
13
TMessages.iml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
|
80
TMessagesProj/TMessagesProj.iml
Normal file
80
TMessagesProj/TMessagesProj.iml
Normal file
@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="android" name="Android">
|
||||
<configuration>
|
||||
<option name="SELECTED_BUILD_VARIANT" value="Debug" />
|
||||
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
|
||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebug" />
|
||||
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleTest" />
|
||||
<option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" />
|
||||
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
||||
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
|
||||
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
|
||||
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
|
||||
<option name="APK_PATH" value="/build/apk/TMessagesProj-debug-unaligned.apk" />
|
||||
</configuration>
|
||||
</facet>
|
||||
<facet type="android-gradle" name="Android-Gradle">
|
||||
<configuration>
|
||||
<option name="GRADLE_PROJECT_PATH" value=":TMessagesProj" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="false">
|
||||
<output url="file://$MODULE_DIR$/build/classes/debug" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/r/debug" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/aidl/debug" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/rs/debug" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/buildConfig/debug" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/res/rs/debug" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/r/test" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/aidl/test" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/rs/test" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/source/buildConfig/test" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/res/rs/test" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/res" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/assets" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/jni" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/res" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/resources" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/apk" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/assets" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/bundles" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/dependency-cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/incremental" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/libs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/manifests" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/symbols" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Android 4.3 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" exported="" name="support-v4-18.0.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="ComGoogleAndroidGmsPlayServices3159.aar" level="project" />
|
||||
<orderEntry type="library" exported="" name="HockeySDK-3.0.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="native-libs" level="project" />
|
||||
<orderEntry type="library" exported="" name="ComActionbarsherlockActionbarsherlock440.aar" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
|
49
TMessagesProj/build.gradle
Normal file
49
TMessagesProj/build.gradle
Normal file
@ -0,0 +1,49 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:0.5.+'
|
||||
}
|
||||
}
|
||||
apply plugin: 'android'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
task nativeLibsToJar(
|
||||
type: Zip,
|
||||
description: 'create a jar archive of the native libs') {
|
||||
destinationDir file("$buildDir/native-libs")
|
||||
baseName 'native-libs'
|
||||
extension 'jar'
|
||||
from fileTree(dir: 'libs', include: '**/*.so')
|
||||
into 'lib/'
|
||||
}
|
||||
|
||||
tasks.withType(Compile) {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
tasks.withType(Compile) {
|
||||
compileTask -> compileTask.dependsOn(nativeLibsToJar)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.actionbarsherlock:actionbarsherlock:4.4.0@aar'
|
||||
compile 'com.google.android.gms:play-services:3.1.+'
|
||||
compile 'net.hockeyapp.android:HockeySDK:3.0.0'
|
||||
compile 'com.android.support:support-v4:18.0.+'
|
||||
compile fileTree(dir: "$buildDir/native-libs", include: '*.jar')
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 18
|
||||
buildToolsVersion "17.0.0"
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 8
|
||||
targetSdkVersion 18
|
||||
}
|
||||
}
|
19
TMessagesProj/jni/Android.mk
Executable file
19
TMessagesProj/jni/Android.mk
Executable file
@ -0,0 +1,19 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := tmessages
|
||||
LOCAL_CFLAGS = -w
|
||||
LOCAL_LDLIBS := -llog
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
./aes_core.c \
|
||||
./aes_ige.c \
|
||||
./aes_misc.c \
|
||||
./jni.c \
|
||||
./sqlite3.c \
|
||||
./org_telegram_SQLite_SQLiteCursor.c \
|
||||
./org_telegram_SQLite_SQLiteDatabase.c \
|
||||
./org_telegram_SQLite_SQLitePreparedStatement.c \
|
||||
./org_telegram_SQLite.c
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
2
TMessagesProj/jni/Application.mk
Normal file
2
TMessagesProj/jni/Application.mk
Normal file
@ -0,0 +1,2 @@
|
||||
APP_PLATFORM := android-8
|
||||
APP_ABI := armeabi armeabi-v7a x86 mips
|
147
TMessagesProj/jni/aes.h
Normal file
147
TMessagesProj/jni/aes.h
Normal file
@ -0,0 +1,147 @@
|
||||
/* crypto/aes/aes.h -*- mode:C; c-file-style: "eay" -*- */
|
||||
/* ====================================================================
|
||||
* Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this
|
||||
* software must display the following acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||
*
|
||||
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please contact
|
||||
* openssl-core@openssl.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "OpenSSL"
|
||||
* nor may "OpenSSL" appear in their names without prior written
|
||||
* permission of the OpenSSL Project.
|
||||
*
|
||||
* 6. Redistributions of any form whatsoever must retain the following
|
||||
* acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HEADER_AES_H
|
||||
#define HEADER_AES_H
|
||||
|
||||
//#include <openssl/opensslconf.h>
|
||||
|
||||
#ifdef OPENSSL_NO_AES
|
||||
#error AES is disabled.
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define AES_ENCRYPT 1
|
||||
#define AES_DECRYPT 0
|
||||
|
||||
/* Because array size can't be a const in C, the following two are macros.
|
||||
Both sizes are in bytes. */
|
||||
#define AES_MAXNR 14
|
||||
#define AES_BLOCK_SIZE 16
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This should be a hidden type, but EVP requires that the size be known */
|
||||
struct aes_key_st {
|
||||
#ifdef AES_LONG
|
||||
unsigned long rd_key[4 *(AES_MAXNR + 1)];
|
||||
#else
|
||||
unsigned int rd_key[4 *(AES_MAXNR + 1)];
|
||||
#endif
|
||||
int rounds;
|
||||
};
|
||||
typedef struct aes_key_st AES_KEY;
|
||||
|
||||
const char *AES_options(void);
|
||||
|
||||
int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
|
||||
AES_KEY *key);
|
||||
int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
|
||||
AES_KEY *key);
|
||||
|
||||
int private_AES_set_encrypt_key(const unsigned char *userKey, const int bits,
|
||||
AES_KEY *key);
|
||||
int private_AES_set_decrypt_key(const unsigned char *userKey, const int bits,
|
||||
AES_KEY *key);
|
||||
|
||||
void AES_encrypt(const unsigned char *in, unsigned char *out,
|
||||
const AES_KEY *key);
|
||||
void AES_decrypt(const unsigned char *in, unsigned char *out,
|
||||
const AES_KEY *key);
|
||||
|
||||
void AES_ecb_encrypt(const unsigned char *in, unsigned char *out,
|
||||
const AES_KEY *key, const int enc);
|
||||
void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, const int enc);
|
||||
void AES_cfb128_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, int *num, const int enc);
|
||||
void AES_cfb1_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, int *num, const int enc);
|
||||
void AES_cfb8_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, int *num, const int enc);
|
||||
void AES_ofb128_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, int *num);
|
||||
void AES_ctr128_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char ivec[AES_BLOCK_SIZE],
|
||||
unsigned char ecount_buf[AES_BLOCK_SIZE],
|
||||
unsigned int *num);
|
||||
/* NB: the IV is _two_ blocks long */
|
||||
void AES_ige_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, const int enc);
|
||||
/* NB: the IV is _four_ blocks long */
|
||||
void AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
const AES_KEY *key2, const unsigned char *ivec,
|
||||
const int enc);
|
||||
|
||||
int AES_wrap_key(AES_KEY *key, const unsigned char *iv,
|
||||
unsigned char *out,
|
||||
const unsigned char *in, unsigned int inlen);
|
||||
int AES_unwrap_key(AES_KEY *key, const unsigned char *iv,
|
||||
unsigned char *out,
|
||||
const unsigned char *in, unsigned int inlen);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !HEADER_AES_H */
|
1358
TMessagesProj/jni/aes_core.c
Normal file
1358
TMessagesProj/jni/aes_core.c
Normal file
File diff suppressed because it is too large
Load Diff
325
TMessagesProj/jni/aes_ige.c
Normal file
325
TMessagesProj/jni/aes_ige.c
Normal file
@ -0,0 +1,325 @@
|
||||
/* crypto/aes/aes_ige.c -*- mode:C; c-file-style: "eay" -*- */
|
||||
/* ====================================================================
|
||||
* Copyright (c) 2006 The OpenSSL Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this
|
||||
* software must display the following acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||
*
|
||||
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please contact
|
||||
* openssl-core@openssl.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "OpenSSL"
|
||||
* nor may "OpenSSL" appear in their names without prior written
|
||||
* permission of the OpenSSL Project.
|
||||
*
|
||||
* 6. Redistributions of any form whatsoever must retain the following
|
||||
* acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
*/
|
||||
|
||||
//#include "cryptlib.h"
|
||||
|
||||
#include "aes.h"
|
||||
#include "aes_locl.h"
|
||||
#include <assert.h>
|
||||
#define OPENSSL_assert assert
|
||||
|
||||
#define N_WORDS (AES_BLOCK_SIZE / sizeof(unsigned long))
|
||||
typedef struct {
|
||||
unsigned long data[N_WORDS];
|
||||
} aes_block_t;
|
||||
|
||||
/* XXX: probably some better way to do this */
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#define UNALIGNED_MEMOPS_ARE_FAST 1
|
||||
#else
|
||||
#define UNALIGNED_MEMOPS_ARE_FAST 0
|
||||
#endif
|
||||
|
||||
#if UNALIGNED_MEMOPS_ARE_FAST
|
||||
#define load_block(d, s) (d) = *(const aes_block_t *)(s)
|
||||
#define store_block(d, s) *(aes_block_t *)(d) = (s)
|
||||
#else
|
||||
#define load_block(d, s) memcpy((d).data, (s), AES_BLOCK_SIZE)
|
||||
#define store_block(d, s) memcpy((d), (s).data, AES_BLOCK_SIZE)
|
||||
#endif
|
||||
|
||||
/* N.B. The IV for this mode is _twice_ the block size */
|
||||
|
||||
void AES_ige_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, const int enc)
|
||||
{
|
||||
size_t n;
|
||||
size_t len = length;
|
||||
|
||||
OPENSSL_assert(in && out && key && ivec);
|
||||
OPENSSL_assert((AES_ENCRYPT == enc)||(AES_DECRYPT == enc));
|
||||
OPENSSL_assert((length%AES_BLOCK_SIZE) == 0);
|
||||
|
||||
len = length / AES_BLOCK_SIZE;
|
||||
|
||||
if (AES_ENCRYPT == enc)
|
||||
{
|
||||
if (in != out &&
|
||||
(UNALIGNED_MEMOPS_ARE_FAST || ((size_t)in|(size_t)out|(size_t)ivec)%sizeof(long)==0))
|
||||
{
|
||||
aes_block_t *ivp = (aes_block_t *)ivec;
|
||||
aes_block_t *iv2p = (aes_block_t *)(ivec + AES_BLOCK_SIZE);
|
||||
|
||||
while (len)
|
||||
{
|
||||
aes_block_t *inp = (aes_block_t *)in;
|
||||
aes_block_t *outp = (aes_block_t *)out;
|
||||
|
||||
for(n=0 ; n < N_WORDS; ++n)
|
||||
outp->data[n] = inp->data[n] ^ ivp->data[n];
|
||||
AES_encrypt((unsigned char *)outp->data, (unsigned char *)outp->data, key);
|
||||
for(n=0 ; n < N_WORDS; ++n)
|
||||
outp->data[n] ^= iv2p->data[n];
|
||||
ivp = outp;
|
||||
iv2p = inp;
|
||||
--len;
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
memcpy(ivec, ivp->data, AES_BLOCK_SIZE);
|
||||
memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
aes_block_t tmp, tmp2;
|
||||
aes_block_t iv;
|
||||
aes_block_t iv2;
|
||||
|
||||
load_block(iv, ivec);
|
||||
load_block(iv2, ivec + AES_BLOCK_SIZE);
|
||||
|
||||
while (len)
|
||||
{
|
||||
load_block(tmp, in);
|
||||
for(n=0 ; n < N_WORDS; ++n)
|
||||
tmp2.data[n] = tmp.data[n] ^ iv.data[n];
|
||||
AES_encrypt((unsigned char *)tmp2.data, (unsigned char *)tmp2.data, key);
|
||||
for(n=0 ; n < N_WORDS; ++n)
|
||||
tmp2.data[n] ^= iv2.data[n];
|
||||
store_block(out, tmp2);
|
||||
iv = tmp2;
|
||||
iv2 = tmp;
|
||||
--len;
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
memcpy(ivec, iv.data, AES_BLOCK_SIZE);
|
||||
memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (in != out &&
|
||||
(UNALIGNED_MEMOPS_ARE_FAST || ((size_t)in|(size_t)out|(size_t)ivec)%sizeof(long)==0))
|
||||
{
|
||||
aes_block_t *ivp = (aes_block_t *)ivec;
|
||||
aes_block_t *iv2p = (aes_block_t *)(ivec + AES_BLOCK_SIZE);
|
||||
|
||||
while (len)
|
||||
{
|
||||
aes_block_t tmp;
|
||||
aes_block_t *inp = (aes_block_t *)in;
|
||||
aes_block_t *outp = (aes_block_t *)out;
|
||||
|
||||
for(n=0 ; n < N_WORDS; ++n)
|
||||
tmp.data[n] = inp->data[n] ^ iv2p->data[n];
|
||||
AES_decrypt((unsigned char *)tmp.data, (unsigned char *)outp->data, key);
|
||||
for(n=0 ; n < N_WORDS; ++n)
|
||||
outp->data[n] ^= ivp->data[n];
|
||||
ivp = inp;
|
||||
iv2p = outp;
|
||||
--len;
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
memcpy(ivec, ivp->data, AES_BLOCK_SIZE);
|
||||
memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
aes_block_t tmp, tmp2;
|
||||
aes_block_t iv;
|
||||
aes_block_t iv2;
|
||||
|
||||
load_block(iv, ivec);
|
||||
load_block(iv2, ivec + AES_BLOCK_SIZE);
|
||||
|
||||
while (len)
|
||||
{
|
||||
load_block(tmp, in);
|
||||
tmp2 = tmp;
|
||||
for(n=0 ; n < N_WORDS; ++n)
|
||||
tmp.data[n] ^= iv2.data[n];
|
||||
AES_decrypt((unsigned char *)tmp.data, (unsigned char *)tmp.data, key);
|
||||
for(n=0 ; n < N_WORDS; ++n)
|
||||
tmp.data[n] ^= iv.data[n];
|
||||
store_block(out, tmp);
|
||||
iv = tmp2;
|
||||
iv2 = tmp;
|
||||
--len;
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
memcpy(ivec, iv.data, AES_BLOCK_SIZE);
|
||||
memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that its effectively impossible to do biIGE in anything other
|
||||
* than a single pass, so no provision is made for chaining.
|
||||
*/
|
||||
|
||||
/* N.B. The IV for this mode is _four times_ the block size */
|
||||
|
||||
void AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
const AES_KEY *key2, const unsigned char *ivec,
|
||||
const int enc)
|
||||
{
|
||||
size_t n;
|
||||
size_t len = length;
|
||||
unsigned char tmp[AES_BLOCK_SIZE];
|
||||
unsigned char tmp2[AES_BLOCK_SIZE];
|
||||
unsigned char tmp3[AES_BLOCK_SIZE];
|
||||
unsigned char prev[AES_BLOCK_SIZE];
|
||||
const unsigned char *iv;
|
||||
const unsigned char *iv2;
|
||||
|
||||
OPENSSL_assert(in && out && key && ivec);
|
||||
OPENSSL_assert((AES_ENCRYPT == enc)||(AES_DECRYPT == enc));
|
||||
OPENSSL_assert((length%AES_BLOCK_SIZE) == 0);
|
||||
|
||||
if (AES_ENCRYPT == enc)
|
||||
{
|
||||
/* XXX: Do a separate case for when in != out (strictly should
|
||||
check for overlap, too) */
|
||||
|
||||
/* First the forward pass */
|
||||
iv = ivec;
|
||||
iv2 = ivec + AES_BLOCK_SIZE;
|
||||
while (len >= AES_BLOCK_SIZE)
|
||||
{
|
||||
for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
|
||||
out[n] = in[n] ^ iv[n];
|
||||
AES_encrypt(out, out, key);
|
||||
for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
|
||||
out[n] ^= iv2[n];
|
||||
iv = out;
|
||||
memcpy(prev, in, AES_BLOCK_SIZE);
|
||||
iv2 = prev;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
/* And now backwards */
|
||||
iv = ivec + AES_BLOCK_SIZE*2;
|
||||
iv2 = ivec + AES_BLOCK_SIZE*3;
|
||||
len = length;
|
||||
while(len >= AES_BLOCK_SIZE)
|
||||
{
|
||||
out -= AES_BLOCK_SIZE;
|
||||
/* XXX: reduce copies by alternating between buffers */
|
||||
memcpy(tmp, out, AES_BLOCK_SIZE);
|
||||
for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
|
||||
out[n] ^= iv[n];
|
||||
/* hexdump(stdout, "out ^ iv", out, AES_BLOCK_SIZE); */
|
||||
AES_encrypt(out, out, key);
|
||||
/* hexdump(stdout,"enc", out, AES_BLOCK_SIZE); */
|
||||
/* hexdump(stdout,"iv2", iv2, AES_BLOCK_SIZE); */
|
||||
for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
|
||||
out[n] ^= iv2[n];
|
||||
/* hexdump(stdout,"out", out, AES_BLOCK_SIZE); */
|
||||
iv = out;
|
||||
memcpy(prev, tmp, AES_BLOCK_SIZE);
|
||||
iv2 = prev;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* First backwards */
|
||||
iv = ivec + AES_BLOCK_SIZE*2;
|
||||
iv2 = ivec + AES_BLOCK_SIZE*3;
|
||||
in += length;
|
||||
out += length;
|
||||
while (len >= AES_BLOCK_SIZE)
|
||||
{
|
||||
in -= AES_BLOCK_SIZE;
|
||||
out -= AES_BLOCK_SIZE;
|
||||
memcpy(tmp, in, AES_BLOCK_SIZE);
|
||||
memcpy(tmp2, in, AES_BLOCK_SIZE);
|
||||
for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
|
||||
tmp[n] ^= iv2[n];
|
||||
AES_decrypt(tmp, out, key);
|
||||
for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
|
||||
out[n] ^= iv[n];
|
||||
memcpy(tmp3, tmp2, AES_BLOCK_SIZE);
|
||||
iv = tmp3;
|
||||
iv2 = out;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
/* And now forwards */
|
||||
iv = ivec;
|
||||
iv2 = ivec + AES_BLOCK_SIZE;
|
||||
len = length;
|
||||
while (len >= AES_BLOCK_SIZE)
|
||||
{
|
||||
memcpy(tmp, out, AES_BLOCK_SIZE);
|
||||
memcpy(tmp2, out, AES_BLOCK_SIZE);
|
||||
for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
|
||||
tmp[n] ^= iv2[n];
|
||||
AES_decrypt(tmp, out, key);
|
||||
for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
|
||||
out[n] ^= iv[n];
|
||||
memcpy(tmp3, tmp2, AES_BLOCK_SIZE);
|
||||
iv = tmp3;
|
||||
iv2 = out;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
89
TMessagesProj/jni/aes_locl.h
Normal file
89
TMessagesProj/jni/aes_locl.h
Normal file
@ -0,0 +1,89 @@
|
||||
/* crypto/aes/aes.h -*- mode:C; c-file-style: "eay" -*- */
|
||||
/* ====================================================================
|
||||
* Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this
|
||||
* software must display the following acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||
*
|
||||
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please contact
|
||||
* openssl-core@openssl.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "OpenSSL"
|
||||
* nor may "OpenSSL" appear in their names without prior written
|
||||
* permission of the OpenSSL Project.
|
||||
*
|
||||
* 6. Redistributions of any form whatsoever must retain the following
|
||||
* acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HEADER_AES_LOCL_H
|
||||
#define HEADER_AES_LOCL_H
|
||||
|
||||
//#include <openssl/e_os2.h>
|
||||
|
||||
#ifdef OPENSSL_NO_AES
|
||||
#error AES is disabled.
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64))
|
||||
# define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
|
||||
# define GETU32(p) SWAP(*((u32 *)(p)))
|
||||
# define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); }
|
||||
#else
|
||||
# define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]))
|
||||
# define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); }
|
||||
#endif
|
||||
|
||||
#ifdef AES_LONG
|
||||
typedef unsigned long u32;
|
||||
#else
|
||||
typedef unsigned int u32;
|
||||
#endif
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned char u8;
|
||||
|
||||
#define MAXKC (256/32)
|
||||
#define MAXKB (256/8)
|
||||
#define MAXNR 14
|
||||
|
||||
/* This controls loop-unrolling in aes_core.c */
|
||||
#undef FULL_UNROLL
|
||||
|
||||
#endif /* !HEADER_AES_LOCL_H */
|
85
TMessagesProj/jni/aes_misc.c
Normal file
85
TMessagesProj/jni/aes_misc.c
Normal file
@ -0,0 +1,85 @@
|
||||
/* crypto/aes/aes_misc.c -*- mode:C; c-file-style: "eay" -*- */
|
||||
/* ====================================================================
|
||||
* Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this
|
||||
* software must display the following acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||
*
|
||||
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please contact
|
||||
* openssl-core@openssl.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "OpenSSL"
|
||||
* nor may "OpenSSL" appear in their names without prior written
|
||||
* permission of the OpenSSL Project.
|
||||
*
|
||||
* 6. Redistributions of any form whatsoever must retain the following
|
||||
* acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
*/
|
||||
|
||||
//#include <openssl/opensslv.h>
|
||||
//#include <openssl/crypto.h>
|
||||
#include "aes.h"
|
||||
#include "aes_locl.h"
|
||||
|
||||
const char AES_version[]="AES" ;//OPENSSL_VERSION_PTEXT;
|
||||
|
||||
const char *AES_options(void) {
|
||||
#ifdef FULL_UNROLL
|
||||
return "aes(full)";
|
||||
#else
|
||||
return "aes(partial)";
|
||||
#endif
|
||||
}
|
||||
|
||||
/* FIPS wrapper functions to block low level AES calls in FIPS mode */
|
||||
|
||||
int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
|
||||
AES_KEY *key)
|
||||
{
|
||||
#ifdef OPENSSL_FIPS
|
||||
fips_cipher_abort(AES);
|
||||
#endif
|
||||
return private_AES_set_encrypt_key(userKey, bits, key);
|
||||
}
|
||||
|
||||
int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
|
||||
AES_KEY *key)
|
||||
{
|
||||
#ifdef OPENSSL_FIPS
|
||||
fips_cipher_abort(AES);
|
||||
#endif
|
||||
return private_AES_set_decrypt_key(userKey, bits, key);
|
||||
}
|
183
TMessagesProj/jni/jni.c
Normal file
183
TMessagesProj/jni/jni.c
Normal file
@ -0,0 +1,183 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <jni.h>
|
||||
#include <sys/types.h>
|
||||
#include <inttypes.h>
|
||||
#include <android/log.h>
|
||||
#include "aes.h"
|
||||
|
||||
#define LOG_TAG "tmessages_native"
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
|
||||
|
||||
JNIEXPORT jbyteArray Java_org_telegram_messenger_Utilities_aesIgeEncryption(JNIEnv *env, jclass class, jbyteArray _what, jbyteArray _key, jbyteArray _iv, jboolean encrypt, jboolean changeIv) {
|
||||
unsigned char *what = (unsigned char *)(*env)->GetByteArrayElements(env, _what, NULL);
|
||||
unsigned char *key = (unsigned char *)(*env)->GetByteArrayElements(env, _key, NULL);
|
||||
unsigned char *__iv = (unsigned char *)(*env)->GetByteArrayElements(env, _iv, NULL);
|
||||
unsigned char *iv = 0;
|
||||
|
||||
if (!changeIv) {
|
||||
iv = (unsigned char *)malloc((*env)->GetArrayLength(env, _iv));
|
||||
memcpy(iv, __iv, (*env)->GetArrayLength(env, _iv));
|
||||
} else {
|
||||
iv = __iv;
|
||||
}
|
||||
|
||||
int len = (*env)->GetArrayLength(env, _what);
|
||||
AES_KEY akey;
|
||||
if (!encrypt) {
|
||||
AES_set_decrypt_key(key, (*env)->GetArrayLength(env, _key) * 8, &akey);
|
||||
AES_ige_encrypt(what, what, len, &akey, iv, AES_DECRYPT);
|
||||
} else {
|
||||
AES_set_encrypt_key(key, (*env)->GetArrayLength(env, _key) * 8, &akey);
|
||||
AES_ige_encrypt(what, what, len, &akey, iv, AES_ENCRYPT);
|
||||
}
|
||||
(*env)->ReleaseByteArrayElements(env, _what, what, 0);
|
||||
(*env)->ReleaseByteArrayElements(env, _key, key, JNI_ABORT);
|
||||
if (!changeIv) {
|
||||
(*env)->ReleaseByteArrayElements(env, _iv, __iv, JNI_ABORT);
|
||||
free(iv);
|
||||
} else {
|
||||
(*env)->ReleaseByteArrayElements(env, _iv, __iv, 0);
|
||||
}
|
||||
return _what;
|
||||
}
|
||||
|
||||
uint64_t gcd(uint64_t a, uint64_t b){
|
||||
while(a != 0 && b != 0) {
|
||||
while((b & 1) == 0) b >>= 1;
|
||||
while((a & 1) == 0) a >>= 1;
|
||||
if(a > b) a -= b; else b -= a;
|
||||
}
|
||||
return b == 0 ? a : b;
|
||||
}
|
||||
|
||||
JNIEXPORT jlong Java_org_telegram_messenger_Utilities_doPQNative(JNIEnv* env, jclass class, jlong _what) {
|
||||
uint64_t what = _what;
|
||||
int it = 0, i, j;
|
||||
uint64_t g = 0;
|
||||
for (i = 0; i < 3 || it < 1000; i++){
|
||||
int q = ((lrand48() & 15) + 17) % what;
|
||||
uint64_t x = (long long)lrand48() % (what - 1) + 1, y = x;
|
||||
int lim = 1 << (i + 18), j;
|
||||
for(j = 1; j < lim; j++){
|
||||
++it;
|
||||
uint64_t a = x, b = x, c = q;
|
||||
while(b){
|
||||
if(b & 1){
|
||||
c += a;
|
||||
if(c >= what) c -= what;
|
||||
}
|
||||
a += a;
|
||||
if(a >= what) a -= what;
|
||||
b >>= 1;
|
||||
}
|
||||
x = c;
|
||||
uint64_t z = x < y ? what + x - y : x - y;
|
||||
g = gcd(z, what);
|
||||
if(g != 1) break;
|
||||
if(!(j & (j - 1))) y = x;
|
||||
}
|
||||
if(g > 1 && g < what) break;
|
||||
}
|
||||
return g;
|
||||
}
|
||||
|
||||
//sqlite
|
||||
|
||||
/*JNIEXPORT void Java_org_telegram_messenger_Utilities_beginTransaction(JNIEnv* env, jobject object, int dbHandle) {
|
||||
sqlite3 *db = (sqlite3 *)dbHandle;
|
||||
if (db == NULL) {
|
||||
return;
|
||||
}
|
||||
sqlite3_exec(db, "BEGIN", 0, 0, 0);
|
||||
}
|
||||
|
||||
JNIEXPORT void Java_org_telegram_messenger_Utilities_commitTransaction(JNIEnv* env, jobject object, int dbHandle) {
|
||||
sqlite3 *db = (sqlite3 *)dbHandle;
|
||||
if (db == NULL) {
|
||||
return;
|
||||
}
|
||||
sqlite3_exec(db, "COMMIT", 0, 0, 0);
|
||||
}
|
||||
|
||||
int Java_org_telegram_messenger_Utilities_step(JNIEnv* env, jobject object, int statementHandle) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
||||
|
||||
int errcode = 0 ;
|
||||
|
||||
errcode = sqlite3_step(handle);
|
||||
if (errcode == SQLITE_ROW) {
|
||||
return 0;
|
||||
} else if(errcode == SQLITE_DONE) {
|
||||
return 1;
|
||||
} else if(errcode == SQLITE_BUSY) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
throw_sqlite3_exception(env, sqlite3_db_handle(handle), errcode);
|
||||
}
|
||||
|
||||
int Java_org_telegram_messenger_Utilities_columnType(JNIEnv* env, jobject object, int statementHandle, int columnIndex) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
||||
|
||||
return sqlite3_column_type(handle, columnIndex);
|
||||
}
|
||||
|
||||
int Java_org_telegram_messenger_Utilities_columnIsNull(JNIEnv* env, jobject object, int statementHandle, int columnIndex) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
||||
|
||||
int valType = sqlite3_column_type(handle, columnIndex);
|
||||
|
||||
return SQLITE_NULL == valType;
|
||||
}
|
||||
|
||||
int Java_org_telegram_messenger_Utilities_columnIntValue(JNIEnv* env, jobject object, int statementHandle, int columnIndex) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
||||
|
||||
int valType = sqlite3_column_type(handle, columnIndex);
|
||||
if (SQLITE_NULL == valType) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sqlite3_column_int(handle, columnIndex);
|
||||
}
|
||||
|
||||
jdouble Java_org_telegram_messenger_Utilities_columnDoubleValue(JNIEnv* env, jobject object, int statementHandle, int columnIndex) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
||||
|
||||
int valType = sqlite3_column_type(handle, columnIndex);
|
||||
if (SQLITE_NULL == valType) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sqlite3_column_double(handle, columnIndex);
|
||||
}
|
||||
|
||||
jstring Java_org_telegram_messenger_Utilities_columnStringValue(JNIEnv* env, jobject object, int statementHandle, int columnIndex) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
||||
|
||||
const char* str = sqlite3_column_text(handle, columnIndex);
|
||||
if (str != 0) {
|
||||
return (*env)->NewStringUTF(env, str);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
jbyteArray Java_org_telegram_messenger_Utilities_columnByteArrayValue(JNIEnv* env, jobject object, int statementHandle, int columnIndex) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
||||
|
||||
void *buf = sqlite3_column_blob(handle, columnIndex);
|
||||
int length = sqlite3_column_bytes(handle, columnIndex);
|
||||
|
||||
if (buf != 0 && length > 0) {
|
||||
jbyteArray result = (*env)->NewByteArray(env, length);
|
||||
(*env)->SetByteArrayRegion(env, result, 0, length, buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}*/
|
11
TMessagesProj/jni/org_telegram_SQLite.c
Executable file
11
TMessagesProj/jni/org_telegram_SQLite.c
Executable file
@ -0,0 +1,11 @@
|
||||
#include "sqlite3.h"
|
||||
#include "org_telegram_SQLite.h"
|
||||
|
||||
void throw_sqlite3_exception(JNIEnv *env, sqlite3 *handle, int errcode) {
|
||||
if (SQLITE_OK == errcode) {
|
||||
errcode = sqlite3_errcode(handle);
|
||||
}
|
||||
const char *errmsg = sqlite3_errmsg(handle);
|
||||
jclass exClass = (*env)->FindClass(env, "org/telegram/SQLite/SQLiteException");
|
||||
(*env)->ThrowNew(env, exClass, errmsg);
|
||||
}
|
9
TMessagesProj/jni/org_telegram_SQLite.h
Executable file
9
TMessagesProj/jni/org_telegram_SQLite.h
Executable file
@ -0,0 +1,9 @@
|
||||
#ifndef __SQLITE_H__
|
||||
#define __SQLITE_H__
|
||||
|
||||
#include <jni.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
void throw_sqlite3_exception(JNIEnv* env, sqlite3 *handle, int errcode);
|
||||
|
||||
#endif
|
60
TMessagesProj/jni/org_telegram_SQLite_SQLiteCursor.c
Executable file
60
TMessagesProj/jni/org_telegram_SQLite_SQLiteCursor.c
Executable file
@ -0,0 +1,60 @@
|
||||
#include "org_telegram_SQLite.h"
|
||||
|
||||
int Java_org_telegram_SQLite_SQLiteCursor_columnType(JNIEnv *env, jobject object, int statementHandle, int columnIndex) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
||||
return sqlite3_column_type(handle, columnIndex);
|
||||
}
|
||||
|
||||
int Java_org_telegram_SQLite_SQLiteCursor_columnIsNull(JNIEnv *env, jobject object, int statementHandle, int columnIndex) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
||||
int valType = sqlite3_column_type(handle, columnIndex);
|
||||
return SQLITE_NULL == valType;
|
||||
}
|
||||
|
||||
int Java_org_telegram_SQLite_SQLiteCursor_columnIntValue(JNIEnv *env, jobject object, int statementHandle, int columnIndex) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
||||
int valType = sqlite3_column_type(handle, columnIndex);
|
||||
if (SQLITE_NULL == valType) {
|
||||
return 0;
|
||||
}
|
||||
return sqlite3_column_int(handle, columnIndex);
|
||||
}
|
||||
|
||||
long long Java_org_telegram_SQLite_SQLiteCursor_columnLongValue(JNIEnv *env, jobject object, int statementHandle, int columnIndex) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
||||
int valType = sqlite3_column_type(handle, columnIndex);
|
||||
if (SQLITE_NULL == valType) {
|
||||
return 0;
|
||||
}
|
||||
return sqlite3_column_int64(handle, columnIndex);
|
||||
}
|
||||
|
||||
double Java_org_telegram_SQLite_SQLiteCursor_columnDoubleValue(JNIEnv *env, jobject object, int statementHandle, int columnIndex) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
||||
int valType = sqlite3_column_type(handle, columnIndex);
|
||||
if (SQLITE_NULL == valType) {
|
||||
return 0;
|
||||
}
|
||||
return sqlite3_column_double(handle, columnIndex);
|
||||
}
|
||||
|
||||
jstring Java_org_telegram_SQLite_SQLiteCursor_columnStringValue(JNIEnv *env, jobject object, int statementHandle, int columnIndex) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
||||
const char *str = sqlite3_column_text(handle, columnIndex);
|
||||
if (str != 0) {
|
||||
return (*env)->NewStringUTF(env, str);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
jbyteArray Java_org_telegram_SQLite_SQLiteCursor_columnByteArrayValue(JNIEnv *env, jobject object, int statementHandle, int columnIndex) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
||||
void *buf = sqlite3_column_blob(handle, columnIndex);
|
||||
int length = sqlite3_column_bytes(handle, columnIndex);
|
||||
if (buf != 0 && length > 0) {
|
||||
jbyteArray result = (*env)->NewByteArray(env, length);
|
||||
(*env)->SetByteArrayRegion(env, result, 0, length, buf);
|
||||
return result;
|
||||
}
|
||||
return 0;
|
||||
}
|
32
TMessagesProj/jni/org_telegram_SQLite_SQLiteDatabase.c
Executable file
32
TMessagesProj/jni/org_telegram_SQLite_SQLiteDatabase.c
Executable file
@ -0,0 +1,32 @@
|
||||
#include "org_telegram_SQLite.h"
|
||||
|
||||
void Java_org_telegram_SQLite_SQLiteDatabase_closedb(JNIEnv *env, jobject object, int sqliteHandle) {
|
||||
sqlite3 *handle = (sqlite3 *)sqliteHandle;
|
||||
int err = sqlite3_close(handle);
|
||||
if (SQLITE_OK != err) {
|
||||
throw_sqlite3_exception(env, handle, err);
|
||||
}
|
||||
}
|
||||
|
||||
void Java_org_telegram_SQLite_SQLiteDatabase_beginTransaction(JNIEnv *env, jobject object, int sqliteHandle) {
|
||||
sqlite3 *handle = (sqlite3 *)sqliteHandle;
|
||||
sqlite3_exec(handle, "BEGIN", 0, 0, 0);
|
||||
}
|
||||
|
||||
void Java_org_telegram_SQLite_SQLiteDatabase_commitTransaction(JNIEnv *env, jobject object, int sqliteHandle) {
|
||||
sqlite3 *handle = (sqlite3 *)sqliteHandle;
|
||||
sqlite3_exec(handle, "COMMIT", 0, 0, 0);
|
||||
}
|
||||
|
||||
int Java_org_telegram_SQLite_SQLiteDatabase_opendb(JNIEnv *env, jobject object, jstring fileName) {
|
||||
char const *fileNameStr = (*env)->GetStringUTFChars(env, fileName, 0);
|
||||
sqlite3 *handle = 0;
|
||||
int err = sqlite3_open(fileNameStr, &handle);
|
||||
if (SQLITE_OK != err) {
|
||||
throw_sqlite3_exception(env, handle, err);
|
||||
}
|
||||
if (fileNameStr != 0) {
|
||||
(*env)->ReleaseStringUTFChars(env, fileName, fileNameStr);
|
||||
}
|
||||
return (int)handle;
|
||||
}
|
138
TMessagesProj/jni/org_telegram_SQLite_SQLitePreparedStatement.c
Executable file
138
TMessagesProj/jni/org_telegram_SQLite_SQLitePreparedStatement.c
Executable file
@ -0,0 +1,138 @@
|
||||
#include "org_telegram_SQLite.h"
|
||||
|
||||
jfieldID queryArgsCountField;
|
||||
|
||||
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
JNIEnv* env = 0;
|
||||
|
||||
if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
jclass class = (*env)->FindClass(env, "org/telegram/SQLite/SQLitePreparedStatement");
|
||||
queryArgsCountField = (*env)->GetFieldID(env, class, "queryArgsCount", "I");
|
||||
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
||||
|
||||
int Java_org_telegram_SQLite_SQLitePreparedStatement_step(JNIEnv* env, jobject object, int statementHandle) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
||||
|
||||
int errcode = sqlite3_step(handle);
|
||||
if (errcode == SQLITE_ROW) {
|
||||
return 0;
|
||||
} else if(errcode == SQLITE_DONE) {
|
||||
return 1;
|
||||
} else if(errcode == SQLITE_BUSY) {
|
||||
return -1;
|
||||
}
|
||||
throw_sqlite3_exception(env, sqlite3_db_handle(handle), errcode);
|
||||
}
|
||||
|
||||
int Java_org_telegram_SQLite_SQLitePreparedStatement_prepare(JNIEnv *env, jobject object, int sqliteHandle, jstring sql) {
|
||||
sqlite3* handle = (sqlite3 *)sqliteHandle;
|
||||
|
||||
char const *sqlStr = (*env)->GetStringUTFChars(env, sql, 0);
|
||||
|
||||
sqlite3_stmt *stmt_handle;
|
||||
|
||||
int errcode = sqlite3_prepare_v2(handle, sqlStr, -1, &stmt_handle, 0);
|
||||
if (SQLITE_OK != errcode) {
|
||||
throw_sqlite3_exception(env, handle, errcode);
|
||||
} else {
|
||||
int argsCount = sqlite3_bind_parameter_count(stmt_handle);
|
||||
(*env)->SetIntField(env, object, queryArgsCountField, argsCount);
|
||||
}
|
||||
|
||||
if (sqlStr != 0) {
|
||||
(*env)->ReleaseStringUTFChars(env, sql, sqlStr);
|
||||
}
|
||||
|
||||
return (int)stmt_handle;
|
||||
}
|
||||
|
||||
void Java_org_telegram_SQLite_SQLitePreparedStatement_reset(JNIEnv *env, jobject object, int statementHandle) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
||||
|
||||
int errcode = sqlite3_reset(handle);
|
||||
if (SQLITE_OK != errcode) {
|
||||
throw_sqlite3_exception(env, sqlite3_db_handle(handle), errcode);
|
||||
}
|
||||
}
|
||||
|
||||
void Java_org_telegram_SQLite_SQLitePreparedStatement_finalize(JNIEnv *env, jobject object, int statementHandle) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
||||
|
||||
int errcode = sqlite3_finalize (handle);
|
||||
if (SQLITE_OK != errcode) {
|
||||
throw_sqlite3_exception(env, sqlite3_db_handle(handle), errcode);
|
||||
}
|
||||
}
|
||||
|
||||
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindByteArray(JNIEnv *env, jobject object, int statementHandle, int index, jbyteArray value) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle;
|
||||
|
||||
const void *buf = (*env)->GetByteArrayElements(env, value, 0);
|
||||
int length = (*env)->GetArrayLength(env, value);
|
||||
|
||||
int errcode = sqlite3_bind_blob(handle, index, buf, length, SQLITE_STATIC);
|
||||
if (SQLITE_OK != errcode) {
|
||||
throw_sqlite3_exception(env, sqlite3_db_handle(handle), errcode);
|
||||
}
|
||||
|
||||
if (buf != 0) {
|
||||
(*env)->ReleaseByteArrayElements(env, value, buf, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindString(JNIEnv *env, jobject object, int statementHandle, int index, jstring value) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle;
|
||||
|
||||
char const *valueStr = (*env)->GetStringUTFChars(env, value, 0);
|
||||
|
||||
int errcode = sqlite3_bind_text(handle, index, valueStr, -1, SQLITE_TRANSIENT);
|
||||
if (SQLITE_OK != errcode) {
|
||||
throw_sqlite3_exception(env, sqlite3_db_handle(handle), errcode);
|
||||
}
|
||||
|
||||
if (valueStr != 0) {
|
||||
(*env)->ReleaseStringUTFChars(env, value, valueStr);
|
||||
}
|
||||
}
|
||||
|
||||
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindInt(JNIEnv *env, jobject object, int statementHandle, int index, int value) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle;
|
||||
|
||||
int errcode = sqlite3_bind_int(handle, index, value);
|
||||
if (SQLITE_OK != errcode) {
|
||||
throw_sqlite3_exception(env, sqlite3_db_handle(handle), errcode);
|
||||
}
|
||||
}
|
||||
|
||||
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindLong(JNIEnv *env, jobject object, int statementHandle, int index, long long value) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle;
|
||||
|
||||
int errcode = sqlite3_bind_int64(handle, index, value);
|
||||
if (SQLITE_OK != errcode) {
|
||||
throw_sqlite3_exception(env, sqlite3_db_handle(handle), errcode);
|
||||
}
|
||||
}
|
||||
|
||||
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindDouble(JNIEnv* env, jobject object, int statementHandle, int index, double value) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle;
|
||||
|
||||
int errcode = sqlite3_bind_double(handle, index, value);
|
||||
if (SQLITE_OK != errcode) {
|
||||
throw_sqlite3_exception(env, sqlite3_db_handle(handle), errcode);
|
||||
}
|
||||
}
|
||||
|
||||
void Java_org_telegram_SQLite_SQLitePreparedStatement_bindNull(JNIEnv* env, jobject object, int statementHandle, int index) {
|
||||
sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle;
|
||||
|
||||
int errcode = sqlite3_bind_null(handle, index);
|
||||
if (SQLITE_OK != errcode) {
|
||||
throw_sqlite3_exception(env, sqlite3_db_handle(handle), errcode);
|
||||
}
|
||||
}
|
||||
|
140460
TMessagesProj/jni/sqlite3.c
Normal file
140460
TMessagesProj/jni/sqlite3.c
Normal file
File diff suppressed because it is too large
Load Diff
7245
TMessagesProj/jni/sqlite3.h
Normal file
7245
TMessagesProj/jni/sqlite3.h
Normal file
File diff suppressed because it is too large
Load Diff
484
TMessagesProj/jni/sqlite3ext.h
Normal file
484
TMessagesProj/jni/sqlite3ext.h
Normal file
@ -0,0 +1,484 @@
|
||||
/*
|
||||
** 2006 June 7
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This header file defines the SQLite interface for use by
|
||||
** shared libraries that want to be imported as extensions into
|
||||
** an SQLite instance. Shared libraries that intend to be loaded
|
||||
** as extensions by SQLite should #include this file instead of
|
||||
** sqlite3.h.
|
||||
*/
|
||||
#ifndef _SQLITE3EXT_H_
|
||||
#define _SQLITE3EXT_H_
|
||||
#include "sqlite3.h"
|
||||
|
||||
typedef struct sqlite3_api_routines sqlite3_api_routines;
|
||||
|
||||
/*
|
||||
** The following structure holds pointers to all of the SQLite API
|
||||
** routines.
|
||||
**
|
||||
** WARNING: In order to maintain backwards compatibility, add new
|
||||
** interfaces to the end of this structure only. If you insert new
|
||||
** interfaces in the middle of this structure, then older different
|
||||
** versions of SQLite will not be able to load each others' shared
|
||||
** libraries!
|
||||
*/
|
||||
struct sqlite3_api_routines {
|
||||
void * (*aggregate_context)(sqlite3_context*,int nBytes);
|
||||
int (*aggregate_count)(sqlite3_context*);
|
||||
int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
|
||||
int (*bind_double)(sqlite3_stmt*,int,double);
|
||||
int (*bind_int)(sqlite3_stmt*,int,int);
|
||||
int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
|
||||
int (*bind_null)(sqlite3_stmt*,int);
|
||||
int (*bind_parameter_count)(sqlite3_stmt*);
|
||||
int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
|
||||
const char * (*bind_parameter_name)(sqlite3_stmt*,int);
|
||||
int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
|
||||
int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
|
||||
int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
|
||||
int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
|
||||
int (*busy_timeout)(sqlite3*,int ms);
|
||||
int (*changes)(sqlite3*);
|
||||
int (*close)(sqlite3*);
|
||||
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
|
||||
int eTextRep,const char*));
|
||||
int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
|
||||
int eTextRep,const void*));
|
||||
const void * (*column_blob)(sqlite3_stmt*,int iCol);
|
||||
int (*column_bytes)(sqlite3_stmt*,int iCol);
|
||||
int (*column_bytes16)(sqlite3_stmt*,int iCol);
|
||||
int (*column_count)(sqlite3_stmt*pStmt);
|
||||
const char * (*column_database_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_database_name16)(sqlite3_stmt*,int);
|
||||
const char * (*column_decltype)(sqlite3_stmt*,int i);
|
||||
const void * (*column_decltype16)(sqlite3_stmt*,int);
|
||||
double (*column_double)(sqlite3_stmt*,int iCol);
|
||||
int (*column_int)(sqlite3_stmt*,int iCol);
|
||||
sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol);
|
||||
const char * (*column_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_name16)(sqlite3_stmt*,int);
|
||||
const char * (*column_origin_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_origin_name16)(sqlite3_stmt*,int);
|
||||
const char * (*column_table_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_table_name16)(sqlite3_stmt*,int);
|
||||
const unsigned char * (*column_text)(sqlite3_stmt*,int iCol);
|
||||
const void * (*column_text16)(sqlite3_stmt*,int iCol);
|
||||
int (*column_type)(sqlite3_stmt*,int iCol);
|
||||
sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
|
||||
void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
|
||||
int (*complete)(const char*sql);
|
||||
int (*complete16)(const void*sql);
|
||||
int (*create_collation)(sqlite3*,const char*,int,void*,
|
||||
int(*)(void*,int,const void*,int,const void*));
|
||||
int (*create_collation16)(sqlite3*,const void*,int,void*,
|
||||
int(*)(void*,int,const void*,int,const void*));
|
||||
int (*create_function)(sqlite3*,const char*,int,int,void*,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*));
|
||||
int (*create_function16)(sqlite3*,const void*,int,int,void*,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*));
|
||||
int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
|
||||
int (*data_count)(sqlite3_stmt*pStmt);
|
||||
sqlite3 * (*db_handle)(sqlite3_stmt*);
|
||||
int (*declare_vtab)(sqlite3*,const char*);
|
||||
int (*enable_shared_cache)(int);
|
||||
int (*errcode)(sqlite3*db);
|
||||
const char * (*errmsg)(sqlite3*);
|
||||
const void * (*errmsg16)(sqlite3*);
|
||||
int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);
|
||||
int (*expired)(sqlite3_stmt*);
|
||||
int (*finalize)(sqlite3_stmt*pStmt);
|
||||
void (*free)(void*);
|
||||
void (*free_table)(char**result);
|
||||
int (*get_autocommit)(sqlite3*);
|
||||
void * (*get_auxdata)(sqlite3_context*,int);
|
||||
int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
|
||||
int (*global_recover)(void);
|
||||
void (*interruptx)(sqlite3*);
|
||||
sqlite_int64 (*last_insert_rowid)(sqlite3*);
|
||||
const char * (*libversion)(void);
|
||||
int (*libversion_number)(void);
|
||||
void *(*malloc)(int);
|
||||
char * (*mprintf)(const char*,...);
|
||||
int (*open)(const char*,sqlite3**);
|
||||
int (*open16)(const void*,sqlite3**);
|
||||
int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
|
||||
int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
||||
void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);
|
||||
void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
|
||||
void *(*realloc)(void*,int);
|
||||
int (*reset)(sqlite3_stmt*pStmt);
|
||||
void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_double)(sqlite3_context*,double);
|
||||
void (*result_error)(sqlite3_context*,const char*,int);
|
||||
void (*result_error16)(sqlite3_context*,const void*,int);
|
||||
void (*result_int)(sqlite3_context*,int);
|
||||
void (*result_int64)(sqlite3_context*,sqlite_int64);
|
||||
void (*result_null)(sqlite3_context*);
|
||||
void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));
|
||||
void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_value)(sqlite3_context*,sqlite3_value*);
|
||||
void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
|
||||
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
|
||||
const char*,const char*),void*);
|
||||
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
|
||||
char * (*snprintf)(int,char*,const char*,...);
|
||||
int (*step)(sqlite3_stmt*);
|
||||
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
|
||||
char const**,char const**,int*,int*,int*);
|
||||
void (*thread_cleanup)(void);
|
||||
int (*total_changes)(sqlite3*);
|
||||
void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
|
||||
int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
|
||||
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
|
||||
sqlite_int64),void*);
|
||||
void * (*user_data)(sqlite3_context*);
|
||||
const void * (*value_blob)(sqlite3_value*);
|
||||
int (*value_bytes)(sqlite3_value*);
|
||||
int (*value_bytes16)(sqlite3_value*);
|
||||
double (*value_double)(sqlite3_value*);
|
||||
int (*value_int)(sqlite3_value*);
|
||||
sqlite_int64 (*value_int64)(sqlite3_value*);
|
||||
int (*value_numeric_type)(sqlite3_value*);
|
||||
const unsigned char * (*value_text)(sqlite3_value*);
|
||||
const void * (*value_text16)(sqlite3_value*);
|
||||
const void * (*value_text16be)(sqlite3_value*);
|
||||
const void * (*value_text16le)(sqlite3_value*);
|
||||
int (*value_type)(sqlite3_value*);
|
||||
char *(*vmprintf)(const char*,va_list);
|
||||
/* Added ??? */
|
||||
int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
|
||||
/* Added by 3.3.13 */
|
||||
int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
|
||||
int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
||||
int (*clear_bindings)(sqlite3_stmt*);
|
||||
/* Added by 3.4.1 */
|
||||
int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
|
||||
void (*xDestroy)(void *));
|
||||
/* Added by 3.5.0 */
|
||||
int (*bind_zeroblob)(sqlite3_stmt*,int,int);
|
||||
int (*blob_bytes)(sqlite3_blob*);
|
||||
int (*blob_close)(sqlite3_blob*);
|
||||
int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
|
||||
int,sqlite3_blob**);
|
||||
int (*blob_read)(sqlite3_blob*,void*,int,int);
|
||||
int (*blob_write)(sqlite3_blob*,const void*,int,int);
|
||||
int (*create_collation_v2)(sqlite3*,const char*,int,void*,
|
||||
int(*)(void*,int,const void*,int,const void*),
|
||||
void(*)(void*));
|
||||
int (*file_control)(sqlite3*,const char*,int,void*);
|
||||
sqlite3_int64 (*memory_highwater)(int);
|
||||
sqlite3_int64 (*memory_used)(void);
|
||||
sqlite3_mutex *(*mutex_alloc)(int);
|
||||
void (*mutex_enter)(sqlite3_mutex*);
|
||||
void (*mutex_free)(sqlite3_mutex*);
|
||||
void (*mutex_leave)(sqlite3_mutex*);
|
||||
int (*mutex_try)(sqlite3_mutex*);
|
||||
int (*open_v2)(const char*,sqlite3**,int,const char*);
|
||||
int (*release_memory)(int);
|
||||
void (*result_error_nomem)(sqlite3_context*);
|
||||
void (*result_error_toobig)(sqlite3_context*);
|
||||
int (*sleep)(int);
|
||||
void (*soft_heap_limit)(int);
|
||||
sqlite3_vfs *(*vfs_find)(const char*);
|
||||
int (*vfs_register)(sqlite3_vfs*,int);
|
||||
int (*vfs_unregister)(sqlite3_vfs*);
|
||||
int (*xthreadsafe)(void);
|
||||
void (*result_zeroblob)(sqlite3_context*,int);
|
||||
void (*result_error_code)(sqlite3_context*,int);
|
||||
int (*test_control)(int, ...);
|
||||
void (*randomness)(int,void*);
|
||||
sqlite3 *(*context_db_handle)(sqlite3_context*);
|
||||
int (*extended_result_codes)(sqlite3*,int);
|
||||
int (*limit)(sqlite3*,int,int);
|
||||
sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
|
||||
const char *(*sql)(sqlite3_stmt*);
|
||||
int (*status)(int,int*,int*,int);
|
||||
int (*backup_finish)(sqlite3_backup*);
|
||||
sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*);
|
||||
int (*backup_pagecount)(sqlite3_backup*);
|
||||
int (*backup_remaining)(sqlite3_backup*);
|
||||
int (*backup_step)(sqlite3_backup*,int);
|
||||
const char *(*compileoption_get)(int);
|
||||
int (*compileoption_used)(const char*);
|
||||
int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void(*xDestroy)(void*));
|
||||
int (*db_config)(sqlite3*,int,...);
|
||||
sqlite3_mutex *(*db_mutex)(sqlite3*);
|
||||
int (*db_status)(sqlite3*,int,int*,int*,int);
|
||||
int (*extended_errcode)(sqlite3*);
|
||||
void (*log)(int,const char*,...);
|
||||
sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64);
|
||||
const char *(*sourceid)(void);
|
||||
int (*stmt_status)(sqlite3_stmt*,int,int);
|
||||
int (*strnicmp)(const char*,const char*,int);
|
||||
int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*);
|
||||
int (*wal_autocheckpoint)(sqlite3*,int);
|
||||
int (*wal_checkpoint)(sqlite3*,const char*);
|
||||
void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
|
||||
int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
|
||||
int (*vtab_config)(sqlite3*,int op,...);
|
||||
int (*vtab_on_conflict)(sqlite3*);
|
||||
/* Version 3.7.16 and later */
|
||||
int (*close_v2)(sqlite3*);
|
||||
const char *(*db_filename)(sqlite3*,const char*);
|
||||
int (*db_readonly)(sqlite3*,const char*);
|
||||
int (*db_release_memory)(sqlite3*);
|
||||
const char *(*errstr)(int);
|
||||
int (*stmt_busy)(sqlite3_stmt*);
|
||||
int (*stmt_readonly)(sqlite3_stmt*);
|
||||
int (*stricmp)(const char*,const char*);
|
||||
int (*uri_boolean)(const char*,const char*,int);
|
||||
sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
|
||||
const char *(*uri_parameter)(const char*,const char*);
|
||||
char *(*vsnprintf)(int,char*,const char*,va_list);
|
||||
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
|
||||
};
|
||||
|
||||
/*
|
||||
** The following macros redefine the API routines so that they are
|
||||
** redirected throught the global sqlite3_api structure.
|
||||
**
|
||||
** This header file is also used by the loadext.c source file
|
||||
** (part of the main SQLite library - not an extension) so that
|
||||
** it can get access to the sqlite3_api_routines structure
|
||||
** definition. But the main library does not want to redefine
|
||||
** the API. So the redefinition macros are only valid if the
|
||||
** SQLITE_CORE macros is undefined.
|
||||
*/
|
||||
#ifndef SQLITE_CORE
|
||||
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
|
||||
#endif
|
||||
#define sqlite3_bind_blob sqlite3_api->bind_blob
|
||||
#define sqlite3_bind_double sqlite3_api->bind_double
|
||||
#define sqlite3_bind_int sqlite3_api->bind_int
|
||||
#define sqlite3_bind_int64 sqlite3_api->bind_int64
|
||||
#define sqlite3_bind_null sqlite3_api->bind_null
|
||||
#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
|
||||
#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
|
||||
#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
|
||||
#define sqlite3_bind_text sqlite3_api->bind_text
|
||||
#define sqlite3_bind_text16 sqlite3_api->bind_text16
|
||||
#define sqlite3_bind_value sqlite3_api->bind_value
|
||||
#define sqlite3_busy_handler sqlite3_api->busy_handler
|
||||
#define sqlite3_busy_timeout sqlite3_api->busy_timeout
|
||||
#define sqlite3_changes sqlite3_api->changes
|
||||
#define sqlite3_close sqlite3_api->close
|
||||
#define sqlite3_collation_needed sqlite3_api->collation_needed
|
||||
#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
|
||||
#define sqlite3_column_blob sqlite3_api->column_blob
|
||||
#define sqlite3_column_bytes sqlite3_api->column_bytes
|
||||
#define sqlite3_column_bytes16 sqlite3_api->column_bytes16
|
||||
#define sqlite3_column_count sqlite3_api->column_count
|
||||
#define sqlite3_column_database_name sqlite3_api->column_database_name
|
||||
#define sqlite3_column_database_name16 sqlite3_api->column_database_name16
|
||||
#define sqlite3_column_decltype sqlite3_api->column_decltype
|
||||
#define sqlite3_column_decltype16 sqlite3_api->column_decltype16
|
||||
#define sqlite3_column_double sqlite3_api->column_double
|
||||
#define sqlite3_column_int sqlite3_api->column_int
|
||||
#define sqlite3_column_int64 sqlite3_api->column_int64
|
||||
#define sqlite3_column_name sqlite3_api->column_name
|
||||
#define sqlite3_column_name16 sqlite3_api->column_name16
|
||||
#define sqlite3_column_origin_name sqlite3_api->column_origin_name
|
||||
#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16
|
||||
#define sqlite3_column_table_name sqlite3_api->column_table_name
|
||||
#define sqlite3_column_table_name16 sqlite3_api->column_table_name16
|
||||
#define sqlite3_column_text sqlite3_api->column_text
|
||||
#define sqlite3_column_text16 sqlite3_api->column_text16
|
||||
#define sqlite3_column_type sqlite3_api->column_type
|
||||
#define sqlite3_column_value sqlite3_api->column_value
|
||||
#define sqlite3_commit_hook sqlite3_api->commit_hook
|
||||
#define sqlite3_complete sqlite3_api->complete
|
||||
#define sqlite3_complete16 sqlite3_api->complete16
|
||||
#define sqlite3_create_collation sqlite3_api->create_collation
|
||||
#define sqlite3_create_collation16 sqlite3_api->create_collation16
|
||||
#define sqlite3_create_function sqlite3_api->create_function
|
||||
#define sqlite3_create_function16 sqlite3_api->create_function16
|
||||
#define sqlite3_create_module sqlite3_api->create_module
|
||||
#define sqlite3_create_module_v2 sqlite3_api->create_module_v2
|
||||
#define sqlite3_data_count sqlite3_api->data_count
|
||||
#define sqlite3_db_handle sqlite3_api->db_handle
|
||||
#define sqlite3_declare_vtab sqlite3_api->declare_vtab
|
||||
#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache
|
||||
#define sqlite3_errcode sqlite3_api->errcode
|
||||
#define sqlite3_errmsg sqlite3_api->errmsg
|
||||
#define sqlite3_errmsg16 sqlite3_api->errmsg16
|
||||
#define sqlite3_exec sqlite3_api->exec
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_expired sqlite3_api->expired
|
||||
#endif
|
||||
#define sqlite3_finalize sqlite3_api->finalize
|
||||
#define sqlite3_free sqlite3_api->free
|
||||
#define sqlite3_free_table sqlite3_api->free_table
|
||||
#define sqlite3_get_autocommit sqlite3_api->get_autocommit
|
||||
#define sqlite3_get_auxdata sqlite3_api->get_auxdata
|
||||
#define sqlite3_get_table sqlite3_api->get_table
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_global_recover sqlite3_api->global_recover
|
||||
#endif
|
||||
#define sqlite3_interrupt sqlite3_api->interruptx
|
||||
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
|
||||
#define sqlite3_libversion sqlite3_api->libversion
|
||||
#define sqlite3_libversion_number sqlite3_api->libversion_number
|
||||
#define sqlite3_malloc sqlite3_api->malloc
|
||||
#define sqlite3_mprintf sqlite3_api->mprintf
|
||||
#define sqlite3_open sqlite3_api->open
|
||||
#define sqlite3_open16 sqlite3_api->open16
|
||||
#define sqlite3_prepare sqlite3_api->prepare
|
||||
#define sqlite3_prepare16 sqlite3_api->prepare16
|
||||
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||
#define sqlite3_profile sqlite3_api->profile
|
||||
#define sqlite3_progress_handler sqlite3_api->progress_handler
|
||||
#define sqlite3_realloc sqlite3_api->realloc
|
||||
#define sqlite3_reset sqlite3_api->reset
|
||||
#define sqlite3_result_blob sqlite3_api->result_blob
|
||||
#define sqlite3_result_double sqlite3_api->result_double
|
||||
#define sqlite3_result_error sqlite3_api->result_error
|
||||
#define sqlite3_result_error16 sqlite3_api->result_error16
|
||||
#define sqlite3_result_int sqlite3_api->result_int
|
||||
#define sqlite3_result_int64 sqlite3_api->result_int64
|
||||
#define sqlite3_result_null sqlite3_api->result_null
|
||||
#define sqlite3_result_text sqlite3_api->result_text
|
||||
#define sqlite3_result_text16 sqlite3_api->result_text16
|
||||
#define sqlite3_result_text16be sqlite3_api->result_text16be
|
||||
#define sqlite3_result_text16le sqlite3_api->result_text16le
|
||||
#define sqlite3_result_value sqlite3_api->result_value
|
||||
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
|
||||
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
|
||||
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
|
||||
#define sqlite3_snprintf sqlite3_api->snprintf
|
||||
#define sqlite3_step sqlite3_api->step
|
||||
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
|
||||
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
|
||||
#define sqlite3_total_changes sqlite3_api->total_changes
|
||||
#define sqlite3_trace sqlite3_api->trace
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
|
||||
#endif
|
||||
#define sqlite3_update_hook sqlite3_api->update_hook
|
||||
#define sqlite3_user_data sqlite3_api->user_data
|
||||
#define sqlite3_value_blob sqlite3_api->value_blob
|
||||
#define sqlite3_value_bytes sqlite3_api->value_bytes
|
||||
#define sqlite3_value_bytes16 sqlite3_api->value_bytes16
|
||||
#define sqlite3_value_double sqlite3_api->value_double
|
||||
#define sqlite3_value_int sqlite3_api->value_int
|
||||
#define sqlite3_value_int64 sqlite3_api->value_int64
|
||||
#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type
|
||||
#define sqlite3_value_text sqlite3_api->value_text
|
||||
#define sqlite3_value_text16 sqlite3_api->value_text16
|
||||
#define sqlite3_value_text16be sqlite3_api->value_text16be
|
||||
#define sqlite3_value_text16le sqlite3_api->value_text16le
|
||||
#define sqlite3_value_type sqlite3_api->value_type
|
||||
#define sqlite3_vmprintf sqlite3_api->vmprintf
|
||||
#define sqlite3_overload_function sqlite3_api->overload_function
|
||||
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||
#define sqlite3_clear_bindings sqlite3_api->clear_bindings
|
||||
#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob
|
||||
#define sqlite3_blob_bytes sqlite3_api->blob_bytes
|
||||
#define sqlite3_blob_close sqlite3_api->blob_close
|
||||
#define sqlite3_blob_open sqlite3_api->blob_open
|
||||
#define sqlite3_blob_read sqlite3_api->blob_read
|
||||
#define sqlite3_blob_write sqlite3_api->blob_write
|
||||
#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2
|
||||
#define sqlite3_file_control sqlite3_api->file_control
|
||||
#define sqlite3_memory_highwater sqlite3_api->memory_highwater
|
||||
#define sqlite3_memory_used sqlite3_api->memory_used
|
||||
#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc
|
||||
#define sqlite3_mutex_enter sqlite3_api->mutex_enter
|
||||
#define sqlite3_mutex_free sqlite3_api->mutex_free
|
||||
#define sqlite3_mutex_leave sqlite3_api->mutex_leave
|
||||
#define sqlite3_mutex_try sqlite3_api->mutex_try
|
||||
#define sqlite3_open_v2 sqlite3_api->open_v2
|
||||
#define sqlite3_release_memory sqlite3_api->release_memory
|
||||
#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem
|
||||
#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig
|
||||
#define sqlite3_sleep sqlite3_api->sleep
|
||||
#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit
|
||||
#define sqlite3_vfs_find sqlite3_api->vfs_find
|
||||
#define sqlite3_vfs_register sqlite3_api->vfs_register
|
||||
#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister
|
||||
#define sqlite3_threadsafe sqlite3_api->xthreadsafe
|
||||
#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob
|
||||
#define sqlite3_result_error_code sqlite3_api->result_error_code
|
||||
#define sqlite3_test_control sqlite3_api->test_control
|
||||
#define sqlite3_randomness sqlite3_api->randomness
|
||||
#define sqlite3_context_db_handle sqlite3_api->context_db_handle
|
||||
#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes
|
||||
#define sqlite3_limit sqlite3_api->limit
|
||||
#define sqlite3_next_stmt sqlite3_api->next_stmt
|
||||
#define sqlite3_sql sqlite3_api->sql
|
||||
#define sqlite3_status sqlite3_api->status
|
||||
#define sqlite3_backup_finish sqlite3_api->backup_finish
|
||||
#define sqlite3_backup_init sqlite3_api->backup_init
|
||||
#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount
|
||||
#define sqlite3_backup_remaining sqlite3_api->backup_remaining
|
||||
#define sqlite3_backup_step sqlite3_api->backup_step
|
||||
#define sqlite3_compileoption_get sqlite3_api->compileoption_get
|
||||
#define sqlite3_compileoption_used sqlite3_api->compileoption_used
|
||||
#define sqlite3_create_function_v2 sqlite3_api->create_function_v2
|
||||
#define sqlite3_db_config sqlite3_api->db_config
|
||||
#define sqlite3_db_mutex sqlite3_api->db_mutex
|
||||
#define sqlite3_db_status sqlite3_api->db_status
|
||||
#define sqlite3_extended_errcode sqlite3_api->extended_errcode
|
||||
#define sqlite3_log sqlite3_api->log
|
||||
#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64
|
||||
#define sqlite3_sourceid sqlite3_api->sourceid
|
||||
#define sqlite3_stmt_status sqlite3_api->stmt_status
|
||||
#define sqlite3_strnicmp sqlite3_api->strnicmp
|
||||
#define sqlite3_unlock_notify sqlite3_api->unlock_notify
|
||||
#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
|
||||
#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
|
||||
#define sqlite3_wal_hook sqlite3_api->wal_hook
|
||||
#define sqlite3_blob_reopen sqlite3_api->blob_reopen
|
||||
#define sqlite3_vtab_config sqlite3_api->vtab_config
|
||||
#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
|
||||
/* Version 3.7.16 and later */
|
||||
#define sqlite3_close_v2 sqlite3_api->close_v2
|
||||
#define sqlite3_db_filename sqlite3_api->db_filename
|
||||
#define sqlite3_db_readonly sqlite3_api->db_readonly
|
||||
#define sqlite3_db_release_memory sqlite3_api->db_release_memory
|
||||
#define sqlite3_errstr sqlite3_api->errstr
|
||||
#define sqlite3_stmt_busy sqlite3_api->stmt_busy
|
||||
#define sqlite3_stmt_readonly sqlite3_api->stmt_readonly
|
||||
#define sqlite3_stricmp sqlite3_api->stricmp
|
||||
#define sqlite3_uri_boolean sqlite3_api->uri_boolean
|
||||
#define sqlite3_uri_int64 sqlite3_api->uri_int64
|
||||
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
|
||||
#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf
|
||||
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
|
||||
#endif /* SQLITE_CORE */
|
||||
|
||||
#ifndef SQLITE_CORE
|
||||
/* This case when the file really is being compiled as a loadable
|
||||
** extension */
|
||||
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
|
||||
# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v;
|
||||
#else
|
||||
/* This case when the file is being statically linked into the
|
||||
** application */
|
||||
# define SQLITE_EXTENSION_INIT1 /*no-op*/
|
||||
# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */
|
||||
#endif
|
||||
|
||||
#endif /* _SQLITE3EXT_H_ */
|
BIN
TMessagesProj/libs/HockeySDK-3.0.0.jar
Normal file
BIN
TMessagesProj/libs/HockeySDK-3.0.0.jar
Normal file
Binary file not shown.
BIN
TMessagesProj/libs/armeabi-v7a/libtmessages.so
Executable file
BIN
TMessagesProj/libs/armeabi-v7a/libtmessages.so
Executable file
Binary file not shown.
BIN
TMessagesProj/libs/armeabi/libtmessages.so
Executable file
BIN
TMessagesProj/libs/armeabi/libtmessages.so
Executable file
Binary file not shown.
BIN
TMessagesProj/libs/mips/libtmessages.so
Executable file
BIN
TMessagesProj/libs/mips/libtmessages.so
Executable file
Binary file not shown.
BIN
TMessagesProj/libs/x86/libtmessages.so
Executable file
BIN
TMessagesProj/libs/x86/libtmessages.so
Executable file
Binary file not shown.
157
TMessagesProj/src/main/AndroidManifest.xml
Normal file
157
TMessagesProj/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,157 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.telegram.messenger"
|
||||
android:versionCode="91"
|
||||
android:versionName="1.2.4">
|
||||
|
||||
<supports-screens android:anyDensity="true"
|
||||
android:smallScreens="true"
|
||||
android:normalScreens="true"
|
||||
android:largeScreens="true"
|
||||
android:resizeable="true"
|
||||
android:xlargeScreens="true"/>
|
||||
|
||||
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18" />
|
||||
|
||||
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>
|
||||
<uses-feature android:name="android.hardware.telephony" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.location.gps" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.location.network" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.location" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.LOCATION" android:required="false" />
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_SMS" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
|
||||
<uses-permission android:name="org.telegram.messenger.permission.MAPS_RECEIVE"/>
|
||||
<uses-permission android:name="org.telegram.messenger.permission.C2D_MESSAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/>
|
||||
<uses-permission android:name="android.permission.READ_PROFILE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/>
|
||||
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/>
|
||||
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
|
||||
<permission android:name="org.telegram.messenger.permission.MAPS_RECEIVE" android:protectionLevel="signature"/>
|
||||
<permission android:name="org.telegram.messenger.permission.C2D_MESSAGE" android:protectionLevel="signature" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/AppName"
|
||||
android:theme="@style/Theme.Sherlock.Light"
|
||||
android:name="org.telegram.ui.ApplicationLoader"
|
||||
android:hardwareAccelerated="true">
|
||||
|
||||
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="your-google-maps-api-key-here" />
|
||||
|
||||
<activity
|
||||
android:name="org.telegram.ui.LaunchActivity"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<data android:mimeType="image/*"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<data android:mimeType="video/*"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<data android:mimeType="text/plain"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<data android:mimeType="vnd.android.cursor.item/vnd.org.telegram.messenger.android.profile"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name="org.telegram.ui.LoginActivity"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
|
||||
</activity>
|
||||
<activity
|
||||
android:name="org.telegram.ui.IntroActivity"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
|
||||
</activity>
|
||||
<activity
|
||||
android:name="org.telegram.ui.ApplicationActivity"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:theme="@style/Theme.TMessages"
|
||||
android:hardwareAccelerated="true"
|
||||
android:launchMode="singleTask"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
|
||||
</activity>
|
||||
<activity
|
||||
android:name="org.telegram.ui.GalleryImageViewer"
|
||||
android:theme="@style/Theme.TMessages.Gallery"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
|
||||
</activity>
|
||||
|
||||
|
||||
<activity android:name="net.hockeyapp.android.UpdateActivity" />
|
||||
|
||||
<receiver android:name="org.telegram.messenger.SmsListener">
|
||||
<intent-filter>
|
||||
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name="org.telegram.messenger.GcmBroadcastReceiver"
|
||||
android:permission="com.google.android.c2dm.permission.SEND" >
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
|
||||
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
|
||||
<category android:name="org.telegram.messenger" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<service android:name="org.telegram.messenger.AuthenticatorService"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.accounts.AccountAuthenticator"/>
|
||||
</intent-filter>
|
||||
<meta-data android:name="android.accounts.AccountAuthenticator"
|
||||
android:resource="@xml/auth"/>
|
||||
</service>
|
||||
|
||||
<service android:name="org.telegram.messenger.ContactsSyncAdapterService"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.content.SyncAdapter" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="android.content.SyncAdapter"
|
||||
android:resource="@xml/sync_contacts" />
|
||||
<meta-data android:name="android.provider.CONTACTS_STRUCTURE"
|
||||
android:resource="@xml/contacts" />
|
||||
</service>
|
||||
|
||||
<uses-library android:name="com.google.android.maps" android:required="false"/>
|
||||
</application>
|
||||
|
||||
</manifest>
|
BIN
TMessagesProj/src/main/assets/PhoneFormats.dat
Normal file
BIN
TMessagesProj/src/main/assets/PhoneFormats.dat
Normal file
Binary file not shown.
236
TMessagesProj/src/main/assets/countries.txt
Normal file
236
TMessagesProj/src/main/assets/countries.txt
Normal file
@ -0,0 +1,236 @@
|
||||
6723;NF;Norfolk Island
|
||||
5999;CW;Curaçao
|
||||
1939;PR;Puerto Rico
|
||||
1876;JM;Jamaica
|
||||
1869;KN;Saint Kitts and Nevis
|
||||
1868;TT;Trinidad and Tobago
|
||||
1849;DO;Dominican Republic
|
||||
1829;DO;Dominican Republic
|
||||
1809;DO;Dominican Republic
|
||||
1787;PR;Puerto Rico
|
||||
1784;VC;Saint Vincent and the Grenadines
|
||||
1767;DM;Dominica
|
||||
1758;LC;Saint Lucia
|
||||
1721;SX;Bonaire, Sint Eustatius and Saba
|
||||
1684;AS;American Samoa
|
||||
1671;GU;Guam
|
||||
1670;MP;Northern Mariana Islands
|
||||
1664;MS;Montserrat
|
||||
1649;TC;Turks and Caicos Islands
|
||||
1473;GD;Grenada
|
||||
1441;BM;Bermuda
|
||||
1345;KY;Cayman Islands
|
||||
1340;VI;US Virgin Islands
|
||||
1284;VG;British Virgin Islands
|
||||
1268;AG;Antigua and Barbuda
|
||||
1264;AI;Anguilla
|
||||
1246;BB;Barbados
|
||||
1242;BS;Bahamas
|
||||
998;UZ;Uzbekistan
|
||||
996;KG;Kyrgyzstan
|
||||
995;GE;Georgia
|
||||
994;AZ;Azerbaijan
|
||||
993;TM;Turkmenistan
|
||||
992;TJ;Tajikistan
|
||||
977;NP;Nepal
|
||||
976;MN;Mongolia
|
||||
975;BT;Bhutan
|
||||
974;QA;Qatar
|
||||
973;BH;Bahrain
|
||||
972;IL;Israel
|
||||
971;AE;United Arab Emirates
|
||||
970;PS;Palestine
|
||||
968;OM;Oman
|
||||
967;YE;Yemen
|
||||
966;SA;Saudi Arabia
|
||||
965;KW;Kuwait
|
||||
964;IQ;Iraq
|
||||
963;SY;Syria
|
||||
962;JO;Jordan
|
||||
961;LB;Lebanon
|
||||
960;MV;Maldives
|
||||
886;TW;Taiwan
|
||||
880;BD;Bangladesh
|
||||
856;LA;Laos
|
||||
855;KH;Cambodia
|
||||
853;MO;Macau
|
||||
852;HK;Hong Kong
|
||||
850;KP;North Korea
|
||||
692;MH;Marshall Islands
|
||||
691;FM;Micronesia
|
||||
690;TK;Tokelau
|
||||
689;PF;French Polynesia
|
||||
688;TV;Tuvalu
|
||||
687;NC;New Caledonia
|
||||
686;KI;Kiribati
|
||||
685;WS;Samoa
|
||||
683;NU;Niue
|
||||
682;CK;Cook Islands
|
||||
681;WF;Wallis and Futuna
|
||||
680;PW;Palau
|
||||
679;FJ;Fiji
|
||||
678;VU;Vanuatu
|
||||
677;SB;Solomon Islands
|
||||
676;TO;Tonga
|
||||
675;PG;Papua New Guinea
|
||||
674;NR;Nauru
|
||||
673;BN;Brunei Darussalam
|
||||
672;AU;Australia
|
||||
670;TL;East Timor
|
||||
599;BQ;Sint Maarten
|
||||
598;UY;Uruguay
|
||||
597;SR;Suriname
|
||||
596;MQ;Martinique
|
||||
595;PY;Paraguay
|
||||
594;GF;French Guiana
|
||||
593;EC;Ecuador
|
||||
592;GY;Guyana
|
||||
591;BO;Bolivia
|
||||
590;GP;Guadeloupe
|
||||
509;HT;Haiti
|
||||
508;PM;Saint Pierre and Miquelon
|
||||
507;PA;Panama
|
||||
506;CR;Costa Rica
|
||||
505;NI;Nicaragua
|
||||
504;HN;Honduras
|
||||
503;SV;El Salvador
|
||||
502;GT;Guatemala
|
||||
501;BZ;Belize
|
||||
500;FK;Falkland Islands
|
||||
423;LI;Liechtenstein
|
||||
421;SK;Slovakia
|
||||
420;CZ;Czech Republic
|
||||
389;MK;Macedonia
|
||||
387;BA;Bosnia and Herzegovina
|
||||
386;SI;Slovenia
|
||||
385;HR;Croatia
|
||||
382;ME;Montenegro
|
||||
381;RS;Serbia
|
||||
380;UA;Ukraine
|
||||
378;SM;San Marino
|
||||
377;MC;Monaco
|
||||
376;AD;Andorra
|
||||
375;BY;Belarus
|
||||
374;AM;Armenia
|
||||
373;MD;Moldova
|
||||
372;EE;Estonia
|
||||
371;LV;Latvia
|
||||
370;LT;Lithuania
|
||||
359;BG;Bulgaria
|
||||
358;FI;Finland
|
||||
357;CY;Cyprus
|
||||
356;MT;Malta
|
||||
355;AL;Albania
|
||||
354;IS;Iceland
|
||||
353;IE;Ireland
|
||||
352;LU;Luxembourg
|
||||
351;PT;Portugal
|
||||
350;GI;Gibraltar
|
||||
299;GL;Greenland
|
||||
298;FO;Faroe Islands
|
||||
297;AW;Aruba
|
||||
291;ER;Eritrea
|
||||
290;SH;Saint Helena
|
||||
269;KM;Comoros
|
||||
268;SZ;Swaziland
|
||||
267;BW;Botswana
|
||||
266;LS;Lesotho
|
||||
265;MW;Malawi
|
||||
264;NA;Namibia
|
||||
263;ZW;Zimbabwe
|
||||
262;RE;Réunion
|
||||
261;MG;Madagascar
|
||||
260;ZM;Zambia
|
||||
258;MZ;Mozambique
|
||||
257;BI;Burundi
|
||||
256;UG;Uganda
|
||||
255;TZ;Tanzania
|
||||
254;KE;Kenya
|
||||
253;DJ;Djibouti
|
||||
252;SO;Somalia
|
||||
251;ET;Ethiopia
|
||||
250;RW;Rwanda
|
||||
249;SD;Sudan
|
||||
248;SC;Seychelles
|
||||
247;SH;Saint Helena
|
||||
246;IO;United Kingdom
|
||||
245;GW;Guinea-Bissau
|
||||
244;AO;Angola
|
||||
243;CD;Congo, Democratic Republic
|
||||
242;CG;Congo
|
||||
241;GA;Gabon
|
||||
240;GQ;Equatorial Guinea
|
||||
239;ST;São Tomé and Príncipe
|
||||
238;CV;Cape Verde
|
||||
237;CM;Cameroon
|
||||
236;CF;Central African Republic
|
||||
235;TD;Chad
|
||||
234;NG;Nigeria
|
||||
233;GH;Ghana
|
||||
232;SL;Sierra Leone
|
||||
231;LR;Liberia
|
||||
230;MU;Mauritius
|
||||
229;BJ;Benin
|
||||
228;TG;Togo
|
||||
227;NE;Niger
|
||||
226;BF;Burkina Faso
|
||||
225;CI;Côte d`Ivoire
|
||||
224;GN;Guinea
|
||||
223;ML;Mali
|
||||
222;MR;Mauritania
|
||||
221;SN;Senegal
|
||||
220;GM;Gambia
|
||||
218;LY;Libya
|
||||
216;TN;Tunisia
|
||||
213;DZ;Algeria
|
||||
212;MA;Morocco
|
||||
211;SS;South Sudan
|
||||
98;IR;Iran
|
||||
95;MM;Myanmar
|
||||
94;LK;Sri Lanka
|
||||
93;AF;Afghanistan
|
||||
92;PK;Pakistan
|
||||
91;IN;India
|
||||
90;TR;Turkey
|
||||
86;CN;China
|
||||
84;VN;Vietnam
|
||||
82;KR;South Korea
|
||||
81;JP;Japan
|
||||
66;TH;Thailand
|
||||
65;SG;Singapore
|
||||
64;NZ;New Zealand
|
||||
63;PH;Philippines
|
||||
62;ID;Indonesia
|
||||
61;AU;Australia
|
||||
60;MY;Malaysia
|
||||
58;VE;Venezuela
|
||||
57;CO;Colombia
|
||||
56;CL;Chile
|
||||
55;BR;Brazil
|
||||
54;AR;Argentina
|
||||
53;CU;Cuba
|
||||
52;MX;Mexico
|
||||
51;PE;Peru
|
||||
49;DE;Germany
|
||||
48;PL;Poland
|
||||
47;NO;Norway
|
||||
46;SE;Sweden
|
||||
45;DK;Denmark
|
||||
44;GB;United Kingdom
|
||||
43;AT;Austria
|
||||
41;CH;Switzerland
|
||||
40;RO;Romania
|
||||
39;IT;Italy
|
||||
36;HU;Hungary
|
||||
34;ES;Spain
|
||||
33;FR;France
|
||||
32;BE;Belgium
|
||||
31;NL;Netherlands
|
||||
30;GR;Greece
|
||||
27;ZA;South Africa
|
||||
21;DZ;Algeria
|
||||
20;EG;Egypt
|
||||
7;KZ;Kazakhstan
|
||||
7;RU;Russia
|
||||
1;US;USA
|
||||
1;CA;Canada
|
BIN
TMessagesProj/src/main/assets/emojisprite_0.png
Normal file
BIN
TMessagesProj/src/main/assets/emojisprite_0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 722 KiB |
BIN
TMessagesProj/src/main/assets/emojisprite_1.png
Normal file
BIN
TMessagesProj/src/main/assets/emojisprite_1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 531 KiB |
BIN
TMessagesProj/src/main/assets/emojisprite_2.png
Normal file
BIN
TMessagesProj/src/main/assets/emojisprite_2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 944 KiB |
BIN
TMessagesProj/src/main/assets/emojisprite_3.png
Normal file
BIN
TMessagesProj/src/main/assets/emojisprite_3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 402 KiB |
BIN
TMessagesProj/src/main/assets/emojisprite_4.png
Normal file
BIN
TMessagesProj/src/main/assets/emojisprite_4.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 470 KiB |
BIN
TMessagesProj/src/main/assets/fonts/rlight.ttf
Normal file
BIN
TMessagesProj/src/main/assets/fonts/rlight.ttf
Normal file
Binary file not shown.
566
TMessagesProj/src/main/java/jawnae/pyronet/PyroClient.java
Executable file
566
TMessagesProj/src/main/java/jawnae/pyronet/PyroClient.java
Executable file
@ -0,0 +1,566 @@
|
||||
/*
|
||||
* Copyright (c) 2008, https://code.google.com/p/pyronet/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jawnae.pyronet;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.net.ConnectException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.NotYetConnectedException;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import jawnae.pyronet.events.PyroClientListener;
|
||||
import jawnae.pyronet.traffic.ByteStream;
|
||||
|
||||
public class PyroClient {
|
||||
private final PyroSelector selector;
|
||||
|
||||
final PyroServer server;
|
||||
|
||||
private final SelectionKey key;
|
||||
|
||||
private final ByteStream outbound;
|
||||
|
||||
// called by PyroSelector.connect()
|
||||
PyroClient(PyroSelector selector, InetSocketAddress bind,
|
||||
InetSocketAddress host) throws IOException {
|
||||
this(selector, null, PyroClient.bindAndConfigure(selector,
|
||||
SocketChannel.open(), bind));
|
||||
|
||||
((SocketChannel) this.key.channel()).connect(host);
|
||||
}
|
||||
|
||||
// called by PyroClient and PyroServer
|
||||
PyroClient(PyroSelector selector, PyroServer server, SelectionKey key) {
|
||||
this.selector = selector;
|
||||
this.selector.checkThread();
|
||||
|
||||
this.server = server;
|
||||
this.key = key;
|
||||
this.key.attach(this);
|
||||
|
||||
this.outbound = new ByteStream();
|
||||
this.listeners = new CopyOnWriteArrayList<PyroClientListener>();
|
||||
this.lastEventTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
private final List<PyroClientListener> listeners;
|
||||
|
||||
public void addListener(PyroClientListener listener) {
|
||||
this.selector.checkThread();
|
||||
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeListener(PyroClientListener listener) {
|
||||
this.selector.checkThread();
|
||||
|
||||
this.listeners.remove(listener);
|
||||
}
|
||||
|
||||
public void removeListeners() {
|
||||
this.selector.checkThread();
|
||||
|
||||
this.listeners.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the PyroSelector that created this client
|
||||
*/
|
||||
|
||||
public PyroSelector selector() {
|
||||
return this.selector;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
private Object attachment;
|
||||
|
||||
/**
|
||||
* Attach any object to a client, for example to store session information
|
||||
*/
|
||||
|
||||
public void attach(Object attachment) {
|
||||
this.attachment = attachment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the previously attached object, or <code>null</code> if none is
|
||||
* set
|
||||
*/
|
||||
|
||||
public <T> T attachment() {
|
||||
return (T) this.attachment;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
/**
|
||||
* Returns the local socket address (host+port)
|
||||
*/
|
||||
|
||||
public InetSocketAddress getLocalAddress() {
|
||||
Socket s = ((SocketChannel) key.channel()).socket();
|
||||
return (InetSocketAddress) s.getLocalSocketAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the remove socket address (host+port)
|
||||
*/
|
||||
|
||||
public InetSocketAddress getRemoteAddress() {
|
||||
Socket s = ((SocketChannel) key.channel()).socket();
|
||||
return (InetSocketAddress) s.getRemoteSocketAddress();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
public void setTimeout(int ms) throws IOException {
|
||||
this.selector.checkThread();
|
||||
|
||||
((SocketChannel) key.channel()).socket().setSoTimeout(ms);
|
||||
|
||||
// prevent a call to setTimeout from immediately causing a timeout
|
||||
this.lastEventTime = System.currentTimeMillis();
|
||||
this.timeout = ms;
|
||||
}
|
||||
|
||||
public void setLinger(boolean enabled, int seconds) throws IOException {
|
||||
this.selector.checkThread();
|
||||
|
||||
((SocketChannel) key.channel()).socket().setSoLinger(enabled, seconds);
|
||||
}
|
||||
|
||||
public void setKeepAlive(boolean enabled) throws IOException {
|
||||
this.selector.checkThread();
|
||||
|
||||
((SocketChannel) key.channel()).socket().setKeepAlive(enabled);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
/**
|
||||
* Returns the server that accepted this client.
|
||||
*
|
||||
* @throws PyroException
|
||||
* if this client was not accepted by a server (it connected to
|
||||
* a server)
|
||||
*/
|
||||
|
||||
public final PyroServer getServer() throws PyroException {
|
||||
if (this.server == null)
|
||||
throw new PyroException("this client was not accepted by a server");
|
||||
return this.server;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
//
|
||||
|
||||
private boolean doEagerWrite = false;
|
||||
|
||||
/**
|
||||
* If enabled, causes calls to write() to make an attempt to write the
|
||||
* bytes, without waiting for the selector to signal writable state.
|
||||
*/
|
||||
|
||||
public void setEagerWrite(boolean enabled) {
|
||||
this.doEagerWrite = enabled;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
public void writeCopy(ByteBuffer data) throws PyroException {
|
||||
this.write(this.selector.copy(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Will enqueue the bytes to send them<br>
|
||||
* 1. when the selector is ready to write, if eagerWrite is disabled
|
||||
* (default)<br>
|
||||
* 2. immediately, if eagerWrite is enabled<br>
|
||||
* The ByteBuffer instance is kept, not copied, and thus should not be
|
||||
* modified
|
||||
*
|
||||
* @throws PyroException
|
||||
* when shutdown() has been called.
|
||||
*/
|
||||
|
||||
public void write(ByteBuffer data) throws PyroException {
|
||||
this.selector.checkThread();
|
||||
|
||||
if (!this.key.isValid()) {
|
||||
// graceful, as this is meant to be async
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.doShutdown) {
|
||||
throw new PyroException("shutting down");
|
||||
}
|
||||
|
||||
this.outbound.append(data);
|
||||
|
||||
if (this.doEagerWrite) {
|
||||
try {
|
||||
this.onReadyToWrite(System.currentTimeMillis());
|
||||
} catch (NotYetConnectedException exc) {
|
||||
this.adjustWriteOp();
|
||||
} catch (IOException exc) {
|
||||
this.onConnectionError(exc);
|
||||
key.cancel();
|
||||
}
|
||||
} else {
|
||||
this.adjustWriteOp();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes as many as possible bytes to the socket buffer
|
||||
*/
|
||||
|
||||
public int flush() {
|
||||
int total = 0;
|
||||
|
||||
while (this.outbound.hasData()) {
|
||||
int written;
|
||||
|
||||
try {
|
||||
written = this.onReadyToWrite(System.currentTimeMillis());
|
||||
} catch (IOException exc) {
|
||||
written = 0;
|
||||
}
|
||||
|
||||
if (written == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
total += written;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes an attempt to write all outbound bytes, fails on failure.
|
||||
*
|
||||
* @throws PyroException
|
||||
* on failure
|
||||
*/
|
||||
|
||||
public int flushOrDie() throws PyroException {
|
||||
int total = 0;
|
||||
|
||||
while (this.outbound.hasData()) {
|
||||
int written;
|
||||
|
||||
try {
|
||||
written = this.onReadyToWrite(System.currentTimeMillis());
|
||||
} catch (IOException exc) {
|
||||
written = 0;
|
||||
}
|
||||
|
||||
if (written == 0) {
|
||||
throw new PyroException("failed to flush, wrote " + total
|
||||
+ " bytes");
|
||||
}
|
||||
|
||||
total += written;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether there are bytes left in the outbound queue.
|
||||
*/
|
||||
|
||||
public boolean hasDataEnqueued() {
|
||||
this.selector.checkThread();
|
||||
|
||||
return this.outbound.hasData();
|
||||
}
|
||||
|
||||
private boolean doShutdown = false;
|
||||
|
||||
/**
|
||||
* Gracefully shuts down the connection. The connection is closed after the
|
||||
* last outbound bytes are sent. Enqueuing new bytes after shutdown, is not
|
||||
* allowed and will throw an exception
|
||||
*/
|
||||
|
||||
public void shutdown() {
|
||||
this.selector.checkThread();
|
||||
|
||||
this.doShutdown = true;
|
||||
|
||||
if (!this.hasDataEnqueued()) {
|
||||
this.dropConnection();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Immediately drop the connection, regardless of any pending outbound
|
||||
* bytes. Actual behaviour depends on the socket linger settings.
|
||||
*/
|
||||
|
||||
public void dropConnection() {
|
||||
this.selector.checkThread();
|
||||
|
||||
if (this.isDisconnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Runnable drop = new Runnable() {
|
||||
@Override
|
||||
@SuppressWarnings("synthetic-access")
|
||||
public void run() {
|
||||
try {
|
||||
if (key.channel().isOpen()) {
|
||||
((SocketChannel) key.channel()).close();
|
||||
}
|
||||
} catch (Exception exc) {
|
||||
selector().scheduleTask(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
drop.run();
|
||||
|
||||
this.onConnectionError("local");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the connection is connected to a remote client.
|
||||
*/
|
||||
|
||||
public boolean isDisconnected() {
|
||||
this.selector.checkThread();
|
||||
|
||||
return !((SocketChannel) this.key.channel()).isOpen();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void onInterestOp(long now) {
|
||||
if (!key.isValid()) {
|
||||
this.onConnectionError("remote");
|
||||
} else {
|
||||
try {
|
||||
if (key.isConnectable())
|
||||
this.onReadyToConnect(now);
|
||||
if (key.isReadable())
|
||||
this.onReadyToRead(now);
|
||||
if (key.isWritable())
|
||||
this.onReadyToWrite(now);
|
||||
} catch (Exception exc) {
|
||||
this.onConnectionError(exc);
|
||||
key.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private long timeout = 0L;
|
||||
|
||||
private long lastEventTime;
|
||||
|
||||
boolean didTimeout(long now) {
|
||||
if (this.timeout == 0)
|
||||
return false; // never timeout
|
||||
return (now - this.lastEventTime) > this.timeout;
|
||||
}
|
||||
|
||||
private void onReadyToConnect(long now) throws IOException {
|
||||
this.selector.checkThread();
|
||||
this.lastEventTime = now;
|
||||
|
||||
this.selector.adjustInterestOp(key, SelectionKey.OP_CONNECT, false);
|
||||
boolean result = ((SocketChannel) key.channel()).finishConnect();
|
||||
|
||||
for (PyroClientListener listener: this.listeners)
|
||||
listener.connectedClient(this);
|
||||
}
|
||||
|
||||
private void onReadyToRead(long now) throws IOException {
|
||||
this.selector.checkThread();
|
||||
this.lastEventTime = now;
|
||||
|
||||
SocketChannel channel = (SocketChannel) key.channel();
|
||||
|
||||
ByteBuffer buffer = this.selector.networkBuffer;
|
||||
|
||||
// read from channel
|
||||
buffer.clear();
|
||||
int bytes = channel.read(buffer);
|
||||
if (bytes == -1)
|
||||
throw new EOFException();
|
||||
buffer.flip();
|
||||
|
||||
for (PyroClientListener listener: this.listeners)
|
||||
listener.receivedData(this, buffer);
|
||||
}
|
||||
|
||||
private int onReadyToWrite(long now) throws IOException {
|
||||
this.selector.checkThread();
|
||||
this.lastEventTime = now;
|
||||
|
||||
int sent = 0;
|
||||
|
||||
// copy outbound bytes into network buffer
|
||||
ByteBuffer buffer = this.selector.networkBuffer;
|
||||
buffer.clear();
|
||||
this.outbound.get(buffer);
|
||||
buffer.flip();
|
||||
|
||||
// write to channel
|
||||
if (buffer.hasRemaining()) {
|
||||
SocketChannel channel = (SocketChannel) key.channel();
|
||||
sent = channel.write(buffer);
|
||||
}
|
||||
|
||||
if (sent > 0) {
|
||||
this.outbound.discard(sent);
|
||||
}
|
||||
|
||||
for (PyroClientListener listener: this.listeners)
|
||||
listener.sentData(this, sent);
|
||||
|
||||
this.adjustWriteOp();
|
||||
|
||||
if (this.doShutdown && !this.outbound.hasData()) {
|
||||
this.dropConnection();
|
||||
}
|
||||
|
||||
return sent;
|
||||
}
|
||||
|
||||
void onConnectionError(final Object cause) {
|
||||
this.selector.checkThread();
|
||||
|
||||
try {
|
||||
// if the key is invalid, the channel may remain open!!
|
||||
((SocketChannel) this.key.channel()).close();
|
||||
} catch (Exception exc) {
|
||||
// type: java.io.IOException
|
||||
// message:
|
||||
// "A non-blocking socket operation could not be completed immediately"
|
||||
|
||||
// try again later
|
||||
this.selector.scheduleTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
PyroClient.this.onConnectionError(cause);
|
||||
}
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.server != null) {
|
||||
this.server.onDisconnect(this);
|
||||
}
|
||||
|
||||
if (cause instanceof ConnectException) {
|
||||
for (PyroClientListener listener: this.listeners)
|
||||
listener.unconnectableClient(this);
|
||||
} else if (cause instanceof EOFException) // after read=-1
|
||||
{
|
||||
for (PyroClientListener listener: this.listeners)
|
||||
listener.disconnectedClient(this);
|
||||
} else if (cause instanceof IOException) {
|
||||
for (PyroClientListener listener: this.listeners)
|
||||
listener.droppedClient(this, (IOException) cause);
|
||||
} else if (!(cause instanceof String)) {
|
||||
for (PyroClientListener listener: this.listeners)
|
||||
listener.unconnectableClient(this);
|
||||
} else if (cause.equals("local")) {
|
||||
for (PyroClientListener listener: this.listeners)
|
||||
listener.disconnectedClient(this);
|
||||
} else if (cause.equals("remote")) {
|
||||
for (PyroClientListener listener: this.listeners)
|
||||
listener.droppedClient(this, null);
|
||||
} else {
|
||||
throw new IllegalStateException("illegal cause: " + cause);
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return this.getClass().getSimpleName() + "[" + this.getAddressText()
|
||||
+ "]";
|
||||
}
|
||||
|
||||
private final String getAddressText() {
|
||||
if (!this.key.channel().isOpen())
|
||||
return "closed";
|
||||
|
||||
InetSocketAddress sockaddr = this.getRemoteAddress();
|
||||
if (sockaddr == null)
|
||||
return "connecting";
|
||||
InetAddress inetaddr = sockaddr.getAddress();
|
||||
return inetaddr.getHostAddress() + "@" + sockaddr.getPort();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void adjustWriteOp() {
|
||||
this.selector.checkThread();
|
||||
|
||||
boolean interested = this.outbound.hasData();
|
||||
|
||||
this.selector.adjustInterestOp(this.key, SelectionKey.OP_WRITE,
|
||||
interested);
|
||||
}
|
||||
|
||||
static final SelectionKey bindAndConfigure(PyroSelector selector,
|
||||
SocketChannel channel, InetSocketAddress bind) throws IOException {
|
||||
selector.checkThread();
|
||||
|
||||
channel.socket().bind(bind);
|
||||
|
||||
return configure(selector, channel, true);
|
||||
}
|
||||
|
||||
static final SelectionKey configure(PyroSelector selector,
|
||||
SocketChannel channel, boolean connect) throws IOException {
|
||||
selector.checkThread();
|
||||
|
||||
channel.configureBlocking(false);
|
||||
// channel.socket().setSoLinger(false, 0); // this will b0rk your
|
||||
// connections
|
||||
channel.socket().setSoLinger(true, 4);
|
||||
channel.socket().setReuseAddress(true);
|
||||
channel.socket().setKeepAlive(false);
|
||||
channel.socket().setTcpNoDelay(true);
|
||||
channel.socket().setReceiveBufferSize(PyroSelector.BUFFER_SIZE);
|
||||
channel.socket().setSendBufferSize(PyroSelector.BUFFER_SIZE);
|
||||
|
||||
int ops = SelectionKey.OP_READ;
|
||||
if (connect)
|
||||
ops |= SelectionKey.OP_CONNECT;
|
||||
|
||||
return selector.register(channel, ops);
|
||||
}
|
||||
}
|
34
TMessagesProj/src/main/java/jawnae/pyronet/PyroException.java
Executable file
34
TMessagesProj/src/main/java/jawnae/pyronet/PyroException.java
Executable file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2008, https://code.google.com/p/pyronet/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jawnae.pyronet;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class PyroException extends RuntimeException {
|
||||
public PyroException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public PyroException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public PyroException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
}
|
325
TMessagesProj/src/main/java/jawnae/pyronet/PyroSelector.java
Executable file
325
TMessagesProj/src/main/java/jawnae/pyronet/PyroSelector.java
Executable file
@ -0,0 +1,325 @@
|
||||
/*
|
||||
* Copyright (c) 2008, https://code.google.com/p/pyronet/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jawnae.pyronet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.CancelledKeyException;
|
||||
import java.nio.channels.SelectableChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import jawnae.pyronet.events.PyroSelectorListener;
|
||||
|
||||
public class PyroSelector {
|
||||
public static boolean DO_NOT_CHECK_NETWORK_THREAD = true;
|
||||
|
||||
public static final int BUFFER_SIZE = 64 * 1024;
|
||||
|
||||
Thread networkThread;
|
||||
|
||||
final Selector nioSelector;
|
||||
|
||||
final ByteBuffer networkBuffer;
|
||||
|
||||
final PyroSelectorListener listener;
|
||||
|
||||
public PyroSelector() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public PyroSelector(PyroSelectorListener listener) {
|
||||
this.listener = listener;
|
||||
this.networkBuffer = ByteBuffer.allocateDirect(BUFFER_SIZE);
|
||||
|
||||
try {
|
||||
this.nioSelector = Selector.open();
|
||||
} catch (IOException exc) {
|
||||
throw new PyroException("Failed to open a selector?!", exc);
|
||||
}
|
||||
|
||||
this.networkThread = Thread.currentThread();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
public ByteBuffer malloc(int size) {
|
||||
return ByteBuffer.allocate(size);
|
||||
}
|
||||
|
||||
public ByteBuffer malloc(byte[] array) {
|
||||
ByteBuffer copy = this.malloc(array.length);
|
||||
copy.put(array);
|
||||
copy.flip();
|
||||
return copy;
|
||||
}
|
||||
|
||||
public ByteBuffer copy(ByteBuffer buffer) {
|
||||
ByteBuffer copy = this.malloc(buffer.remaining());
|
||||
copy.put(buffer);
|
||||
buffer.position(buffer.position() - copy.remaining());
|
||||
copy.flip();
|
||||
return copy;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
public final boolean isNetworkThread() {
|
||||
if (DO_NOT_CHECK_NETWORK_THREAD) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return networkThread == Thread.currentThread();
|
||||
}
|
||||
|
||||
public final Thread networkThread() {
|
||||
return this.networkThread;
|
||||
}
|
||||
|
||||
public final void checkThread() {
|
||||
if (DO_NOT_CHECK_NETWORK_THREAD) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.isNetworkThread()) {
|
||||
throw new PyroException(
|
||||
"call from outside the network-thread, you must schedule tasks");
|
||||
}
|
||||
}
|
||||
|
||||
public PyroServer listen(InetSocketAddress end, int backlog)
|
||||
throws IOException {
|
||||
try {
|
||||
return new PyroServer(this, nioSelector, end, backlog);
|
||||
} catch (IOException exc) {
|
||||
if (this.listener == null)
|
||||
throw exc;
|
||||
|
||||
this.listener.serverBindFailed(exc);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public PyroServer listen(InetSocketAddress end) throws IOException {
|
||||
return this.listen(end, 50);
|
||||
}
|
||||
|
||||
public PyroServer listen(int port) throws IOException {
|
||||
return this.listen(new InetSocketAddress(InetAddress.getLocalHost(),
|
||||
port));
|
||||
}
|
||||
|
||||
public PyroClient connect(InetSocketAddress host) throws IOException {
|
||||
return this.connect(host, null);
|
||||
}
|
||||
|
||||
public PyroClient connect(InetSocketAddress host, InetSocketAddress bind)
|
||||
throws IOException {
|
||||
try {
|
||||
return new PyroClient(this, bind, host);
|
||||
} catch (IOException exc) {
|
||||
if (this.listener == null)
|
||||
throw exc;
|
||||
|
||||
this.listener.clientBindFailed(exc);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void select() {
|
||||
this.select(10);
|
||||
}
|
||||
|
||||
public void select(long eventTimeout) {
|
||||
this.checkThread();
|
||||
|
||||
//
|
||||
|
||||
this.executePendingTasks();
|
||||
this.performNioSelect(eventTimeout);
|
||||
|
||||
final long now = System.currentTimeMillis();
|
||||
this.handleSelectedKeys(now);
|
||||
this.handleSocketTimeouts(now);
|
||||
}
|
||||
|
||||
private void executePendingTasks() {
|
||||
while (true) {
|
||||
Runnable task = this.tasks.poll();
|
||||
if (task == null)
|
||||
break;
|
||||
|
||||
if (this.listener != null)
|
||||
this.listener.executingTask(task);
|
||||
|
||||
try {
|
||||
task.run();
|
||||
} catch (Throwable cause) {
|
||||
if (this.listener != null)
|
||||
this.listener.taskCrashed(task, cause);
|
||||
else
|
||||
cause.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final void performNioSelect(long timeout) {
|
||||
int selected;
|
||||
try {
|
||||
selected = nioSelector.select(timeout);
|
||||
} catch (IOException exc) {
|
||||
if (this.listener != null)
|
||||
this.listener.selectFailure(exc);
|
||||
else
|
||||
exc.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.listener != null)
|
||||
this.listener.selectedKeys(selected);
|
||||
}
|
||||
|
||||
private final void handleSelectedKeys(long now) {
|
||||
Iterator<SelectionKey> keys = nioSelector.selectedKeys().iterator();
|
||||
|
||||
while (keys.hasNext()) {
|
||||
SelectionKey key = keys.next();
|
||||
keys.remove();
|
||||
|
||||
if (key.channel() instanceof ServerSocketChannel) {
|
||||
PyroServer server = (PyroServer) key.attachment();
|
||||
if (this.listener != null)
|
||||
this.listener.serverSelected(server);
|
||||
server.onInterestOp();
|
||||
}
|
||||
|
||||
if (key.channel() instanceof SocketChannel) {
|
||||
PyroClient client = (PyroClient) key.attachment();
|
||||
if (this.listener != null)
|
||||
this.listener.clientSelected(client, key.readyOps());
|
||||
client.onInterestOp(now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final void handleSocketTimeouts(long now) {
|
||||
for (SelectionKey key: nioSelector.keys()) {
|
||||
if (key.channel() instanceof SocketChannel) {
|
||||
PyroClient client = (PyroClient) key.attachment();
|
||||
|
||||
if (client.didTimeout(now)) {
|
||||
try {
|
||||
throw new SocketTimeoutException(
|
||||
"PyroNet detected NIO timeout");
|
||||
} catch (SocketTimeoutException exc) {
|
||||
client.onConnectionError(exc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void spawnNetworkThread(final String name) {
|
||||
// now no thread can access this selector
|
||||
//
|
||||
// N.B.
|
||||
// -- updating this non-volatile field is thread-safe
|
||||
// -- because the current thread can see it (causing it
|
||||
// -- to become UNACCESSIBLE), and all other threads
|
||||
// -- that might not see the change will
|
||||
// -- (continue to) block access to this selector
|
||||
this.networkThread = null;
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// spawned thread can access this selector
|
||||
//
|
||||
// N.B.
|
||||
// -- updating this non-volatile field is thread-safe
|
||||
// -- because the current thread can see it (causing it
|
||||
// -- to become ACCESSIBLE), and all other threads
|
||||
// -- that might not see the change will
|
||||
// -- (continue to) block access to this selector
|
||||
PyroSelector.this.networkThread = Thread.currentThread();
|
||||
|
||||
// start select-loop
|
||||
try {
|
||||
while (true) {
|
||||
PyroSelector.this.select();
|
||||
}
|
||||
} catch (Exception exc) {
|
||||
// this never be caused by Pyro-code
|
||||
throw new IllegalStateException(exc);
|
||||
}
|
||||
}
|
||||
}, name).start();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
private BlockingQueue<Runnable> tasks = new LinkedBlockingQueue<Runnable>();
|
||||
|
||||
public void scheduleTask(Runnable task) {
|
||||
if (task == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
try {
|
||||
this.tasks.put(task);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
wakeup();
|
||||
}
|
||||
|
||||
public void wakeup() {
|
||||
this.nioSelector.wakeup();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
final SelectionKey register(SelectableChannel channel, int ops)
|
||||
throws IOException {
|
||||
return channel.register(this.nioSelector, ops);
|
||||
}
|
||||
|
||||
final boolean adjustInterestOp(SelectionKey key, int op, boolean state) {
|
||||
this.checkThread();
|
||||
|
||||
try {
|
||||
int ops = key.interestOps();
|
||||
boolean changed = state != ((ops & op) == op);
|
||||
if (changed)
|
||||
key.interestOps(state ? (ops | op) : (ops & ~op));
|
||||
return changed;
|
||||
} catch (CancelledKeyException exc) {
|
||||
// ignore
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
224
TMessagesProj/src/main/java/jawnae/pyronet/PyroServer.java
Executable file
224
TMessagesProj/src/main/java/jawnae/pyronet/PyroServer.java
Executable file
@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (c) 2008, https://code.google.com/p/pyronet/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jawnae.pyronet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import jawnae.pyronet.addon.PyroSelectorProvider;
|
||||
import jawnae.pyronet.events.PyroServerListener;
|
||||
|
||||
public class PyroServer implements Iterable<PyroClient> {
|
||||
private final PyroSelector selector;
|
||||
|
||||
public final SelectionKey serverKey;
|
||||
|
||||
final List<PyroClient> clients;
|
||||
|
||||
PyroServer(PyroSelector selector, Selector nioSelector,
|
||||
InetSocketAddress endpoint, int backlog) throws IOException {
|
||||
this.selector = selector;
|
||||
this.selector.checkThread();
|
||||
|
||||
ServerSocketChannel ssc;
|
||||
ssc = ServerSocketChannel.open();
|
||||
ssc.socket().bind(endpoint, backlog);
|
||||
ssc.configureBlocking(false);
|
||||
|
||||
this.serverKey = ssc.register(nioSelector, SelectionKey.OP_ACCEPT);
|
||||
this.serverKey.attach(this);
|
||||
|
||||
this.clients = new ArrayList<PyroClient>();
|
||||
this.listeners = new CopyOnWriteArrayList<PyroServerListener>();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
private final List<PyroServerListener> listeners;
|
||||
|
||||
public void addListener(PyroServerListener listener) {
|
||||
this.selector.checkThread();
|
||||
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeListener(PyroServerListener listener) {
|
||||
this.selector.checkThread();
|
||||
|
||||
this.listeners.remove(listener);
|
||||
}
|
||||
|
||||
public void removeListeners() {
|
||||
this.selector.checkThread();
|
||||
|
||||
this.listeners.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the network that created this server
|
||||
*/
|
||||
|
||||
public PyroSelector selector() {
|
||||
return this.selector;
|
||||
}
|
||||
|
||||
private PyroSelectorProvider selectorProvider;
|
||||
|
||||
/**
|
||||
* By installing a PyroSelectorProvider you alter the PyroSelector used to
|
||||
* do the I/O of a PyroClient. This can be used for multi-threading your
|
||||
* network code
|
||||
*/
|
||||
|
||||
public void installSelectorProvider(PyroSelectorProvider selectorProvider) {
|
||||
this.selector().checkThread();
|
||||
|
||||
this.selectorProvider = selectorProvider;
|
||||
}
|
||||
|
||||
void onInterestOp() {
|
||||
if (!serverKey.isValid())
|
||||
throw new PyroException("invalid selection key");
|
||||
|
||||
try {
|
||||
if (serverKey.isAcceptable()) {
|
||||
this.onReadyToAccept();
|
||||
}
|
||||
} catch (IOException exc) {
|
||||
throw new IllegalStateException(exc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator to access all connected clients of this server
|
||||
*/
|
||||
|
||||
@Override
|
||||
public Iterator<PyroClient> iterator() {
|
||||
this.selector.checkThread();
|
||||
|
||||
List<PyroClient> copy = new ArrayList<PyroClient>();
|
||||
copy.addAll(this.clients);
|
||||
return copy.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the server socket. Any current connections will continue.
|
||||
*/
|
||||
|
||||
public void close() throws IOException {
|
||||
this.selector.checkThread();
|
||||
|
||||
this.serverKey.channel().close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the server socket. Any current connections will be closed.
|
||||
*/
|
||||
|
||||
public void terminate() throws IOException {
|
||||
this.close();
|
||||
|
||||
for (PyroClient client: this) {
|
||||
client.dropConnection();
|
||||
}
|
||||
}
|
||||
|
||||
private void onReadyToAccept() throws IOException {
|
||||
this.selector.checkThread();
|
||||
|
||||
final SocketChannel channel = ((ServerSocketChannel) serverKey
|
||||
.channel()).accept();
|
||||
|
||||
final PyroSelector acceptedClientSelector;
|
||||
{
|
||||
if (this.selectorProvider == null)
|
||||
acceptedClientSelector = this.selector;
|
||||
else
|
||||
acceptedClientSelector = this.selectorProvider
|
||||
.provideFor(channel);
|
||||
}
|
||||
|
||||
if (acceptedClientSelector == this.selector) {
|
||||
SelectionKey clientKey = PyroClient.configure(
|
||||
acceptedClientSelector, channel, false);
|
||||
PyroClient client = new PyroClient(acceptedClientSelector, this,
|
||||
clientKey);
|
||||
this.fireAcceptedClient(client);
|
||||
this.clients.add(client);
|
||||
} else {
|
||||
// create client in PyroClient-selector thread
|
||||
acceptedClientSelector.scheduleTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
SelectionKey clientKey;
|
||||
try {
|
||||
clientKey = PyroClient.configure(
|
||||
acceptedClientSelector, channel, false);
|
||||
} catch (IOException exc) {
|
||||
throw new IllegalStateException(exc);
|
||||
}
|
||||
final PyroClient client = new PyroClient(
|
||||
acceptedClientSelector, PyroServer.this, clientKey);
|
||||
PyroServer.this.fireAcceptedClient(client);
|
||||
|
||||
// add client to list in PyroServer-selector thread
|
||||
PyroServer.this.selector().scheduleTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
PyroServer.this.clients.add(client);
|
||||
}
|
||||
});
|
||||
PyroServer.this.selector().wakeup();
|
||||
}
|
||||
});
|
||||
acceptedClientSelector.wakeup();
|
||||
}
|
||||
}
|
||||
|
||||
void fireAcceptedClient(PyroClient client) {
|
||||
for (PyroServerListener listener: this.listeners) {
|
||||
listener.acceptedClient(client);
|
||||
}
|
||||
}
|
||||
|
||||
void onDisconnect(final PyroClient client) {
|
||||
if (this.selector().isNetworkThread()) {
|
||||
this.clients.remove(client);
|
||||
} else {
|
||||
// we are in the PyroClient-selector thread
|
||||
this.selector().scheduleTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// call again from the PyroServer-selector thread
|
||||
PyroServer.this.onDisconnect(client);
|
||||
}
|
||||
});
|
||||
this.selector().wakeup();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2008, https://code.google.com/p/pyronet/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jawnae.pyronet.addon;
|
||||
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.Arrays;
|
||||
|
||||
import jawnae.pyronet.PyroSelector;
|
||||
|
||||
public class PyroRoundrobinSelectorProvider implements PyroSelectorProvider {
|
||||
private final PyroSelector[] selectors;
|
||||
|
||||
private int index;
|
||||
|
||||
public PyroRoundrobinSelectorProvider(PyroSelector[] selectors) {
|
||||
this.selectors = Arrays.copyOf(selectors, selectors.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PyroSelector provideFor(SocketChannel channel) {
|
||||
// this is called from the PyroServer-selector thread
|
||||
return this.selectors[this.index++ % this.selectors.length];
|
||||
}
|
||||
}
|
27
TMessagesProj/src/main/java/jawnae/pyronet/addon/PyroSelectorProvider.java
Executable file
27
TMessagesProj/src/main/java/jawnae/pyronet/addon/PyroSelectorProvider.java
Executable file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2008, https://code.google.com/p/pyronet/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jawnae.pyronet.addon;
|
||||
|
||||
import java.nio.channels.SocketChannel;
|
||||
|
||||
import jawnae.pyronet.PyroSelector;
|
||||
|
||||
public interface PyroSelectorProvider {
|
||||
public PyroSelector provideFor(SocketChannel channel);
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2008, https://code.google.com/p/pyronet/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jawnae.pyronet.addon;
|
||||
|
||||
import java.nio.channels.SocketChannel;
|
||||
|
||||
import jawnae.pyronet.PyroSelector;
|
||||
|
||||
public class PyroSingletonSelectorProvider implements PyroSelectorProvider {
|
||||
private final PyroSelector selector;
|
||||
|
||||
public PyroSingletonSelectorProvider(PyroSelector selector) {
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PyroSelector provideFor(SocketChannel channel) {
|
||||
return this.selector;
|
||||
}
|
||||
}
|
55
TMessagesProj/src/main/java/jawnae/pyronet/events/PyroClientAdapter.java
Executable file
55
TMessagesProj/src/main/java/jawnae/pyronet/events/PyroClientAdapter.java
Executable file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2008, https://code.google.com/p/pyronet/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jawnae.pyronet.events;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import jawnae.pyronet.PyroClient;
|
||||
|
||||
public class PyroClientAdapter implements PyroClientListener {
|
||||
public void connectedClient(PyroClient client) {
|
||||
//
|
||||
}
|
||||
|
||||
public void unconnectableClient(PyroClient client) {
|
||||
System.out.println("unconnectable");
|
||||
}
|
||||
|
||||
public void droppedClient(PyroClient client, IOException cause) {
|
||||
if (cause != null) {
|
||||
System.out.println(this.getClass().getSimpleName()
|
||||
+ ".droppedClient() caught exception: " + cause);
|
||||
}
|
||||
}
|
||||
|
||||
public void disconnectedClient(PyroClient client) {
|
||||
//
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
public void receivedData(PyroClient client, ByteBuffer data) {
|
||||
//
|
||||
}
|
||||
|
||||
public void sentData(PyroClient client, int bytes) {
|
||||
//
|
||||
}
|
||||
}
|
40
TMessagesProj/src/main/java/jawnae/pyronet/events/PyroClientListener.java
Executable file
40
TMessagesProj/src/main/java/jawnae/pyronet/events/PyroClientListener.java
Executable file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2008, https://code.google.com/p/pyronet/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jawnae.pyronet.events;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import jawnae.pyronet.PyroClient;
|
||||
|
||||
public interface PyroClientListener {
|
||||
public void connectedClient(PyroClient client);
|
||||
|
||||
public void unconnectableClient(PyroClient client);
|
||||
|
||||
public void droppedClient(PyroClient client, IOException cause);
|
||||
|
||||
public void disconnectedClient(PyroClient client);
|
||||
|
||||
//
|
||||
|
||||
public void receivedData(PyroClient client, ByteBuffer data);
|
||||
|
||||
public void sentData(PyroClient client, int bytes);
|
||||
}
|
111
TMessagesProj/src/main/java/jawnae/pyronet/events/PyroLazyBastardAdapter.java
Executable file
111
TMessagesProj/src/main/java/jawnae/pyronet/events/PyroLazyBastardAdapter.java
Executable file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2008, https://code.google.com/p/pyronet/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jawnae.pyronet.events;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import jawnae.pyronet.PyroClient;
|
||||
import jawnae.pyronet.PyroServer;
|
||||
|
||||
public class PyroLazyBastardAdapter implements PyroSelectorListener,
|
||||
PyroServerListener, PyroClientListener {
|
||||
// --------------- PyroSelectorListener
|
||||
|
||||
public void executingTask(Runnable task) {
|
||||
//
|
||||
}
|
||||
|
||||
public void taskCrashed(Runnable task, Throwable cause) {
|
||||
System.out.println(this.getClass().getSimpleName()
|
||||
+ ".taskCrashed() caught exception:");
|
||||
cause.printStackTrace();
|
||||
}
|
||||
|
||||
public void selectedKeys(int count) {
|
||||
//
|
||||
}
|
||||
|
||||
public void selectFailure(IOException cause) {
|
||||
System.out.println(this.getClass().getSimpleName()
|
||||
+ ".selectFailure() caught exception:");
|
||||
cause.printStackTrace();
|
||||
}
|
||||
|
||||
public void serverSelected(PyroServer server) {
|
||||
//
|
||||
}
|
||||
|
||||
public void clientSelected(PyroClient client, int readyOps) {
|
||||
//
|
||||
}
|
||||
|
||||
// ------------- PyroServerListener
|
||||
|
||||
public void acceptedClient(PyroClient client) {
|
||||
//
|
||||
}
|
||||
|
||||
// ------------- PyroClientListener
|
||||
|
||||
public void connectedClient(PyroClient client) {
|
||||
//
|
||||
}
|
||||
|
||||
public void unconnectableClient(PyroClient client) {
|
||||
System.out.println(this.getClass().getSimpleName()
|
||||
+ ".unconnectableClient()");
|
||||
}
|
||||
|
||||
public void droppedClient(PyroClient client, IOException cause) {
|
||||
if (cause != null && !(cause instanceof EOFException)) {
|
||||
System.out.println(this.getClass().getSimpleName()
|
||||
+ ".droppedClient() caught exception: " + cause);
|
||||
}
|
||||
}
|
||||
|
||||
public void disconnectedClient(PyroClient client) {
|
||||
//
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
public void receivedData(PyroClient client, ByteBuffer data) {
|
||||
//
|
||||
}
|
||||
|
||||
public void sentData(PyroClient client, int bytes) {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serverBindFailed(IOException cause) {
|
||||
System.out.println(this.getClass().getSimpleName()
|
||||
+ ".serverBindFailed() caught exception:");
|
||||
cause.printStackTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clientBindFailed(IOException cause) {
|
||||
System.out.println(this.getClass().getSimpleName()
|
||||
+ ".serverBindFailed() caught exception:");
|
||||
cause.printStackTrace();
|
||||
}
|
||||
}
|
70
TMessagesProj/src/main/java/jawnae/pyronet/events/PyroSelectorAdapter.java
Executable file
70
TMessagesProj/src/main/java/jawnae/pyronet/events/PyroSelectorAdapter.java
Executable file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2008, https://code.google.com/p/pyronet/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jawnae.pyronet.events;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import jawnae.pyronet.PyroClient;
|
||||
import jawnae.pyronet.PyroServer;
|
||||
|
||||
public class PyroSelectorAdapter implements PyroSelectorListener {
|
||||
public void executingTask(Runnable task) {
|
||||
//
|
||||
}
|
||||
|
||||
public void taskCrashed(Runnable task, Throwable cause) {
|
||||
System.out.println(this.getClass().getSimpleName()
|
||||
+ " caught exception: " + cause);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
public void selectedKeys(int count) {
|
||||
//
|
||||
}
|
||||
|
||||
public void selectFailure(IOException cause) {
|
||||
System.out.println(this.getClass().getSimpleName()
|
||||
+ " caught exception: " + cause);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
public void serverSelected(PyroServer server) {
|
||||
//
|
||||
}
|
||||
|
||||
public void clientSelected(PyroClient client, int readyOps) {
|
||||
//
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@Override
|
||||
public void serverBindFailed(IOException cause) {
|
||||
System.out.println(this.getClass().getSimpleName()
|
||||
+ ".serverBindFailed() caught exception: " + cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clientBindFailed(IOException cause) {
|
||||
System.out.println(this.getClass().getSimpleName()
|
||||
+ ".serverBindFailed() caught exception: " + cause);
|
||||
}
|
||||
}
|
48
TMessagesProj/src/main/java/jawnae/pyronet/events/PyroSelectorListener.java
Executable file
48
TMessagesProj/src/main/java/jawnae/pyronet/events/PyroSelectorListener.java
Executable file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2008, https://code.google.com/p/pyronet/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jawnae.pyronet.events;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import jawnae.pyronet.PyroClient;
|
||||
import jawnae.pyronet.PyroServer;
|
||||
|
||||
public interface PyroSelectorListener {
|
||||
public void executingTask(Runnable task);
|
||||
|
||||
public void taskCrashed(Runnable task, Throwable cause);
|
||||
|
||||
//
|
||||
|
||||
public void selectedKeys(int count);
|
||||
|
||||
public void selectFailure(IOException cause);
|
||||
|
||||
//
|
||||
|
||||
public void serverSelected(PyroServer server);
|
||||
|
||||
public void clientSelected(PyroClient client, int readyOps);
|
||||
|
||||
//
|
||||
|
||||
public void serverBindFailed(IOException cause);
|
||||
|
||||
public void clientBindFailed(IOException cause);
|
||||
}
|
28
TMessagesProj/src/main/java/jawnae/pyronet/events/PyroServerAdapter.java
Executable file
28
TMessagesProj/src/main/java/jawnae/pyronet/events/PyroServerAdapter.java
Executable file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2008, https://code.google.com/p/pyronet/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jawnae.pyronet.events;
|
||||
|
||||
import jawnae.pyronet.PyroClient;
|
||||
|
||||
public class PyroServerAdapter implements PyroServerListener {
|
||||
@Override
|
||||
public void acceptedClient(PyroClient client) {
|
||||
//
|
||||
}
|
||||
}
|
28
TMessagesProj/src/main/java/jawnae/pyronet/events/PyroServerListener.java
Executable file
28
TMessagesProj/src/main/java/jawnae/pyronet/events/PyroServerListener.java
Executable file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2008, https://code.google.com/p/pyronet/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jawnae.pyronet.events;
|
||||
|
||||
import jawnae.pyronet.PyroClient;
|
||||
|
||||
public interface PyroServerListener {
|
||||
/**
|
||||
* Note: invoked from the PyroSelector-thread that created this PyroClient
|
||||
*/
|
||||
public void acceptedClient(PyroClient client);
|
||||
}
|
48
TMessagesProj/src/main/java/jawnae/pyronet/traffic/ByteSink.java
Executable file
48
TMessagesProj/src/main/java/jawnae/pyronet/traffic/ByteSink.java
Executable file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2008, https://code.google.com/p/pyronet/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jawnae.pyronet.traffic;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public interface ByteSink {
|
||||
public static int FEED_ACCEPTED = 1;
|
||||
|
||||
public static int FEED_ACCEPTED_LAST = 2;
|
||||
|
||||
public static int FEED_REJECTED = 3;
|
||||
|
||||
/**
|
||||
* determines what to do with the specified byte: accept, accept as final
|
||||
* byte, reject
|
||||
*/
|
||||
|
||||
public int feed(byte b);
|
||||
|
||||
/**
|
||||
* Resets the state of this ByteSink, allowing it to be enqueued again
|
||||
*/
|
||||
|
||||
public void reset();
|
||||
|
||||
/**
|
||||
* Called by the client when this ByteSink is complete
|
||||
*/
|
||||
|
||||
public void onReady(ByteBuffer buffer);
|
||||
}
|
74
TMessagesProj/src/main/java/jawnae/pyronet/traffic/ByteSinkEndsWith.java
Executable file
74
TMessagesProj/src/main/java/jawnae/pyronet/traffic/ByteSinkEndsWith.java
Executable file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2008, https://code.google.com/p/pyronet/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jawnae.pyronet.traffic;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public abstract class ByteSinkEndsWith implements ByteSink {
|
||||
private final ByteBuffer result;
|
||||
|
||||
private final byte[] endsWith;
|
||||
|
||||
private final boolean includeEndsWith;
|
||||
|
||||
private int matchCount;
|
||||
|
||||
private int filled;
|
||||
|
||||
public ByteSinkEndsWith(byte[] endsWith, int capacity,
|
||||
boolean includeEndsWith) {
|
||||
if (endsWith == null || endsWith.length == 0)
|
||||
throw new IllegalStateException();
|
||||
this.result = ByteBuffer.allocate(capacity);
|
||||
this.endsWith = endsWith;
|
||||
this.includeEndsWith = includeEndsWith;
|
||||
|
||||
this.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.result.clear();
|
||||
this.matchCount = 0;
|
||||
this.filled = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int feed(byte b) {
|
||||
if (this.endsWith[this.matchCount] == b) {
|
||||
this.matchCount++;
|
||||
} else {
|
||||
this.matchCount = 0;
|
||||
}
|
||||
|
||||
this.result.put(this.filled, b);
|
||||
|
||||
this.filled += 1;
|
||||
|
||||
if (this.matchCount == this.endsWith.length) {
|
||||
int len = this.filled
|
||||
- (this.includeEndsWith ? 0 : this.endsWith.length);
|
||||
this.result.limit(len);
|
||||
this.onReady(this.result);
|
||||
return FEED_ACCEPTED_LAST;
|
||||
}
|
||||
|
||||
return ByteSink.FEED_ACCEPTED;
|
||||
}
|
||||
}
|
55
TMessagesProj/src/main/java/jawnae/pyronet/traffic/ByteSinkLength.java
Executable file
55
TMessagesProj/src/main/java/jawnae/pyronet/traffic/ByteSinkLength.java
Executable file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2008, https://code.google.com/p/pyronet/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jawnae.pyronet.traffic;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public abstract class ByteSinkLength implements ByteSink {
|
||||
private final ByteBuffer result;
|
||||
|
||||
private int filled;
|
||||
|
||||
public ByteSinkLength(int size) {
|
||||
if (size == 0)
|
||||
throw new IllegalArgumentException();
|
||||
this.result = ByteBuffer.allocate(size);
|
||||
|
||||
this.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.result.clear();
|
||||
this.filled = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int feed(byte b) {
|
||||
this.result.put(this.filled, b);
|
||||
|
||||
this.filled += 1;
|
||||
|
||||
if (this.filled == this.result.capacity()) {
|
||||
this.onReady(this.result);
|
||||
return FEED_ACCEPTED_LAST;
|
||||
}
|
||||
|
||||
return ByteSink.FEED_ACCEPTED;
|
||||
}
|
||||
}
|
95
TMessagesProj/src/main/java/jawnae/pyronet/traffic/ByteSinkPacket16.java
Executable file
95
TMessagesProj/src/main/java/jawnae/pyronet/traffic/ByteSinkPacket16.java
Executable file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2008, https://code.google.com/p/pyronet/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jawnae.pyronet.traffic;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import jawnae.pyronet.PyroClient;
|
||||
|
||||
public abstract class ByteSinkPacket16 implements ByteSink {
|
||||
public static void sendTo(PyroClient client, byte[] payload) {
|
||||
if (payload.length > 0x0000FFFF) {
|
||||
throw new IllegalStateException("packet bigger than 64K-1 bytes");
|
||||
}
|
||||
|
||||
byte[] wrapped = new byte[2 + payload.length];
|
||||
wrapped[0] = (byte) (payload.length >> 8);
|
||||
wrapped[1] = (byte) (payload.length >> 0);
|
||||
System.arraycopy(payload, 0, wrapped, 2, payload.length);
|
||||
|
||||
client.write(client.selector().malloc(wrapped));
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
ByteSinkLength current;
|
||||
|
||||
public ByteSinkPacket16() {
|
||||
this.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.current = new ByteSinkLength(2) {
|
||||
@Override
|
||||
public void onReady(ByteBuffer buffer) {
|
||||
// header is received
|
||||
int len = buffer.getShort(0) & 0xFFFF;
|
||||
|
||||
current = new ByteSinkLength(len) {
|
||||
@Override
|
||||
public void onReady(ByteBuffer buffer) {
|
||||
// sometime we want do reset in
|
||||
// ByteSinkPacket16.this.onReady, then add the sink back
|
||||
// to feeder, in such process, onReady should be execute
|
||||
// at last.
|
||||
current = null;
|
||||
|
||||
// content is received
|
||||
ByteSinkPacket16.this.onReady(buffer);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int feed(byte b) {
|
||||
if (this.current == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
int result = this.current.feed(b);
|
||||
|
||||
if (result == FEED_ACCEPTED) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// 'current' will be replaced by now
|
||||
|
||||
if (this.current == null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
else {
|
||||
return FEED_ACCEPTED;
|
||||
}
|
||||
// return this.current.feed(b);
|
||||
}
|
||||
}
|
94
TMessagesProj/src/main/java/jawnae/pyronet/traffic/ByteSinkPacket24.java
Executable file
94
TMessagesProj/src/main/java/jawnae/pyronet/traffic/ByteSinkPacket24.java
Executable file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2008, https://code.google.com/p/pyronet/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jawnae.pyronet.traffic;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import jawnae.pyronet.PyroClient;
|
||||
|
||||
public abstract class ByteSinkPacket24 implements ByteSink {
|
||||
public static void sendTo(PyroClient client, byte[] payload) {
|
||||
if (payload.length > 0x00FFFFFF) {
|
||||
throw new IllegalStateException("packet bigger than 16M-1 bytes");
|
||||
}
|
||||
|
||||
byte[] wrapped = new byte[3 + payload.length];
|
||||
wrapped[0] = (byte) (payload.length >> 16);
|
||||
wrapped[1] = (byte) (payload.length >> 8);
|
||||
wrapped[2] = (byte) (payload.length >> 0);
|
||||
System.arraycopy(payload, 0, wrapped, 3, payload.length);
|
||||
|
||||
client.write(client.selector().malloc(wrapped));
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
ByteSinkLength current;
|
||||
|
||||
public ByteSinkPacket24() {
|
||||
this.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.current = new ByteSinkLength(3) {
|
||||
@Override
|
||||
public void onReady(ByteBuffer buffer) {
|
||||
// header is received
|
||||
int len = ((buffer.getShort(0) & 0xFFFF) << 8)
|
||||
| (buffer.get(3) & 0xFF);
|
||||
|
||||
current = new ByteSinkLength(len) {
|
||||
@Override
|
||||
public void onReady(ByteBuffer buffer) {
|
||||
// sometime we want do reset in
|
||||
// ByteSinkPacket24.this.onReady, then add the sink back
|
||||
// to feeder, in such process, onReady should be execute
|
||||
// at last.
|
||||
current = null;
|
||||
// content is received
|
||||
ByteSinkPacket24.this.onReady(buffer);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int feed(byte b) {
|
||||
if (this.current == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
int result = this.current.feed(b);
|
||||
|
||||
if (result == FEED_ACCEPTED) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// 'current' will be replaced by now
|
||||
|
||||
if (this.current == null) {
|
||||
return result;
|
||||
} else {
|
||||
return FEED_ACCEPTED;
|
||||
}
|
||||
// return this.current.feed(b);
|
||||
}
|
||||
}
|
102
TMessagesProj/src/main/java/jawnae/pyronet/traffic/ByteSinkPacket32.java
Executable file
102
TMessagesProj/src/main/java/jawnae/pyronet/traffic/ByteSinkPacket32.java
Executable file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2008, https://code.google.com/p/pyronet/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jawnae.pyronet.traffic;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import jawnae.pyronet.PyroClient;
|
||||
|
||||
public abstract class ByteSinkPacket32 implements ByteSink {
|
||||
public static void sendTo(PyroClient client, byte[] payload) {
|
||||
boolean isExtreme = (payload.length > 0xFFFFFFFF - 4);
|
||||
|
||||
byte[] wrapped = new byte[4 + (isExtreme ? 0 : payload.length)];
|
||||
wrapped[0] = (byte) (payload.length >> 24);
|
||||
wrapped[1] = (byte) (payload.length >> 16);
|
||||
wrapped[2] = (byte) (payload.length >> 8);
|
||||
wrapped[3] = (byte) (payload.length >> 0);
|
||||
|
||||
if (!isExtreme) {
|
||||
System.arraycopy(payload, 0, wrapped, 4, payload.length);
|
||||
}
|
||||
|
||||
client.write(client.selector().malloc(wrapped));
|
||||
|
||||
if (isExtreme) {
|
||||
client.write(client.selector().malloc(payload));
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
ByteSinkLength current;
|
||||
|
||||
public ByteSinkPacket32() {
|
||||
this.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.current = new ByteSinkLength(4) {
|
||||
@Override
|
||||
public void onReady(ByteBuffer buffer) {
|
||||
// header is received
|
||||
int len = buffer.getInt(0);
|
||||
|
||||
current = new ByteSinkLength(len) {
|
||||
@Override
|
||||
public void onReady(ByteBuffer buffer) {
|
||||
// sometime we want do reset in
|
||||
// ByteSinkPacket24.this.onReady, then add the sink back
|
||||
// to feeder, in such process, onReady should be execute
|
||||
// at last.
|
||||
current = null;
|
||||
|
||||
// content is received
|
||||
ByteSinkPacket32.this.onReady(buffer);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int feed(byte b) {
|
||||
if (this.current == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
int result = this.current.feed(b);
|
||||
|
||||
if (result == FEED_ACCEPTED) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// 'current' will be replaced by now
|
||||
|
||||
if (this.current == null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
else {
|
||||
return FEED_ACCEPTED;
|
||||
}
|
||||
// return this.current.feed(b);
|
||||
}
|
||||
}
|
141
TMessagesProj/src/main/java/jawnae/pyronet/traffic/ByteStream.java
Executable file
141
TMessagesProj/src/main/java/jawnae/pyronet/traffic/ByteStream.java
Executable file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) 2008, https://code.google.com/p/pyronet/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jawnae.pyronet.traffic;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import jawnae.pyronet.PyroException;
|
||||
|
||||
public class ByteStream {
|
||||
private final List<ByteBuffer> queue;
|
||||
|
||||
public ByteStream() {
|
||||
// the queue is expected to be relatively small, and iterated often.
|
||||
// hence removing the first element will be fast, even when using an
|
||||
// ArrayList
|
||||
this.queue = new ArrayList<ByteBuffer>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the ByteBuffer instance to the ByteStream. The bytes are not
|
||||
* copied, so do not modify the contents of the ByteBuffer.
|
||||
*/
|
||||
|
||||
public void append(ByteBuffer buf) {
|
||||
if (buf == null)
|
||||
throw new NullPointerException();
|
||||
this.queue.add(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether there are any bytes pending in this stream
|
||||
*/
|
||||
|
||||
public boolean hasData() {
|
||||
int size = this.queue.size();
|
||||
for (int i = 0; i < size; i++)
|
||||
if (this.queue.get(i).hasRemaining())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getByteCount() {
|
||||
int size = this.queue.size();
|
||||
|
||||
int sum = 0;
|
||||
for (int i = 0; i < size; i++)
|
||||
sum += this.queue.get(i).remaining();
|
||||
return sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the specified buffer with as much bytes as possible. When N bytes
|
||||
* are read, the buffer position will be increased by N
|
||||
*/
|
||||
|
||||
public void get(ByteBuffer dst) {
|
||||
if (dst == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
for (ByteBuffer data: this.queue) {
|
||||
// data pos/lim must not be modified
|
||||
data = data.slice();
|
||||
|
||||
if (data.remaining() > dst.remaining()) {
|
||||
data.limit(dst.remaining());
|
||||
dst.put(data);
|
||||
break;
|
||||
}
|
||||
|
||||
dst.put(data);
|
||||
|
||||
if (!dst.hasRemaining()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Discards the specified amount of bytes from the stream.
|
||||
*
|
||||
* @throws PyroException
|
||||
* if it failed to discard the specified number of bytes
|
||||
*/
|
||||
|
||||
public void discard(int count) {
|
||||
int original = count;
|
||||
|
||||
while (count > 0) {
|
||||
// peek at the first buffer
|
||||
ByteBuffer data = this.queue.get(0);
|
||||
|
||||
if (count < data.remaining()) {
|
||||
// discarding less bytes than remaining in buffer
|
||||
data.position(data.position() + count);
|
||||
count = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// discard the first buffer
|
||||
this.queue.remove(0);
|
||||
count -= data.remaining();
|
||||
}
|
||||
|
||||
if (count != 0) {
|
||||
// apparantly we cannot discard the amount of bytes
|
||||
// the user demanded, this is a bug in other code
|
||||
throw new PyroException("discarded " + (original - count) + "/"
|
||||
+ original + " bytes");
|
||||
}
|
||||
}
|
||||
|
||||
public byte read() {
|
||||
ByteBuffer data = this.queue.get(0);
|
||||
byte result = data.get();
|
||||
if (!data.hasRemaining()) {
|
||||
// discard the first buffer
|
||||
this.queue.remove(0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
119
TMessagesProj/src/main/java/jawnae/pyronet/traffic/PyroByteSinkFeeder.java
Executable file
119
TMessagesProj/src/main/java/jawnae/pyronet/traffic/PyroByteSinkFeeder.java
Executable file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (c) 2008, https://code.google.com/p/pyronet/
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jawnae.pyronet.traffic;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import jawnae.pyronet.PyroClient;
|
||||
import jawnae.pyronet.PyroSelector;
|
||||
import jawnae.pyronet.events.PyroClientAdapter;
|
||||
|
||||
public class PyroByteSinkFeeder extends PyroClientAdapter {
|
||||
private final PyroSelector selector;
|
||||
|
||||
private final ByteStream inbound;
|
||||
|
||||
private final LinkedList<ByteSink> sinks;
|
||||
|
||||
public PyroByteSinkFeeder(PyroClient client) {
|
||||
this(client.selector());
|
||||
}
|
||||
|
||||
public PyroByteSinkFeeder(PyroSelector selector) {
|
||||
this(selector, 8 * 1024);
|
||||
}
|
||||
|
||||
public PyroByteSinkFeeder(PyroSelector selector, int bufferSize) {
|
||||
this.selector = selector;
|
||||
this.inbound = new ByteStream();
|
||||
this.sinks = new LinkedList<ByteSink>();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@Override
|
||||
public void receivedData(PyroClient client, ByteBuffer data) {
|
||||
this.feed(data);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
public ByteBuffer shutdown() {
|
||||
int bytes = this.inbound.getByteCount();
|
||||
ByteBuffer tmp = this.selector.malloc(bytes);
|
||||
this.inbound.get(tmp);
|
||||
this.inbound.discard(bytes);
|
||||
tmp.flip();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
public void addByteSink(ByteSink sink) {
|
||||
this.selector.checkThread();
|
||||
|
||||
this.register(sink);
|
||||
}
|
||||
|
||||
public void feed(ByteBuffer data) {
|
||||
ByteBuffer copy = this.selector.copy(data);
|
||||
|
||||
this.inbound.append(copy);
|
||||
|
||||
this.fill();
|
||||
}
|
||||
|
||||
final void register(ByteSink sink) {
|
||||
this.sinks.addLast(sink);
|
||||
|
||||
this.fill();
|
||||
}
|
||||
|
||||
private final void fill() {
|
||||
if (this.sinks.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ByteSink currentSink = this.sinks.removeFirst();
|
||||
|
||||
while (currentSink != null && inbound.hasData()) {
|
||||
switch (currentSink.feed(inbound.read())) {
|
||||
case ByteSink.FEED_ACCEPTED:
|
||||
continue; // continue to next feed
|
||||
|
||||
case ByteSink.FEED_ACCEPTED_LAST:
|
||||
break; // break out switch, not while
|
||||
|
||||
case ByteSink.FEED_REJECTED:
|
||||
break; // break out switch, not while
|
||||
}
|
||||
|
||||
if (this.sinks.isEmpty()) {
|
||||
currentSink = null;
|
||||
break;
|
||||
}
|
||||
|
||||
currentSink = this.sinks.removeFirst();
|
||||
}
|
||||
|
||||
if (currentSink != null) {
|
||||
this.sinks.addFirst(currentSink);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
// Copyright (c) 2012, Rick Maddy
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package org.telegram.PhoneFormat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class CallingCodeInfo {
|
||||
public ArrayList<String> countries;
|
||||
public String callingCode;
|
||||
public ArrayList<String> trunkPrefixes;
|
||||
public ArrayList<String> intlPrefixes;
|
||||
public ArrayList<RuleSet> ruleSets;
|
||||
//public ArrayList formatStrings;
|
||||
|
||||
String matchingAccessCode(String str) {
|
||||
for (String code : intlPrefixes) {
|
||||
if (str.startsWith(code)) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String matchingTrunkCode(String str) {
|
||||
for (String code : trunkPrefixes) {
|
||||
if (str.startsWith(code)) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
String format(String orig) {
|
||||
String str = orig;
|
||||
String trunkPrefix = null;
|
||||
String intlPrefix = null;
|
||||
if (str.startsWith(callingCode)) {
|
||||
intlPrefix = callingCode;
|
||||
str = str.substring(intlPrefix.length());
|
||||
} else {
|
||||
String trunk = matchingTrunkCode(str);
|
||||
if (trunk != null) {
|
||||
trunkPrefix = trunk;
|
||||
str = str.substring(trunkPrefix.length());
|
||||
}
|
||||
}
|
||||
|
||||
for (RuleSet set : ruleSets) {
|
||||
String phone = set.format(str, intlPrefix, trunkPrefix, true);
|
||||
if (phone != null) {
|
||||
return phone;
|
||||
}
|
||||
}
|
||||
|
||||
for (RuleSet set : ruleSets) {
|
||||
String phone = set.format(str, intlPrefix, trunkPrefix, false);
|
||||
if (phone != null) {
|
||||
return phone;
|
||||
}
|
||||
}
|
||||
|
||||
if (intlPrefix != null && str.length() != 0) {
|
||||
return String.format("%s %s", intlPrefix, str);
|
||||
}
|
||||
|
||||
return orig;
|
||||
}
|
||||
|
||||
boolean isValidPhoneNumber(String orig) {
|
||||
String str = orig;
|
||||
String trunkPrefix = null;
|
||||
String intlPrefix = null;
|
||||
if (str.startsWith(callingCode)) {
|
||||
intlPrefix = callingCode;
|
||||
str = str.substring(intlPrefix.length());
|
||||
} else {
|
||||
String trunk = matchingTrunkCode(str);
|
||||
if (trunk != null) {
|
||||
trunkPrefix = trunk;
|
||||
str = str.substring(trunkPrefix.length());
|
||||
}
|
||||
}
|
||||
|
||||
for (RuleSet set : ruleSets) {
|
||||
boolean valid = set.isValid(str, intlPrefix, trunkPrefix, true);
|
||||
if (valid) {
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
|
||||
for (RuleSet set : ruleSets) {
|
||||
boolean valid = set.isValid(str, intlPrefix, trunkPrefix, false);
|
||||
if (valid) {
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,365 @@
|
||||
// Copyright (c) 2012, Rick Maddy
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package org.telegram.PhoneFormat;
|
||||
|
||||
import org.telegram.messenger.Utilities;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
|
||||
public class PhoneFormat {
|
||||
public byte[] data;
|
||||
public ByteBuffer buffer;
|
||||
public String defaultCountry;
|
||||
public String defaultCallingCode;
|
||||
public HashMap<String, Integer> callingCodeOffsets;
|
||||
public HashMap<String, ArrayList<String>> callingCodeCountries;
|
||||
public HashMap<String, CallingCodeInfo> callingCodeData;
|
||||
public HashMap<String, String> countryCallingCode;
|
||||
|
||||
public static PhoneFormat Instance = new PhoneFormat();
|
||||
|
||||
public static String strip(String str) {
|
||||
StringBuilder res = new StringBuilder(str);
|
||||
String phoneChars = "0123456789+*#";
|
||||
for (int i = res.length() - 1; i >= 0; i--) {
|
||||
if (!phoneChars.contains(res.substring(i, i + 1))) {
|
||||
res.deleteCharAt(i);
|
||||
}
|
||||
}
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
public static String stripExceptNumbers(String str) {
|
||||
StringBuilder res = new StringBuilder(str);
|
||||
String phoneChars = "0123456789";
|
||||
for (int i = res.length() - 1; i >= 0; i--) {
|
||||
if (!phoneChars.contains(res.substring(i, i + 1))) {
|
||||
res.deleteCharAt(i);
|
||||
}
|
||||
}
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
public PhoneFormat() {
|
||||
init(null);
|
||||
}
|
||||
|
||||
public PhoneFormat(String countryCode) {
|
||||
init(countryCode);
|
||||
}
|
||||
|
||||
public void init(String countryCode) {
|
||||
try {
|
||||
InputStream stream = Utilities.applicationContext.getAssets().open("PhoneFormats.dat");
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
byte[] buf = new byte[1024];
|
||||
int len;
|
||||
while ((len = stream.read(buf, 0, 1024)) != -1) {
|
||||
bos.write(buf, 0, len);
|
||||
}
|
||||
data = bos.toByteArray();
|
||||
buffer = ByteBuffer.wrap(data);
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (countryCode != null && countryCode.length() != 0) {
|
||||
defaultCountry = countryCode;
|
||||
} else {
|
||||
Locale loc = Locale.getDefault();
|
||||
defaultCountry = loc.getCountry().toLowerCase();
|
||||
}
|
||||
callingCodeOffsets = new HashMap<String, Integer>(255);
|
||||
callingCodeCountries = new HashMap<String, ArrayList<String>>(255);
|
||||
callingCodeData = new HashMap<String, CallingCodeInfo>(10);
|
||||
countryCallingCode = new HashMap<String, String>(255);
|
||||
|
||||
parseDataHeader();
|
||||
}
|
||||
|
||||
public String defaultCallingCode() {
|
||||
return callingCodeForCountryCode(defaultCountry);
|
||||
}
|
||||
|
||||
public String callingCodeForCountryCode(String countryCode) {
|
||||
return countryCallingCode.get(countryCode.toLowerCase());
|
||||
}
|
||||
|
||||
public ArrayList countriesForCallingCode(String callingCode) {
|
||||
if (callingCode.startsWith("+")) {
|
||||
callingCode = callingCode.substring(1);
|
||||
}
|
||||
|
||||
return callingCodeCountries.get(callingCode);
|
||||
}
|
||||
|
||||
public CallingCodeInfo findCallingCodeInfo(String str) {
|
||||
CallingCodeInfo res = null;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (i < str.length()) {
|
||||
res = callingCodeInfo(str.substring(0, i + 1));
|
||||
if (res != null) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public String format(String orig) {
|
||||
String str = strip(orig);
|
||||
|
||||
if (str.startsWith("+")) {
|
||||
String rest = str.substring(1);
|
||||
CallingCodeInfo info = findCallingCodeInfo(rest);
|
||||
if (info != null) {
|
||||
String phone = info.format(rest);
|
||||
return "+" + phone;
|
||||
} else {
|
||||
return orig;
|
||||
}
|
||||
} else {
|
||||
CallingCodeInfo info = callingCodeInfo(defaultCallingCode);
|
||||
if (info == null) {
|
||||
return orig;
|
||||
}
|
||||
|
||||
String accessCode = info.matchingAccessCode(str);
|
||||
if (accessCode != null) {
|
||||
String rest = str.substring(accessCode.length());
|
||||
String phone = rest;
|
||||
CallingCodeInfo info2 = findCallingCodeInfo(rest);
|
||||
if (info2 != null) {
|
||||
phone = info2.format(rest);
|
||||
}
|
||||
|
||||
if (phone.length() == 0) {
|
||||
return accessCode;
|
||||
} else {
|
||||
return String.format("%s %s", accessCode, phone);
|
||||
}
|
||||
} else {
|
||||
return info.format(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPhoneNumberValid(String phoneNumber) {
|
||||
String str = strip(phoneNumber);
|
||||
|
||||
if (str.startsWith("+")) {
|
||||
String rest = str.substring(1);
|
||||
CallingCodeInfo info = findCallingCodeInfo(rest);
|
||||
return info != null && info.isValidPhoneNumber(rest);
|
||||
} else {
|
||||
CallingCodeInfo info = callingCodeInfo(defaultCallingCode);
|
||||
if (info == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String accessCode = info.matchingAccessCode(str);
|
||||
if (accessCode != null) {
|
||||
String rest = str.substring(accessCode.length());
|
||||
if (rest.length() != 0) {
|
||||
CallingCodeInfo info2 = findCallingCodeInfo(rest);
|
||||
return info2 != null && info2.isValidPhoneNumber(rest);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return info.isValidPhoneNumber(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int value32(int offset) {
|
||||
if (offset + 4 <= data.length) {
|
||||
buffer.position(offset);
|
||||
return buffer.getInt();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
short value16(int offset) {
|
||||
if (offset + 2 <= data.length) {
|
||||
buffer.position(offset);
|
||||
return buffer.getShort();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public String valueString(int offset) {
|
||||
try {
|
||||
for (int a = offset; a < data.length; a++) {
|
||||
if (data[a] == '\0') {
|
||||
if (offset == a - offset) {
|
||||
return "";
|
||||
}
|
||||
return new String(data, offset, a - offset);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public CallingCodeInfo callingCodeInfo(String callingCode) {
|
||||
CallingCodeInfo res = callingCodeData.get(callingCode);
|
||||
if (res == null) {
|
||||
Integer num = callingCodeOffsets.get(callingCode);
|
||||
if (num != null) {
|
||||
final byte[] bytes = data;
|
||||
int start = num;
|
||||
int offset = start;
|
||||
res = new CallingCodeInfo();
|
||||
res.callingCode = callingCode;
|
||||
res.countries = callingCodeCountries.get(callingCode);
|
||||
callingCodeData.put(callingCode, res);
|
||||
|
||||
int block1Len = value16(offset);
|
||||
offset += 2;
|
||||
|
||||
offset += 2;
|
||||
int block2Len = value16(offset);
|
||||
offset += 2;
|
||||
|
||||
offset += 2;
|
||||
int setCnt = value16(offset);
|
||||
offset += 2;
|
||||
|
||||
offset += 2;
|
||||
|
||||
ArrayList<String> strs = new ArrayList<String>(5);
|
||||
String str;
|
||||
while ((str = valueString(offset)).length() != 0) {
|
||||
strs.add(str);
|
||||
offset += str.length() + 1;
|
||||
}
|
||||
res.trunkPrefixes = strs;
|
||||
offset++;
|
||||
|
||||
strs = new ArrayList<String>(5);
|
||||
while ((str = valueString(offset)).length() != 0) {
|
||||
strs.add(str);
|
||||
offset += str.length() + 1;
|
||||
}
|
||||
res.intlPrefixes = strs;
|
||||
|
||||
ArrayList<RuleSet> ruleSets = new ArrayList<RuleSet>(setCnt);
|
||||
offset = start + block1Len;
|
||||
for (int s = 0; s < setCnt; s++) {
|
||||
RuleSet ruleSet = new RuleSet();
|
||||
ruleSet.matchLen = value16(offset);
|
||||
offset += 2;
|
||||
int ruleCnt = value16(offset);
|
||||
offset += 2;
|
||||
ArrayList<PhoneRule> rules = new ArrayList<PhoneRule>(ruleCnt);
|
||||
for (int r = 0; r < ruleCnt; r++) {
|
||||
PhoneRule rule = new PhoneRule();
|
||||
rule.minVal = value32(offset);
|
||||
offset += 4;
|
||||
rule.maxVal = value32(offset);
|
||||
offset += 4;
|
||||
rule.byte8 = (int)bytes[offset++];
|
||||
rule.maxLen = (int)bytes[offset++];
|
||||
rule.otherFlag = (int)bytes[offset++];
|
||||
rule.prefixLen = (int)bytes[offset++];
|
||||
rule.flag12 = (int)bytes[offset++];
|
||||
rule.flag13 = (int)bytes[offset++];
|
||||
int strOffset = value16(offset);
|
||||
offset += 2;
|
||||
rule.format = valueString(start + block1Len + block2Len + strOffset);
|
||||
|
||||
int openPos = rule.format.indexOf("[[");
|
||||
if (openPos != -1) {
|
||||
int closePos = rule.format.indexOf("]]");
|
||||
rule.format = String.format("%s%s", rule.format.substring(0, openPos), rule.format.substring(closePos + 2));
|
||||
}
|
||||
|
||||
rules.add(rule);
|
||||
|
||||
if (rule.hasIntlPrefix) {
|
||||
ruleSet.hasRuleWithIntlPrefix = true;
|
||||
}
|
||||
if (rule.hasTrunkPrefix) {
|
||||
ruleSet.hasRuleWithTrunkPrefix = true;
|
||||
}
|
||||
}
|
||||
ruleSet.rules = rules;
|
||||
ruleSets.add(ruleSet);
|
||||
}
|
||||
res.ruleSets = ruleSets;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public void parseDataHeader() {
|
||||
int count = value32(0);
|
||||
int base = count * 12 + 4;
|
||||
int spot = 4;
|
||||
for (int i = 0; i < count; i++) {
|
||||
String callingCode = valueString(spot);
|
||||
spot += 4;
|
||||
String country = valueString(spot);
|
||||
spot += 4;
|
||||
int offset = value32(spot) + base;
|
||||
spot += 4;
|
||||
|
||||
if (country.equals(defaultCountry)) {
|
||||
defaultCallingCode = callingCode;
|
||||
}
|
||||
|
||||
countryCallingCode.put(country, callingCode);
|
||||
|
||||
callingCodeOffsets.put(callingCode, offset);
|
||||
ArrayList<String> countries = callingCodeCountries.get(callingCode);
|
||||
if (countries == null) {
|
||||
countries = new ArrayList<String>();
|
||||
callingCodeCountries.put(callingCode, countries);
|
||||
}
|
||||
countries.add(country);
|
||||
}
|
||||
|
||||
if (defaultCallingCode != null) {
|
||||
callingCodeInfo(defaultCallingCode);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
// Copyright (c) 2012, Rick Maddy
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package org.telegram.PhoneFormat;
|
||||
|
||||
public class PhoneRule {
|
||||
public int minVal;
|
||||
public int maxVal;
|
||||
public int byte8;
|
||||
public int maxLen;
|
||||
public int otherFlag;
|
||||
public int prefixLen;
|
||||
public int flag12;
|
||||
public int flag13;
|
||||
public String format;
|
||||
public boolean hasIntlPrefix;
|
||||
public boolean hasTrunkPrefix;
|
||||
|
||||
String format(String str, String intlPrefix, String trunkPrefix) {
|
||||
boolean hadC = false;
|
||||
boolean hadN = false;
|
||||
boolean hasOpen = false;
|
||||
int spot = 0;
|
||||
StringBuilder res = new StringBuilder(20);
|
||||
for (int i = 0; i < format.length(); i++) {
|
||||
char ch = format.charAt(i);
|
||||
switch (ch) {
|
||||
case 'c':
|
||||
hadC = true;
|
||||
if (intlPrefix != null) {
|
||||
res.append(intlPrefix);
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
hadN = true;
|
||||
if (trunkPrefix != null) {
|
||||
res.append(trunkPrefix);
|
||||
}
|
||||
break;
|
||||
case '#':
|
||||
if (spot < str.length()) {
|
||||
res.append(str.substring(spot, spot + 1));
|
||||
spot++;
|
||||
} else if (hasOpen) {
|
||||
res.append(" ");
|
||||
}
|
||||
break;
|
||||
case '(':
|
||||
if (spot < str.length()) {
|
||||
hasOpen = true;
|
||||
}
|
||||
default:
|
||||
if (!(ch == ' ' && i > 0 && ((format.charAt(i - 1) == 'n' && trunkPrefix == null) || (format.charAt(i - 1) == 'c' && intlPrefix == null)))) {
|
||||
if (spot < str.length() || (hasOpen && ch == ')')) {
|
||||
res.append(format.substring(i, i + 1));
|
||||
if (ch == ')') {
|
||||
hasOpen = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (intlPrefix != null && !hadC) {
|
||||
res.insert(0, String.format("%s ", intlPrefix));
|
||||
} else if (trunkPrefix != null && !hadN) {
|
||||
res.insert(0, trunkPrefix);
|
||||
}
|
||||
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
boolean hasIntlPrefix() {
|
||||
return (flag12 & 0x02) != 0;
|
||||
}
|
||||
|
||||
boolean hasTrunkPrefix() {
|
||||
return (flag12 & 0x01) != 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
// Copyright (c) 2012, Rick Maddy
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package org.telegram.PhoneFormat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class RuleSet {
|
||||
public int matchLen;
|
||||
public ArrayList<PhoneRule> rules;
|
||||
public boolean hasRuleWithIntlPrefix;
|
||||
public boolean hasRuleWithTrunkPrefix;
|
||||
public static Pattern pattern = Pattern.compile("[0-9]+");
|
||||
|
||||
String format(String str, String intlPrefix, String trunkPrefix, boolean prefixRequired) {
|
||||
if (str.length() >= matchLen) {
|
||||
String begin = str.substring(0, matchLen);
|
||||
|
||||
int val = 0;
|
||||
Matcher matcher = pattern.matcher(begin);
|
||||
if (matcher.find()) {
|
||||
String num = matcher.group(0);
|
||||
val = Integer.parseInt(num);
|
||||
}
|
||||
|
||||
for (PhoneRule rule : rules) {
|
||||
if (val >= rule.minVal && val <= rule.maxVal && str.length() <= rule.maxLen) {
|
||||
if (prefixRequired) {
|
||||
if (((rule.flag12 & 0x03) == 0 && trunkPrefix == null && intlPrefix == null) || (trunkPrefix != null && (rule.flag12 & 0x01) != 0) || (intlPrefix != null && (rule.flag12 & 0x02) != 0)) {
|
||||
return rule.format(str, intlPrefix, trunkPrefix);
|
||||
}
|
||||
} else {
|
||||
if ((trunkPrefix == null && intlPrefix == null) || (trunkPrefix != null && (rule.flag12 & 0x01) != 0) || (intlPrefix != null && (rule.flag12 & 0x02) != 0)) {
|
||||
return rule.format(str, intlPrefix, trunkPrefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!prefixRequired) {
|
||||
if (intlPrefix != null) {
|
||||
for (PhoneRule rule : rules) {
|
||||
if (val >= rule.minVal && val <= rule.maxVal && str.length() <= rule.maxLen) {
|
||||
if (trunkPrefix == null || (rule.flag12 & 0x01) != 0) {
|
||||
return rule.format(str, intlPrefix, trunkPrefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (trunkPrefix != null) {
|
||||
for (PhoneRule rule : rules) {
|
||||
if (val >= rule.minVal && val <= rule.maxVal && str.length() <= rule.maxLen) {
|
||||
if (intlPrefix == null || (rule.flag12 & 0x02) != 0) {
|
||||
return rule.format(str, intlPrefix, trunkPrefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
boolean isValid(String str, String intlPrefix, String trunkPrefix, boolean prefixRequired) {
|
||||
if (str.length() >= matchLen) {
|
||||
String begin = str.substring(0, matchLen);
|
||||
int val = 0;
|
||||
Matcher matcher = pattern.matcher(begin);
|
||||
if (matcher.find()) {
|
||||
String num = matcher.group(0);
|
||||
val = Integer.parseInt(num);
|
||||
}
|
||||
|
||||
for (PhoneRule rule : rules) {
|
||||
if (val >= rule.minVal && val <= rule.maxVal && str.length() == rule.maxLen) {
|
||||
if (prefixRequired) {
|
||||
if (((rule.flag12 & 0x03) == 0 && trunkPrefix == null && intlPrefix == null) || (trunkPrefix != null && (rule.flag12 & 0x01) != 0) || (intlPrefix != null && (rule.flag12 & 0x02) != 0)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if ((trunkPrefix == null && intlPrefix == null) || (trunkPrefix != null && (rule.flag12 & 0x01) != 0) || (intlPrefix != null && (rule.flag12 & 0x02) != 0)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!prefixRequired) {
|
||||
if (intlPrefix != null && !hasRuleWithIntlPrefix) {
|
||||
for (PhoneRule rule : rules) {
|
||||
if (val >= rule.minVal && val <= rule.maxVal && str.length() == rule.maxLen) {
|
||||
if (trunkPrefix == null || (rule.flag12 & 0x01) != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (trunkPrefix != null && !hasRuleWithTrunkPrefix) {
|
||||
for (PhoneRule rule : rules) {
|
||||
if (val >= rule.minVal && val <= rule.maxVal && str.length() == rule.maxLen) {
|
||||
if (intlPrefix == null || (rule.flag12 & 0x02) != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
125
TMessagesProj/src/main/java/org/telegram/SQLite/SQLiteCursor.java
Executable file
125
TMessagesProj/src/main/java/org/telegram/SQLite/SQLiteCursor.java
Executable file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.SQLite;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
public class SQLiteCursor {
|
||||
|
||||
public static final int FIELD_TYPE_INT = 1;
|
||||
public static final int FIELD_TYPE_FLOAT = 2;
|
||||
public static final int FIELD_TYPE_STRING = 3;
|
||||
public static final int FIELD_TYPE_BYTEARRAY = 4;
|
||||
public static final int FIELD_TYPE_NULL = 5;
|
||||
|
||||
SQLitePreparedStatement preparedStatement;
|
||||
boolean inRow = false;
|
||||
|
||||
public SQLiteCursor(SQLitePreparedStatement stmt) {
|
||||
preparedStatement = stmt;
|
||||
}
|
||||
|
||||
public boolean isNull(int columnIndex) throws SQLiteException {
|
||||
checkRow();
|
||||
return columnIsNull(preparedStatement.getStatementHandle(), columnIndex) == 1;
|
||||
}
|
||||
|
||||
public int intValue(int columnIndex) throws SQLiteException {
|
||||
checkRow();
|
||||
return columnIntValue(preparedStatement.getStatementHandle(), columnIndex);
|
||||
}
|
||||
|
||||
public double doubleValue(int columnIndex) throws SQLiteException {
|
||||
checkRow();
|
||||
return columnDoubleValue(preparedStatement.getStatementHandle(), columnIndex);
|
||||
}
|
||||
|
||||
public long longValue(int columnIndex) throws SQLiteException {
|
||||
checkRow();
|
||||
return columnLongValue(preparedStatement.getStatementHandle(), columnIndex);
|
||||
}
|
||||
|
||||
public String stringValue(int columnIndex) throws SQLiteException {
|
||||
checkRow();
|
||||
return columnStringValue(preparedStatement.getStatementHandle(), columnIndex);
|
||||
}
|
||||
|
||||
public byte[] byteArrayValue(int columnIndex) throws SQLiteException {
|
||||
checkRow();
|
||||
return columnByteArrayValue(preparedStatement.getStatementHandle(), columnIndex);
|
||||
}
|
||||
|
||||
public int getTypeOf(int columnIndex) throws SQLiteException {
|
||||
checkRow();
|
||||
return columnType(preparedStatement.getStatementHandle(), columnIndex);
|
||||
}
|
||||
|
||||
public Object objectValue(int columnIndex) throws SQLiteException {
|
||||
checkRow();
|
||||
|
||||
int type = columnType(preparedStatement.getStatementHandle(), columnIndex);
|
||||
switch (type) {
|
||||
case FIELD_TYPE_INT:
|
||||
return intValue(columnIndex);
|
||||
case FIELD_TYPE_BYTEARRAY:
|
||||
return byteArrayValue(columnIndex);
|
||||
case FIELD_TYPE_FLOAT:
|
||||
return doubleValue(columnIndex);
|
||||
case FIELD_TYPE_STRING:
|
||||
return stringValue(columnIndex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean next() throws SQLiteException {
|
||||
int res = preparedStatement.step(preparedStatement.getStatementHandle());
|
||||
if(res == -1) {
|
||||
int repeatCount = 6;
|
||||
while (repeatCount-- != 0) {
|
||||
try {
|
||||
Log.e("tmessages", "sqlite busy, waiting...");
|
||||
Thread.sleep(500);
|
||||
res = preparedStatement.step();
|
||||
if (res == 0) {
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (res == -1) {
|
||||
throw new SQLiteException("sqlite busy");
|
||||
}
|
||||
}
|
||||
inRow = (res == 0);
|
||||
return inRow;
|
||||
}
|
||||
|
||||
public int getStatementHandle() {
|
||||
return preparedStatement.getStatementHandle();
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
preparedStatement.dispose();
|
||||
}
|
||||
|
||||
void checkRow() throws SQLiteException {
|
||||
if (!inRow) {
|
||||
throw new SQLiteException("You must call next before");
|
||||
}
|
||||
}
|
||||
|
||||
native int columnType(int statementHandle, int columnIndex);
|
||||
native int columnIsNull(int statementHandle, int columnIndex);
|
||||
native int columnIntValue(int statementHandle, int columnIndex);
|
||||
native long columnLongValue(int statementHandle, int columnIndex);
|
||||
native double columnDoubleValue(int statementHandle, int columnIndex);
|
||||
native String columnStringValue(int statementHandle, int columnIndex);
|
||||
native byte[] columnByteArrayValue(int statementHandle, int columnIndex);
|
||||
}
|
149
TMessagesProj/src/main/java/org/telegram/SQLite/SQLiteDatabase.java
Executable file
149
TMessagesProj/src/main/java/org/telegram/SQLite/SQLiteDatabase.java
Executable file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.SQLite;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
public class SQLiteDatabase {
|
||||
private final int sqliteHandle;
|
||||
|
||||
private final Map<String, SQLitePreparedStatement> preparedMap;
|
||||
private boolean isOpen = false;
|
||||
private boolean inTransaction = false;
|
||||
|
||||
public int getSQLiteHandle() {
|
||||
return sqliteHandle;
|
||||
}
|
||||
|
||||
public SQLiteDatabase(String fileName) throws SQLiteException {
|
||||
sqliteHandle = opendb(fileName);
|
||||
isOpen = true;
|
||||
preparedMap = new HashMap<String, SQLitePreparedStatement>();
|
||||
}
|
||||
|
||||
public boolean tableExists(String tableName) throws SQLiteException {
|
||||
checkOpened();
|
||||
String s = "SELECT rowid FROM sqlite_master WHERE type='table' AND name=?;";
|
||||
return executeInt(s, tableName) != null;
|
||||
}
|
||||
|
||||
public void execute(String sql, Object... args) throws SQLiteException {
|
||||
checkOpened();
|
||||
SQLiteCursor cursor = query(sql, args);
|
||||
try {
|
||||
cursor.next();
|
||||
} finally {
|
||||
cursor.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public SQLitePreparedStatement executeFast(String sql) throws SQLiteException{
|
||||
return new SQLitePreparedStatement(this, sql, true);
|
||||
}
|
||||
|
||||
public Integer executeInt(String sql, Object... args) throws SQLiteException {
|
||||
checkOpened();
|
||||
SQLiteCursor cursor = query(sql, args);
|
||||
try {
|
||||
if (!cursor.next()) {
|
||||
return null;
|
||||
}
|
||||
return cursor.intValue(0);
|
||||
} finally {
|
||||
cursor.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public int executeIntOrThrow(String sql, Object... args) throws SQLiteException, SQLiteNoRowException {
|
||||
checkOpened();
|
||||
Integer val = executeInt(sql, args);
|
||||
if (val != null) {
|
||||
return val;
|
||||
}
|
||||
|
||||
throw new SQLiteNoRowException();
|
||||
}
|
||||
|
||||
public String executeString(String sql, Object... args) throws SQLiteException {
|
||||
checkOpened();
|
||||
SQLiteCursor cursor = query(sql, args);
|
||||
try {
|
||||
if (!cursor.next()) {
|
||||
return null;
|
||||
}
|
||||
return cursor.stringValue(0);
|
||||
} finally {
|
||||
cursor.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public SQLiteCursor query(String sql, Object... args) throws SQLiteException {
|
||||
checkOpened();
|
||||
SQLitePreparedStatement stmt = preparedMap.get(sql);
|
||||
|
||||
if (stmt == null) {
|
||||
stmt = new SQLitePreparedStatement(this, sql, false);
|
||||
preparedMap.put(sql, stmt);
|
||||
}
|
||||
|
||||
return stmt.query(args);
|
||||
}
|
||||
|
||||
public SQLiteCursor queryFinalized(String sql, Object... args) throws SQLiteException {
|
||||
checkOpened();
|
||||
return new SQLitePreparedStatement(this, sql, true).query(args);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (isOpen) {
|
||||
try {
|
||||
for (SQLitePreparedStatement stmt : preparedMap.values()) {
|
||||
stmt.finalizeQuery();
|
||||
}
|
||||
closedb(sqliteHandle);
|
||||
} catch (SQLiteException e) {
|
||||
Log.e("tmessages", e.getMessage(), e);
|
||||
}
|
||||
isOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
void checkOpened() throws SQLiteException {
|
||||
if (!isOpen) {
|
||||
throw new SQLiteException("Database closed");
|
||||
}
|
||||
}
|
||||
|
||||
public void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
close();
|
||||
}
|
||||
|
||||
private StackTraceElement[] temp;
|
||||
public void beginTransaction() throws SQLiteException {
|
||||
if (inTransaction) {
|
||||
throw new SQLiteException("database already in transaction");
|
||||
}
|
||||
inTransaction = true;
|
||||
beginTransaction(sqliteHandle);
|
||||
}
|
||||
|
||||
public void commitTransaction() {
|
||||
inTransaction = false;
|
||||
commitTransaction(sqliteHandle);
|
||||
}
|
||||
|
||||
native int opendb(String fileName) throws SQLiteException;
|
||||
native void closedb(int sqliteHandle) throws SQLiteException;
|
||||
native void beginTransaction(int sqliteHandle);
|
||||
native void commitTransaction(int sqliteHandle);
|
||||
}
|
27
TMessagesProj/src/main/java/org/telegram/SQLite/SQLiteException.java
Executable file
27
TMessagesProj/src/main/java/org/telegram/SQLite/SQLiteException.java
Executable file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.SQLite;
|
||||
|
||||
public class SQLiteException extends Exception {
|
||||
private static final long serialVersionUID = -2398298479089615621L;
|
||||
public final int errorCode;
|
||||
|
||||
public SQLiteException(int errcode, String msg) {
|
||||
super(msg);
|
||||
errorCode = errcode;
|
||||
}
|
||||
|
||||
public SQLiteException(String msg) {
|
||||
this(0, msg);
|
||||
}
|
||||
|
||||
public SQLiteException() {
|
||||
errorCode = 0;
|
||||
}
|
||||
}
|
13
TMessagesProj/src/main/java/org/telegram/SQLite/SQLiteNoRowException.java
Executable file
13
TMessagesProj/src/main/java/org/telegram/SQLite/SQLiteNoRowException.java
Executable file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.SQLite;
|
||||
|
||||
public class SQLiteNoRowException extends Exception {
|
||||
private static final long serialVersionUID = 4098095358028103112L;
|
||||
}
|
127
TMessagesProj/src/main/java/org/telegram/SQLite/SQLitePreparedStatement.java
Executable file
127
TMessagesProj/src/main/java/org/telegram/SQLite/SQLitePreparedStatement.java
Executable file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.SQLite;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
public class SQLitePreparedStatement {
|
||||
private boolean isFinalized = false;
|
||||
private int sqliteStatementHandle;
|
||||
|
||||
private int queryArgsCount;
|
||||
private boolean finalizeAfterQuery = false;
|
||||
|
||||
public int getStatementHandle() {
|
||||
return sqliteStatementHandle;
|
||||
}
|
||||
|
||||
public SQLitePreparedStatement(SQLiteDatabase db, String sql, boolean finalize) throws SQLiteException {
|
||||
finalizeAfterQuery = finalize;
|
||||
sqliteStatementHandle = prepare(db.getSQLiteHandle(), sql);
|
||||
}
|
||||
|
||||
public SQLiteCursor query(Object[] args) throws SQLiteException {
|
||||
if (args == null || args.length != queryArgsCount) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
checkFinalized();
|
||||
|
||||
reset(sqliteStatementHandle);
|
||||
|
||||
int i = 1;
|
||||
for (Object obj : args) {
|
||||
if (obj == null) {
|
||||
bindNull(sqliteStatementHandle, i);
|
||||
} else if (obj instanceof Integer) {
|
||||
bindInt(sqliteStatementHandle, i, (Integer)obj);
|
||||
} else if (obj instanceof Double) {
|
||||
bindDouble(sqliteStatementHandle, i, (Double)obj);
|
||||
} else if (obj instanceof String) {
|
||||
bindString(sqliteStatementHandle, i, (String)obj);
|
||||
} else if (obj instanceof byte[]) {
|
||||
bindByteArray(sqliteStatementHandle, i, (byte[])obj);
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return new SQLiteCursor(this);
|
||||
}
|
||||
|
||||
public int step() throws SQLiteException {
|
||||
return step(sqliteStatementHandle);
|
||||
}
|
||||
|
||||
public SQLitePreparedStatement stepThis() throws SQLiteException {
|
||||
step(sqliteStatementHandle);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void requery() throws SQLiteException {
|
||||
checkFinalized();
|
||||
reset(sqliteStatementHandle);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
if (finalizeAfterQuery) {
|
||||
finalizeQuery();
|
||||
}
|
||||
}
|
||||
|
||||
void checkFinalized() throws SQLiteException {
|
||||
if (isFinalized) {
|
||||
throw new SQLiteException("Prepared query finalized");
|
||||
}
|
||||
}
|
||||
|
||||
public void finalizeQuery() {
|
||||
if (isFinalized) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
isFinalized = true;
|
||||
finalize(sqliteStatementHandle);
|
||||
} catch (SQLiteException e) {
|
||||
Log.e("tmessages", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void bindInteger(int index, int value) throws SQLiteException {
|
||||
bindInt(sqliteStatementHandle, index, value);
|
||||
}
|
||||
|
||||
public void bindDouble(int index, double value) throws SQLiteException {
|
||||
bindDouble(sqliteStatementHandle, index, value);
|
||||
}
|
||||
|
||||
public void bindByteArray(int index, byte[] value) throws SQLiteException {
|
||||
bindByteArray(sqliteStatementHandle, index, value);
|
||||
}
|
||||
|
||||
public void bindString(int index, String value) throws SQLiteException {
|
||||
bindString(sqliteStatementHandle, index, value);
|
||||
}
|
||||
|
||||
public void bindLong(int index, long value) throws SQLiteException {
|
||||
bindLong(sqliteStatementHandle, index, value);
|
||||
}
|
||||
|
||||
native void bindByteArray(int statementHandle, int index, byte[] value) throws SQLiteException;
|
||||
native void bindString(int statementHandle, int index, String value) throws SQLiteException;
|
||||
native void bindInt(int statementHandle, int index, int value) throws SQLiteException;
|
||||
native void bindLong(int statementHandle, int index, long value) throws SQLiteException;
|
||||
native void bindDouble(int statementHandle, int index, double value) throws SQLiteException;
|
||||
native void bindNull(int statementHandle, int index) throws SQLiteException;
|
||||
native void reset(int statementHandle) throws SQLiteException;
|
||||
native int prepare(int sqliteHandle, String sql) throws SQLiteException;
|
||||
native void finalize(int statementHandle) throws SQLiteException;
|
||||
native int step(int statementHandle) throws SQLiteException;
|
||||
}
|
436
TMessagesProj/src/main/java/org/telegram/TL/TLClassStore.java
Normal file
436
TMessagesProj/src/main/java/org/telegram/TL/TLClassStore.java
Normal file
@ -0,0 +1,436 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.TL;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.telegram.messenger.ConnectionsManager;
|
||||
import org.telegram.messenger.SerializedData;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class TLClassStore {
|
||||
private HashMap<Integer, Class> classStore;
|
||||
|
||||
public TLClassStore () {
|
||||
classStore = new HashMap<Integer, Class>();
|
||||
|
||||
classStore.put(TLRPC.TL_chatPhotoEmpty.constructor, TLRPC.TL_chatPhotoEmpty.class);
|
||||
classStore.put(TLRPC.TL_chatPhoto.constructor, TLRPC.TL_chatPhoto.class);
|
||||
classStore.put(TLRPC.TL_futuresalts.constructor, TLRPC.TL_futuresalts.class);
|
||||
classStore.put(TLRPC.TL_bad_msg_notification.constructor, TLRPC.TL_bad_msg_notification.class);
|
||||
classStore.put(TLRPC.TL_bad_server_salt.constructor, TLRPC.TL_bad_server_salt.class);
|
||||
classStore.put(TLRPC.TL_error.constructor, TLRPC.TL_error.class);
|
||||
classStore.put(TLRPC.TL_messages_sentEncryptedMessage.constructor, TLRPC.TL_messages_sentEncryptedMessage.class);
|
||||
classStore.put(TLRPC.TL_messages_sentEncryptedFile.constructor, TLRPC.TL_messages_sentEncryptedFile.class);
|
||||
classStore.put(TLRPC.TL_auth_checkedPhone.constructor, TLRPC.TL_auth_checkedPhone.class);
|
||||
classStore.put(TLRPC.TL_msgs_ack.constructor, TLRPC.TL_msgs_ack.class);
|
||||
classStore.put(TLRPC.TL_messages_chatFull.constructor, TLRPC.TL_messages_chatFull.class);
|
||||
classStore.put(TLRPC.TL_rpc_result.constructor, TLRPC.TL_rpc_result.class);
|
||||
classStore.put(TLRPC.TL_contactStatus.constructor, TLRPC.TL_contactStatus.class);
|
||||
classStore.put(TLRPC.TL_auth_authorization.constructor, TLRPC.TL_auth_authorization.class);
|
||||
classStore.put(TLRPC.TL_messages_messages.constructor, TLRPC.TL_messages_messages.class);
|
||||
classStore.put(TLRPC.TL_messages_messagesSlice.constructor, TLRPC.TL_messages_messagesSlice.class);
|
||||
classStore.put(TLRPC.TL_rpc_answer_unknown.constructor, TLRPC.TL_rpc_answer_unknown.class);
|
||||
classStore.put(TLRPC.TL_rpc_answer_dropped.constructor, TLRPC.TL_rpc_answer_dropped.class);
|
||||
classStore.put(TLRPC.TL_rpc_answer_dropped_running.constructor, TLRPC.TL_rpc_answer_dropped_running.class);
|
||||
classStore.put(TLRPC.TL_contacts_link.constructor, TLRPC.TL_contacts_link.class);
|
||||
classStore.put(TLRPC.TL_encryptedFile.constructor, TLRPC.TL_encryptedFile.class);
|
||||
classStore.put(TLRPC.TL_encryptedFileEmpty.constructor, TLRPC.TL_encryptedFileEmpty.class);
|
||||
classStore.put(TLRPC.TL_peerUser.constructor, TLRPC.TL_peerUser.class);
|
||||
classStore.put(TLRPC.TL_peerChat.constructor, TLRPC.TL_peerChat.class);
|
||||
classStore.put(TLRPC.TL_destroy_session_ok.constructor, TLRPC.TL_destroy_session_ok.class);
|
||||
classStore.put(TLRPC.TL_destroy_session_none.constructor, TLRPC.TL_destroy_session_none.class);
|
||||
classStore.put(TLRPC.TL_updates_difference.constructor, TLRPC.TL_updates_difference.class);
|
||||
classStore.put(TLRPC.TL_updates_getDifference.constructor, TLRPC.TL_updates_getDifference.class);
|
||||
classStore.put(TLRPC.TL_updates_differenceSlice.constructor, TLRPC.TL_updates_differenceSlice.class);
|
||||
classStore.put(TLRPC.TL_updates_differenceEmpty.constructor, TLRPC.TL_updates_differenceEmpty.class);
|
||||
classStore.put(TLRPC.TL_geoPointEmpty.constructor, TLRPC.TL_geoPointEmpty.class);
|
||||
classStore.put(TLRPC.TL_geoPoint.constructor, TLRPC.TL_geoPoint.class);
|
||||
classStore.put(TLRPC.TL_messageForwarded.constructor, TLRPC.TL_messageForwarded.class);
|
||||
classStore.put(TLRPC.TL_messageEmpty.constructor, TLRPC.TL_messageEmpty.class);
|
||||
classStore.put(TLRPC.TL_message.constructor, TLRPC.TL_message.class);
|
||||
classStore.put(TLRPC.TL_messageService.constructor, TLRPC.TL_messageService.class);
|
||||
classStore.put(TLRPC.TL_inputPhoneContact.constructor, TLRPC.TL_inputPhoneContact.class);
|
||||
classStore.put(TLRPC.TL_invokeAfterMsg.constructor, TLRPC.TL_invokeAfterMsg.class);
|
||||
classStore.put(TLRPC.TL_messageMediaVideo.constructor, TLRPC.TL_messageMediaVideo.class);
|
||||
classStore.put(TLRPC.TL_messageMediaGeo.constructor, TLRPC.TL_messageMediaGeo.class);
|
||||
classStore.put(TLRPC.TL_messageMediaPhoto.constructor, TLRPC.TL_messageMediaPhoto.class);
|
||||
classStore.put(TLRPC.TL_messageMediaEmpty.constructor, TLRPC.TL_messageMediaEmpty.class);
|
||||
classStore.put(TLRPC.TL_messageMediaContact.constructor, TLRPC.TL_messageMediaContact.class);
|
||||
classStore.put(TLRPC.TL_auth_sentCode.constructor, TLRPC.TL_auth_sentCode.class);
|
||||
classStore.put(TLRPC.TL_peerNotifySettingsEmpty.constructor, TLRPC.TL_peerNotifySettingsEmpty.class);
|
||||
classStore.put(TLRPC.TL_peerNotifySettings.constructor, TLRPC.TL_peerNotifySettings.class);
|
||||
classStore.put(TLRPC.TL_msg_resend_req.constructor, TLRPC.TL_msg_resend_req.class);
|
||||
classStore.put(TLRPC.TL_http_wait.constructor, TLRPC.TL_http_wait.class);
|
||||
classStore.put(TLRPC.TL_contacts_blocked.constructor, TLRPC.TL_contacts_blocked.class);
|
||||
classStore.put(TLRPC.TL_contacts_blockedSlice.constructor, TLRPC.TL_contacts_blockedSlice.class);
|
||||
classStore.put(TLRPC.TL_inputGeoPoint.constructor, TLRPC.TL_inputGeoPoint.class);
|
||||
classStore.put(TLRPC.TL_inputGeoPointEmpty.constructor, TLRPC.TL_inputGeoPointEmpty.class);
|
||||
classStore.put(TLRPC.TL_help_inviteText.constructor, TLRPC.TL_help_inviteText.class);
|
||||
classStore.put(TLRPC.TL_messages_dhConfigNotModified.constructor, TLRPC.TL_messages_dhConfigNotModified.class);
|
||||
classStore.put(TLRPC.TL_messages_dhConfig.constructor, TLRPC.TL_messages_dhConfig.class);
|
||||
classStore.put(TLRPC.TL_destroy_sessions_res.constructor, TLRPC.TL_destroy_sessions_res.class);
|
||||
classStore.put(TLRPC.TL_contacts_contacts.constructor, TLRPC.TL_contacts_contacts.class);
|
||||
classStore.put(TLRPC.TL_contacts_contactsNotModified.constructor, TLRPC.TL_contacts_contactsNotModified.class);
|
||||
classStore.put(TLRPC.TL_photos_photos.constructor, TLRPC.TL_photos_photos.class);
|
||||
classStore.put(TLRPC.TL_photos_photosSlice.constructor, TLRPC.TL_photos_photosSlice.class);
|
||||
classStore.put(TLRPC.TL_chatFull.constructor, TLRPC.TL_chatFull.class);
|
||||
classStore.put(TLRPC.TL_msgs_all_info.constructor, TLRPC.TL_msgs_all_info.class);
|
||||
classStore.put(TLRPC.TL_inputPeerNotifySettings.constructor, TLRPC.TL_inputPeerNotifySettings.class);
|
||||
classStore.put(TLRPC.TL_null.constructor, TLRPC.TL_null.class);
|
||||
classStore.put(TLRPC.TL_inputUserSelf.constructor, TLRPC.TL_inputUserSelf.class);
|
||||
classStore.put(TLRPC.TL_inputUserForeign.constructor, TLRPC.TL_inputUserForeign.class);
|
||||
classStore.put(TLRPC.TL_inputUserEmpty.constructor, TLRPC.TL_inputUserEmpty.class);
|
||||
classStore.put(TLRPC.TL_inputUserContact.constructor, TLRPC.TL_inputUserContact.class);
|
||||
classStore.put(TLRPC.TL_p_q_inner_data.constructor, TLRPC.TL_p_q_inner_data.class);
|
||||
classStore.put(TLRPC.TL_msgs_state_req.constructor, TLRPC.TL_msgs_state_req.class);
|
||||
classStore.put(TLRPC.TL_boolTrue.constructor, TLRPC.TL_boolTrue.class);
|
||||
classStore.put(TLRPC.TL_boolFalse.constructor, TLRPC.TL_boolFalse.class);
|
||||
classStore.put(TLRPC.TL_auth_exportedAuthorization.constructor, TLRPC.TL_auth_exportedAuthorization.class);
|
||||
classStore.put(TLRPC.TL_messages_statedMessagesLinks.constructor, TLRPC.TL_messages_statedMessagesLinks.class);
|
||||
classStore.put(TLRPC.TL_messages_statedMessages.constructor, TLRPC.TL_messages_statedMessages.class);
|
||||
classStore.put(TLRPC.TL_inputNotifyChats.constructor, TLRPC.TL_inputNotifyChats.class);
|
||||
classStore.put(TLRPC.TL_inputNotifyPeer.constructor, TLRPC.TL_inputNotifyPeer.class);
|
||||
classStore.put(TLRPC.TL_inputNotifyUsers.constructor, TLRPC.TL_inputNotifyUsers.class);
|
||||
classStore.put(TLRPC.TL_inputNotifyGeoChatPeer.constructor, TLRPC.TL_inputNotifyGeoChatPeer.class);
|
||||
classStore.put(TLRPC.TL_inputNotifyAll.constructor, TLRPC.TL_inputNotifyAll.class);
|
||||
classStore.put(TLRPC.TL_inputEncryptedFileLocation.constructor, TLRPC.TL_inputEncryptedFileLocation.class);
|
||||
classStore.put(TLRPC.TL_inputFileLocation.constructor, TLRPC.TL_inputFileLocation.class);
|
||||
classStore.put(TLRPC.TL_inputVideoFileLocation.constructor, TLRPC.TL_inputVideoFileLocation.class);
|
||||
classStore.put(TLRPC.TL_photos_photo.constructor, TLRPC.TL_photos_photo.class);
|
||||
classStore.put(TLRPC.TL_userContact.constructor, TLRPC.TL_userContact.class);
|
||||
classStore.put(TLRPC.TL_userRequest.constructor, TLRPC.TL_userRequest.class);
|
||||
classStore.put(TLRPC.TL_userForeign.constructor, TLRPC.TL_userForeign.class);
|
||||
classStore.put(TLRPC.TL_userDeleted.constructor, TLRPC.TL_userDeleted.class);
|
||||
classStore.put(TLRPC.TL_userSelf.constructor, TLRPC.TL_userSelf.class);
|
||||
classStore.put(TLRPC.TL_userEmpty.constructor, TLRPC.TL_userEmpty.class);
|
||||
classStore.put(TLRPC.TL_geoChatMessage.constructor, TLRPC.TL_geoChatMessage.class);
|
||||
classStore.put(TLRPC.TL_geoChatMessageService.constructor, TLRPC.TL_geoChatMessageService.class);
|
||||
classStore.put(TLRPC.TL_geoChatMessageEmpty.constructor, TLRPC.TL_geoChatMessageEmpty.class);
|
||||
classStore.put(TLRPC.TL_pong.constructor, TLRPC.TL_pong.class);
|
||||
classStore.put(TLRPC.TL_messageActionChatEditPhoto.constructor, TLRPC.TL_messageActionChatEditPhoto.class);
|
||||
classStore.put(TLRPC.TL_messageActionChatDeleteUser.constructor, TLRPC.TL_messageActionChatDeleteUser.class);
|
||||
classStore.put(TLRPC.TL_messageActionChatDeletePhoto.constructor, TLRPC.TL_messageActionChatDeletePhoto.class);
|
||||
classStore.put(TLRPC.TL_messageActionChatAddUser.constructor, TLRPC.TL_messageActionChatAddUser.class);
|
||||
classStore.put(TLRPC.TL_messageActionChatCreate.constructor, TLRPC.TL_messageActionChatCreate.class);
|
||||
classStore.put(TLRPC.TL_messageActionEmpty.constructor, TLRPC.TL_messageActionEmpty.class);
|
||||
classStore.put(TLRPC.TL_messageActionChatEditTitle.constructor, TLRPC.TL_messageActionChatEditTitle.class);
|
||||
classStore.put(TLRPC.TL_messageActionGeoChatCreate.constructor, TLRPC.TL_messageActionGeoChatCreate.class);
|
||||
classStore.put(TLRPC.TL_messageActionGeoChatCheckin.constructor, TLRPC.TL_messageActionGeoChatCheckin.class);
|
||||
classStore.put(TLRPC.TL_contacts_foreignLinkMutual.constructor, TLRPC.TL_contacts_foreignLinkMutual.class);
|
||||
classStore.put(TLRPC.TL_contacts_foreignLinkUnknown.constructor, TLRPC.TL_contacts_foreignLinkUnknown.class);
|
||||
classStore.put(TLRPC.TL_contacts_foreignLinkRequested.constructor, TLRPC.TL_contacts_foreignLinkRequested.class);
|
||||
classStore.put(TLRPC.TL_dh_gen_retry.constructor, TLRPC.TL_dh_gen_retry.class);
|
||||
classStore.put(TLRPC.TL_dh_gen_fail.constructor, TLRPC.TL_dh_gen_fail.class);
|
||||
classStore.put(TLRPC.TL_dh_gen_ok.constructor, TLRPC.TL_dh_gen_ok.class);
|
||||
classStore.put(TLRPC.TL_peerNotifyEventsAll.constructor, TLRPC.TL_peerNotifyEventsAll.class);
|
||||
classStore.put(TLRPC.TL_chatLocated.constructor, TLRPC.TL_chatLocated.class);
|
||||
classStore.put(TLRPC.TL_decryptedMessageService.constructor, TLRPC.TL_decryptedMessageService.class);
|
||||
classStore.put(TLRPC.TL_decryptedMessage.constructor, TLRPC.TL_decryptedMessage.class);
|
||||
classStore.put(TLRPC.TL_inputPeerNotifyEventsAll.constructor, TLRPC.TL_inputPeerNotifyEventsAll.class);
|
||||
classStore.put(TLRPC.TL_client_DH_inner_data.constructor, TLRPC.TL_client_DH_inner_data.class);
|
||||
classStore.put(TLRPC.TL_video.constructor, TLRPC.TL_video.class);
|
||||
classStore.put(TLRPC.TL_videoEmpty.constructor, TLRPC.TL_videoEmpty.class);
|
||||
classStore.put(TLRPC.TL_contactBlocked.constructor, TLRPC.TL_contactBlocked.class);
|
||||
classStore.put(TLRPC.TL_inputAppEvent.constructor, TLRPC.TL_inputAppEvent.class);
|
||||
classStore.put(TLRPC.TL_messages_affectedHistory.constructor, TLRPC.TL_messages_affectedHistory.class);
|
||||
classStore.put(TLRPC.TL_inputMediaUploadedPhoto.constructor, TLRPC.TL_inputMediaUploadedPhoto.class);
|
||||
classStore.put(TLRPC.TL_inputMediaVideo.constructor, TLRPC.TL_inputMediaVideo.class);
|
||||
classStore.put(TLRPC.TL_inputMediaGeoPoint.constructor, TLRPC.TL_inputMediaGeoPoint.class);
|
||||
classStore.put(TLRPC.TL_inputMediaContact.constructor, TLRPC.TL_inputMediaContact.class);
|
||||
classStore.put(TLRPC.TL_inputMediaUploadedThumbVideo.constructor, TLRPC.TL_inputMediaUploadedThumbVideo.class);
|
||||
classStore.put(TLRPC.TL_inputMediaUploadedVideo.constructor, TLRPC.TL_inputMediaUploadedVideo.class);
|
||||
classStore.put(TLRPC.TL_inputMediaPhoto.constructor, TLRPC.TL_inputMediaPhoto.class);
|
||||
classStore.put(TLRPC.TL_inputMediaEmpty.constructor, TLRPC.TL_inputMediaEmpty.class);
|
||||
classStore.put(TLRPC.TL_geochats_messagesSlice.constructor, TLRPC.TL_geochats_messagesSlice.class);
|
||||
classStore.put(TLRPC.TL_geochats_messages.constructor, TLRPC.TL_geochats_messages.class);
|
||||
classStore.put(TLRPC.TL_messages_sentMessage.constructor, TLRPC.TL_messages_sentMessage.class);
|
||||
classStore.put(TLRPC.TL_messages_sentMessageLink.constructor, TLRPC.TL_messages_sentMessageLink.class);
|
||||
classStore.put(TLRPC.TL_encryptedMessageService.constructor, TLRPC.TL_encryptedMessageService.class);
|
||||
classStore.put(TLRPC.TL_encryptedMessage.constructor, TLRPC.TL_encryptedMessage.class);
|
||||
classStore.put(TLRPC.TL_server_DH_params_fail.constructor, TLRPC.TL_server_DH_params_fail.class);
|
||||
classStore.put(TLRPC.TL_server_DH_params_ok.constructor, TLRPC.TL_server_DH_params_ok.class);
|
||||
classStore.put(TLRPC.TL_userStatusEmpty.constructor, TLRPC.TL_userStatusEmpty.class);
|
||||
classStore.put(TLRPC.TL_userStatusOnline.constructor, TLRPC.TL_userStatusOnline.class);
|
||||
classStore.put(TLRPC.TL_userStatusOffline.constructor, TLRPC.TL_userStatusOffline.class);
|
||||
classStore.put(TLRPC.TL_msg_copy.constructor, TLRPC.TL_msg_copy.class);
|
||||
classStore.put(TLRPC.TL_contacts_importedContacts.constructor, TLRPC.TL_contacts_importedContacts.class);
|
||||
classStore.put(TLRPC.TL_futureSalt.constructor, TLRPC.TL_futureSalt.class);
|
||||
classStore.put(TLRPC.TL_updateEncryptedMessagesRead.constructor, TLRPC.TL_updateEncryptedMessagesRead.class);
|
||||
classStore.put(TLRPC.TL_updateContactLink.constructor, TLRPC.TL_updateContactLink.class);
|
||||
classStore.put(TLRPC.TL_updateReadMessages.constructor, TLRPC.TL_updateReadMessages.class);
|
||||
classStore.put(TLRPC.TL_updateRestoreMessages.constructor, TLRPC.TL_updateRestoreMessages.class);
|
||||
classStore.put(TLRPC.TL_updateUserTyping.constructor, TLRPC.TL_updateUserTyping.class);
|
||||
classStore.put(TLRPC.TL_updateChatUserTyping.constructor, TLRPC.TL_updateChatUserTyping.class);
|
||||
classStore.put(TLRPC.TL_updateUserName.constructor, TLRPC.TL_updateUserName.class);
|
||||
classStore.put(TLRPC.TL_updateNewEncryptedMessage.constructor, TLRPC.TL_updateNewEncryptedMessage.class);
|
||||
classStore.put(TLRPC.TL_updateNewMessage.constructor, TLRPC.TL_updateNewMessage.class);
|
||||
classStore.put(TLRPC.TL_updateMessageID.constructor, TLRPC.TL_updateMessageID.class);
|
||||
classStore.put(TLRPC.TL_updateDeleteMessages.constructor, TLRPC.TL_updateDeleteMessages.class);
|
||||
classStore.put(TLRPC.TL_updateEncryptedChatTyping.constructor, TLRPC.TL_updateEncryptedChatTyping.class);
|
||||
classStore.put(TLRPC.TL_updateChatParticipants.constructor, TLRPC.TL_updateChatParticipants.class);
|
||||
classStore.put(TLRPC.TL_updateEncryption.constructor, TLRPC.TL_updateEncryption.class);
|
||||
classStore.put(TLRPC.TL_updateActivation.constructor, TLRPC.TL_updateActivation.class);
|
||||
classStore.put(TLRPC.TL_updateNewAuthorization.constructor, TLRPC.TL_updateNewAuthorization.class);
|
||||
classStore.put(TLRPC.TL_updateNewGeoChatMessage.constructor, TLRPC.TL_updateNewGeoChatMessage.class);
|
||||
classStore.put(TLRPC.TL_updateUserPhoto.constructor, TLRPC.TL_updateUserPhoto.class);
|
||||
classStore.put(TLRPC.TL_updateContactRegistered.constructor, TLRPC.TL_updateContactRegistered.class);
|
||||
classStore.put(TLRPC.TL_updateUserStatus.constructor, TLRPC.TL_updateUserStatus.class);
|
||||
classStore.put(TLRPC.TL_rpc_error.constructor, TLRPC.TL_rpc_error.class);
|
||||
classStore.put(TLRPC.TL_rpc_req_error.constructor, TLRPC.TL_rpc_req_error.class);
|
||||
classStore.put(TLRPC.TL_inputEncryptedFile.constructor, TLRPC.TL_inputEncryptedFile.class);
|
||||
classStore.put(TLRPC.TL_inputEncryptedFileEmpty.constructor, TLRPC.TL_inputEncryptedFileEmpty.class);
|
||||
classStore.put(TLRPC.TL_inputEncryptedFileUploaded.constructor, TLRPC.TL_inputEncryptedFileUploaded.class);
|
||||
classStore.put(TLRPC.TL_decryptedMessageActionSetMessageTTL.constructor, TLRPC.TL_decryptedMessageActionSetMessageTTL.class);
|
||||
classStore.put(TLRPC.TL_contacts_myLinkRequested.constructor, TLRPC.TL_contacts_myLinkRequested.class);
|
||||
classStore.put(TLRPC.TL_contacts_myLinkContact.constructor, TLRPC.TL_contacts_myLinkContact.class);
|
||||
classStore.put(TLRPC.TL_contacts_myLinkEmpty.constructor, TLRPC.TL_contacts_myLinkEmpty.class);
|
||||
classStore.put(TLRPC.TL_server_DH_inner_data.constructor, TLRPC.TL_server_DH_inner_data.class);
|
||||
classStore.put(TLRPC.TL_new_session_created.constructor, TLRPC.TL_new_session_created.class);
|
||||
classStore.put(TLRPC.TL_userProfilePhotoEmpty.constructor, TLRPC.TL_userProfilePhotoEmpty.class);
|
||||
classStore.put(TLRPC.TL_userProfilePhoto.constructor, TLRPC.TL_userProfilePhoto.class);
|
||||
classStore.put(TLRPC.TL_photo.constructor, TLRPC.TL_photo.class);
|
||||
classStore.put(TLRPC.TL_photoEmpty.constructor, TLRPC.TL_photoEmpty.class);
|
||||
classStore.put(TLRPC.TL_encryptedChatWaiting.constructor, TLRPC.TL_encryptedChatWaiting.class);
|
||||
classStore.put(TLRPC.TL_encryptedChatEmpty.constructor, TLRPC.TL_encryptedChatEmpty.class);
|
||||
classStore.put(TLRPC.TL_encryptedChatDiscarded.constructor, TLRPC.TL_encryptedChatDiscarded.class);
|
||||
classStore.put(TLRPC.TL_encryptedChat.constructor, TLRPC.TL_encryptedChat.class);
|
||||
classStore.put(TLRPC.TL_encryptedChatRequested.constructor, TLRPC.TL_encryptedChatRequested.class);
|
||||
classStore.put(TLRPC.TL_geochats_statedMessage.constructor, TLRPC.TL_geochats_statedMessage.class);
|
||||
classStore.put(TLRPC.TL_contact.constructor, TLRPC.TL_contact.class);
|
||||
classStore.put(TLRPC.TL_config.constructor, TLRPC.TL_config.class);
|
||||
classStore.put(TLRPC.TL_messages_chats.constructor, TLRPC.TL_messages_chats.class);
|
||||
classStore.put(TLRPC.TL_chatParticipants.constructor, TLRPC.TL_chatParticipants.class);
|
||||
classStore.put(TLRPC.TL_chatParticipantsForbidden.constructor, TLRPC.TL_chatParticipantsForbidden.class);
|
||||
classStore.put(TLRPC.TL_decryptedMessageMediaContact.constructor, TLRPC.TL_decryptedMessageMediaContact.class);
|
||||
classStore.put(TLRPC.TL_decryptedMessageMediaVideo.constructor, TLRPC.TL_decryptedMessageMediaVideo.class);
|
||||
classStore.put(TLRPC.TL_decryptedMessageMediaGeoPoint.constructor, TLRPC.TL_decryptedMessageMediaGeoPoint.class);
|
||||
classStore.put(TLRPC.TL_decryptedMessageMediaFile.constructor, TLRPC.TL_decryptedMessageMediaFile.class);
|
||||
classStore.put(TLRPC.TL_decryptedMessageMediaEmpty.constructor, TLRPC.TL_decryptedMessageMediaEmpty.class);
|
||||
classStore.put(TLRPC.TL_decryptedMessageMediaPhoto.constructor, TLRPC.TL_decryptedMessageMediaPhoto.class);
|
||||
classStore.put(TLRPC.TL_chatParticipant.constructor, TLRPC.TL_chatParticipant.class);
|
||||
classStore.put(TLRPC.TL_chatForbidden.constructor, TLRPC.TL_chatForbidden.class);
|
||||
classStore.put(TLRPC.TL_geoChat.constructor, TLRPC.TL_geoChat.class);
|
||||
classStore.put(TLRPC.TL_chatEmpty.constructor, TLRPC.TL_chatEmpty.class);
|
||||
classStore.put(TLRPC.TL_chat.constructor, TLRPC.TL_chat.class);
|
||||
classStore.put(TLRPC.TL_storage_fileUnknown.constructor, TLRPC.TL_storage_fileUnknown.class);
|
||||
classStore.put(TLRPC.TL_storage_fileWebp.constructor, TLRPC.TL_storage_fileWebp.class);
|
||||
classStore.put(TLRPC.TL_storage_filePng.constructor, TLRPC.TL_storage_filePng.class);
|
||||
classStore.put(TLRPC.TL_storage_fileGif.constructor, TLRPC.TL_storage_fileGif.class);
|
||||
classStore.put(TLRPC.TL_storage_fileMov.constructor, TLRPC.TL_storage_fileMov.class);
|
||||
classStore.put(TLRPC.TL_storage_fileMp3.constructor, TLRPC.TL_storage_fileMp3.class);
|
||||
classStore.put(TLRPC.TL_storage_fileJpeg.constructor, TLRPC.TL_storage_fileJpeg.class);
|
||||
classStore.put(TLRPC.TL_storage_filePartial.constructor, TLRPC.TL_storage_filePartial.class);
|
||||
classStore.put(TLRPC.TL_storage_fileMp4.constructor, TLRPC.TL_storage_fileMp4.class);
|
||||
classStore.put(TLRPC.TL_inputMessagesFilterVideo.constructor, TLRPC.TL_inputMessagesFilterVideo.class);
|
||||
classStore.put(TLRPC.TL_inputMessagesFilterEmpty.constructor, TLRPC.TL_inputMessagesFilterEmpty.class);
|
||||
classStore.put(TLRPC.TL_inputMessagesFilterPhotos.constructor, TLRPC.TL_inputMessagesFilterPhotos.class);
|
||||
classStore.put(TLRPC.TL_inputMessagesFilterPhotoVideo.constructor, TLRPC.TL_inputMessagesFilterPhotoVideo.class);
|
||||
classStore.put(TLRPC.TL_geochats_located.constructor, TLRPC.TL_geochats_located.class);
|
||||
classStore.put(TLRPC.TL_msgs_state_info.constructor, TLRPC.TL_msgs_state_info.class);
|
||||
classStore.put(TLRPC.TL_upload_file.constructor, TLRPC.TL_upload_file.class);
|
||||
classStore.put(TLRPC.TL_dialog.constructor, TLRPC.TL_dialog.class);
|
||||
classStore.put(TLRPC.TL_messages_messageEmpty.constructor, TLRPC.TL_messages_messageEmpty.class);
|
||||
classStore.put(TLRPC.TL_messages_message.constructor, TLRPC.TL_messages_message.class);
|
||||
classStore.put(TLRPC.TL_fileLocation.constructor, TLRPC.TL_fileLocation.class);
|
||||
classStore.put(TLRPC.TL_fileLocationUnavailable.constructor, TLRPC.TL_fileLocationUnavailable.class);
|
||||
classStore.put(TLRPC.TL_inputGeoChat.constructor, TLRPC.TL_inputGeoChat.class);
|
||||
classStore.put(TLRPC.TL_protoMessage.constructor, TLRPC.TL_protoMessage.class);
|
||||
classStore.put(TLRPC.TL_photoSize.constructor, TLRPC.TL_photoSize.class);
|
||||
classStore.put(TLRPC.TL_photoSizeEmpty.constructor, TLRPC.TL_photoSizeEmpty.class);
|
||||
classStore.put(TLRPC.TL_photoCachedSize.constructor, TLRPC.TL_photoCachedSize.class);
|
||||
classStore.put(TLRPC.TL_inputFile.constructor, TLRPC.TL_inputFile.class);
|
||||
classStore.put(TLRPC.TL_messages_statedMessageLink.constructor, TLRPC.TL_messages_statedMessageLink.class);
|
||||
classStore.put(TLRPC.TL_messages_statedMessage.constructor, TLRPC.TL_messages_statedMessage.class);
|
||||
classStore.put(TLRPC.TL_userFull.constructor, TLRPC.TL_userFull.class);
|
||||
classStore.put(TLRPC.TL_msg_new_detailed_info.constructor, TLRPC.TL_msg_new_detailed_info.class);
|
||||
classStore.put(TLRPC.TL_msg_detailed_info.constructor, TLRPC.TL_msg_detailed_info.class);
|
||||
classStore.put(TLRPC.TL_resPQ.constructor, TLRPC.TL_resPQ.class);
|
||||
classStore.put(TLRPC.TL_updateShortChatMessage.constructor, TLRPC.TL_updateShortChatMessage.class);
|
||||
classStore.put(TLRPC.TL_updates.constructor, TLRPC.TL_updates.class);
|
||||
classStore.put(TLRPC.TL_updateShortMessage.constructor, TLRPC.TL_updateShortMessage.class);
|
||||
classStore.put(TLRPC.TL_updateShort.constructor, TLRPC.TL_updateShort.class);
|
||||
classStore.put(TLRPC.TL_updatesCombined.constructor, TLRPC.TL_updatesCombined.class);
|
||||
classStore.put(TLRPC.TL_updatesTooLong.constructor, TLRPC.TL_updatesTooLong.class);
|
||||
classStore.put(TLRPC.TL_messages_chat.constructor, TLRPC.TL_messages_chat.class);
|
||||
classStore.put(TLRPC.TL_wallPaper.constructor, TLRPC.TL_wallPaper.class);
|
||||
classStore.put(TLRPC.TL_wallPaperSolid.constructor, TLRPC.TL_wallPaperSolid.class);
|
||||
classStore.put(TLRPC.TL_updates_state.constructor, TLRPC.TL_updates_state.class);
|
||||
classStore.put(TLRPC.TL_inputEncryptedChat.constructor, TLRPC.TL_inputEncryptedChat.class);
|
||||
classStore.put(TLRPC.TL_inputChatPhoto.constructor, TLRPC.TL_inputChatPhoto.class);
|
||||
classStore.put(TLRPC.TL_inputChatPhotoEmpty.constructor, TLRPC.TL_inputChatPhotoEmpty.class);
|
||||
classStore.put(TLRPC.TL_inputChatUploadedPhoto.constructor, TLRPC.TL_inputChatUploadedPhoto.class);
|
||||
classStore.put(TLRPC.TL_inputVideoEmpty.constructor, TLRPC.TL_inputVideoEmpty.class);
|
||||
classStore.put(TLRPC.TL_inputVideo.constructor, TLRPC.TL_inputVideo.class);
|
||||
classStore.put(TLRPC.TL_nearestDc.constructor, TLRPC.TL_nearestDc.class);
|
||||
classStore.put(TLRPC.TL_inputPhotoEmpty.constructor, TLRPC.TL_inputPhotoEmpty.class);
|
||||
classStore.put(TLRPC.TL_inputPhoto.constructor, TLRPC.TL_inputPhoto.class);
|
||||
classStore.put(TLRPC.TL_importedContact.constructor, TLRPC.TL_importedContact.class);
|
||||
classStore.put(TLRPC.TL_inputPeerContact.constructor, TLRPC.TL_inputPeerContact.class);
|
||||
classStore.put(TLRPC.TL_inputPeerChat.constructor, TLRPC.TL_inputPeerChat.class);
|
||||
classStore.put(TLRPC.TL_inputPeerEmpty.constructor, TLRPC.TL_inputPeerEmpty.class);
|
||||
classStore.put(TLRPC.TL_inputPeerSelf.constructor, TLRPC.TL_inputPeerSelf.class);
|
||||
classStore.put(TLRPC.TL_inputPeerForeign.constructor, TLRPC.TL_inputPeerForeign.class);
|
||||
classStore.put(TLRPC.TL_dcOption.constructor, TLRPC.TL_dcOption.class);
|
||||
classStore.put(TLRPC.TL_inputPhotoCropAuto.constructor, TLRPC.TL_inputPhotoCropAuto.class);
|
||||
classStore.put(TLRPC.TL_inputPhotoCrop.constructor, TLRPC.TL_inputPhotoCrop.class);
|
||||
classStore.put(TLRPC.TL_messages_dialogs.constructor, TLRPC.TL_messages_dialogs.class);
|
||||
classStore.put(TLRPC.TL_messages_dialogsSlice.constructor, TLRPC.TL_messages_dialogsSlice.class);
|
||||
classStore.put(TLRPC.TL_req_pq.constructor, TLRPC.TL_req_pq.class);
|
||||
classStore.put(TLRPC.TL_req_DH_params.constructor, TLRPC.TL_req_DH_params.class);
|
||||
classStore.put(TLRPC.TL_set_client_DH_params.constructor, TLRPC.TL_set_client_DH_params.class);
|
||||
classStore.put(TLRPC.TL_ping.constructor, TLRPC.TL_ping.class);
|
||||
classStore.put(TLRPC.TL_destroy_session.constructor, TLRPC.TL_destroy_session.class);
|
||||
classStore.put(TLRPC.TL_destroy_sessions.constructor, TLRPC.TL_destroy_sessions.class);
|
||||
classStore.put(TLRPC.TL_get_future_salts.constructor, TLRPC.TL_get_future_salts.class);
|
||||
classStore.put(TLRPC.TL_rpc_drop_answer.constructor, TLRPC.TL_rpc_drop_answer.class);
|
||||
classStore.put(TLRPC.TL_auth_checkPhone.constructor, TLRPC.TL_auth_checkPhone.class);
|
||||
classStore.put(TLRPC.TL_auth_sendCode.constructor, TLRPC.TL_auth_sendCode.class);
|
||||
classStore.put(TLRPC.TL_auth_sendCall.constructor, TLRPC.TL_auth_sendCall.class);
|
||||
classStore.put(TLRPC.TL_auth_signUp.constructor, TLRPC.TL_auth_signUp.class);
|
||||
classStore.put(TLRPC.TL_auth_signIn.constructor, TLRPC.TL_auth_signIn.class);
|
||||
classStore.put(TLRPC.TL_auth_logOut.constructor, TLRPC.TL_auth_logOut.class);
|
||||
classStore.put(TLRPC.TL_auth_sendInvites.constructor, TLRPC.TL_auth_sendInvites.class);
|
||||
classStore.put(TLRPC.TL_auth_exportAuthorization.constructor, TLRPC.TL_auth_exportAuthorization.class);
|
||||
classStore.put(TLRPC.TL_auth_importAuthorization.constructor, TLRPC.TL_auth_importAuthorization.class);
|
||||
classStore.put(TLRPC.TL_account_registerDevice.constructor, TLRPC.TL_account_registerDevice.class);
|
||||
classStore.put(TLRPC.TL_account_unregisterDevice.constructor, TLRPC.TL_account_unregisterDevice.class);
|
||||
classStore.put(TLRPC.TL_account_updateNotifySettings.constructor, TLRPC.TL_account_updateNotifySettings.class);
|
||||
classStore.put(TLRPC.TL_account_getNotifySettings.constructor, TLRPC.TL_account_getNotifySettings.class);
|
||||
classStore.put(TLRPC.TL_account_resetNotifySettings.constructor, TLRPC.TL_account_resetNotifySettings.class);
|
||||
classStore.put(TLRPC.TL_account_updateProfile.constructor, TLRPC.TL_account_updateProfile.class);
|
||||
classStore.put(TLRPC.TL_account_updateStatus.constructor, TLRPC.TL_account_updateStatus.class);
|
||||
classStore.put(TLRPC.TL_account_getWallPapers.constructor, TLRPC.TL_account_getWallPapers.class);
|
||||
classStore.put(TLRPC.TL_users_getUsers.constructor, TLRPC.TL_users_getUsers.class);
|
||||
classStore.put(TLRPC.TL_users_getFullUser.constructor, TLRPC.TL_users_getFullUser.class);
|
||||
classStore.put(TLRPC.TL_contacts_getStatuses.constructor, TLRPC.TL_contacts_getStatuses.class);
|
||||
classStore.put(TLRPC.TL_contacts_getContacts.constructor, TLRPC.TL_contacts_getContacts.class);
|
||||
classStore.put(TLRPC.TL_contacts_importContacts.constructor, TLRPC.TL_contacts_importContacts.class);
|
||||
classStore.put(TLRPC.TL_contacts_deleteContact.constructor, TLRPC.TL_contacts_deleteContact.class);
|
||||
classStore.put(TLRPC.TL_contacts_deleteContacts.constructor, TLRPC.TL_contacts_deleteContacts.class);
|
||||
classStore.put(TLRPC.TL_contacts_block.constructor, TLRPC.TL_contacts_block.class);
|
||||
classStore.put(TLRPC.TL_contacts_unblock.constructor, TLRPC.TL_contacts_unblock.class);
|
||||
classStore.put(TLRPC.TL_contacts_getBlocked.constructor, TLRPC.TL_contacts_getBlocked.class);
|
||||
classStore.put(TLRPC.TL_messages_getMessages.constructor, TLRPC.TL_messages_getMessages.class);
|
||||
classStore.put(TLRPC.TL_messages_getDialogs.constructor, TLRPC.TL_messages_getDialogs.class);
|
||||
classStore.put(TLRPC.TL_messages_getHistory.constructor, TLRPC.TL_messages_getHistory.class);
|
||||
classStore.put(TLRPC.TL_messages_search.constructor, TLRPC.TL_messages_search.class);
|
||||
classStore.put(TLRPC.TL_messages_readHistory.constructor, TLRPC.TL_messages_readHistory.class);
|
||||
classStore.put(TLRPC.TL_messages_deleteHistory.constructor, TLRPC.TL_messages_deleteHistory.class);
|
||||
classStore.put(TLRPC.TL_messages_deleteMessages.constructor, TLRPC.TL_messages_deleteMessages.class);
|
||||
classStore.put(TLRPC.TL_messages_restoreMessages.constructor, TLRPC.TL_messages_restoreMessages.class);
|
||||
classStore.put(TLRPC.TL_messages_receivedMessages.constructor, TLRPC.TL_messages_receivedMessages.class);
|
||||
classStore.put(TLRPC.TL_messages_setTyping.constructor, TLRPC.TL_messages_setTyping.class);
|
||||
classStore.put(TLRPC.TL_messages_sendMessage.constructor, TLRPC.TL_messages_sendMessage.class);
|
||||
classStore.put(TLRPC.TL_messages_sendMedia.constructor, TLRPC.TL_messages_sendMedia.class);
|
||||
classStore.put(TLRPC.TL_messages_forwardMessages.constructor, TLRPC.TL_messages_forwardMessages.class);
|
||||
classStore.put(TLRPC.TL_messages_getChats.constructor, TLRPC.TL_messages_getChats.class);
|
||||
classStore.put(TLRPC.TL_messages_getFullChat.constructor, TLRPC.TL_messages_getFullChat.class);
|
||||
classStore.put(TLRPC.TL_messages_editChatTitle.constructor, TLRPC.TL_messages_editChatTitle.class);
|
||||
classStore.put(TLRPC.TL_messages_editChatPhoto.constructor, TLRPC.TL_messages_editChatPhoto.class);
|
||||
classStore.put(TLRPC.TL_messages_addChatUser.constructor, TLRPC.TL_messages_addChatUser.class);
|
||||
classStore.put(TLRPC.TL_messages_deleteChatUser.constructor, TLRPC.TL_messages_deleteChatUser.class);
|
||||
classStore.put(TLRPC.TL_messages_createChat.constructor, TLRPC.TL_messages_createChat.class);
|
||||
classStore.put(TLRPC.TL_updates_getState.constructor, TLRPC.TL_updates_getState.class);
|
||||
classStore.put(TLRPC.TL_photos_updateProfilePhoto.constructor, TLRPC.TL_photos_updateProfilePhoto.class);
|
||||
classStore.put(TLRPC.TL_photos_uploadProfilePhoto.constructor, TLRPC.TL_photos_uploadProfilePhoto.class);
|
||||
classStore.put(TLRPC.TL_upload_saveFilePart.constructor, TLRPC.TL_upload_saveFilePart.class);
|
||||
classStore.put(TLRPC.TL_upload_getFile.constructor, TLRPC.TL_upload_getFile.class);
|
||||
classStore.put(TLRPC.TL_help_getConfig.constructor, TLRPC.TL_help_getConfig.class);
|
||||
classStore.put(TLRPC.TL_help_getNearestDc.constructor, TLRPC.TL_help_getNearestDc.class);
|
||||
classStore.put(TLRPC.TL_help_saveAppLog.constructor, TLRPC.TL_help_saveAppLog.class);
|
||||
classStore.put(TLRPC.TL_help_getInviteText.constructor, TLRPC.TL_help_getInviteText.class);
|
||||
classStore.put(TLRPC.TL_photos_getUserPhotos.constructor, TLRPC.TL_photos_getUserPhotos.class);
|
||||
classStore.put(TLRPC.TL_messages_forwardMessage.constructor, TLRPC.TL_messages_forwardMessage.class);
|
||||
classStore.put(TLRPC.TL_messages_sendBroadcast.constructor, TLRPC.TL_messages_sendBroadcast.class);
|
||||
classStore.put(TLRPC.TL_geochats_getLocated.constructor, TLRPC.TL_geochats_getLocated.class);
|
||||
classStore.put(TLRPC.TL_geochats_getRecents.constructor, TLRPC.TL_geochats_getRecents.class);
|
||||
classStore.put(TLRPC.TL_geochats_checkin.constructor, TLRPC.TL_geochats_checkin.class);
|
||||
classStore.put(TLRPC.TL_geochats_getFullChat.constructor, TLRPC.TL_geochats_getFullChat.class);
|
||||
classStore.put(TLRPC.TL_geochats_editChatTitle.constructor, TLRPC.TL_geochats_editChatTitle.class);
|
||||
classStore.put(TLRPC.TL_geochats_editChatPhoto.constructor, TLRPC.TL_geochats_editChatPhoto.class);
|
||||
classStore.put(TLRPC.TL_geochats_search.constructor, TLRPC.TL_geochats_search.class);
|
||||
classStore.put(TLRPC.TL_geochats_getHistory.constructor, TLRPC.TL_geochats_getHistory.class);
|
||||
classStore.put(TLRPC.TL_geochats_setTyping.constructor, TLRPC.TL_geochats_setTyping.class);
|
||||
classStore.put(TLRPC.TL_geochats_sendMessage.constructor, TLRPC.TL_geochats_sendMessage.class);
|
||||
classStore.put(TLRPC.TL_geochats_sendMedia.constructor, TLRPC.TL_geochats_sendMedia.class);
|
||||
classStore.put(TLRPC.TL_geochats_createGeoChat.constructor, TLRPC.TL_geochats_createGeoChat.class);
|
||||
classStore.put(TLRPC.TL_updates_getDifference.constructor, TLRPC.TL_updates_getDifference.class);
|
||||
classStore.put(TLRPC.TL_messages_getDhConfig.constructor, TLRPC.TL_messages_getDhConfig.class);
|
||||
classStore.put(TLRPC.TL_messages_requestEncryption.constructor, TLRPC.TL_messages_requestEncryption.class);
|
||||
classStore.put(TLRPC.TL_messages_acceptEncryption.constructor, TLRPC.TL_messages_acceptEncryption.class);
|
||||
classStore.put(TLRPC.TL_messages_discardEncryption.constructor, TLRPC.TL_messages_discardEncryption.class);
|
||||
classStore.put(TLRPC.TL_messages_setEncryptedTyping.constructor, TLRPC.TL_messages_setEncryptedTyping.class);
|
||||
classStore.put(TLRPC.TL_messages_readEncryptedHistory.constructor, TLRPC.TL_messages_readEncryptedHistory.class);
|
||||
classStore.put(TLRPC.TL_messages_sendEncrypted.constructor, TLRPC.TL_messages_sendEncrypted.class);
|
||||
classStore.put(TLRPC.TL_messages_sendEncryptedFile.constructor, TLRPC.TL_messages_sendEncryptedFile.class);
|
||||
classStore.put(TLRPC.TL_messages_sendEncryptedService.constructor, TLRPC.TL_messages_sendEncryptedService.class);
|
||||
classStore.put(TLRPC.TL_messages_receivedQueue.constructor, TLRPC.TL_messages_receivedQueue.class);
|
||||
|
||||
classStore.put(TLRPC.TL_msg_container.constructor, TLRPC.TL_msg_container.class);
|
||||
classStore.put(TLRPC.TL_fileEncryptedLocation.constructor, TLRPC.TL_fileEncryptedLocation.class);
|
||||
classStore.put(TLRPC.TL_messageActionTTLChange.constructor, TLRPC.TL_messageActionTTLChange.class);
|
||||
classStore.put(TLRPC.TL_videoEncrypted.constructor, TLRPC.TL_videoEncrypted.class);
|
||||
classStore.put(TLRPC.TL_gzip_packed.constructor, TLRPC.TL_gzip_packed.class);
|
||||
classStore.put(TLRPC.Vector.constructor, TLRPC.Vector.class);
|
||||
classStore.put(TLRPC.TL_userProfilePhotoOld.constructor, TLRPC.TL_userProfilePhotoOld.class);
|
||||
}
|
||||
|
||||
static TLClassStore store = null;
|
||||
|
||||
public static TLClassStore Instance() {
|
||||
if (store == null) {
|
||||
store = new TLClassStore();
|
||||
}
|
||||
return store;
|
||||
}
|
||||
|
||||
public TLObject TLdeserialize(SerializedData stream, int constructor) {
|
||||
try {
|
||||
return TLdeserialize(stream, constructor, null);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public TLObject TLdeserialize(SerializedData stream, int constructor, TLObject request) {
|
||||
Class objClass = classStore.get(constructor);
|
||||
if (objClass != null) {
|
||||
try {
|
||||
TLObject response = (TLObject)objClass.newInstance();
|
||||
if (response instanceof TLRPC.Vector) {
|
||||
if (request != null) {
|
||||
request.parseVector((TLRPC.Vector)response, stream);
|
||||
} else {
|
||||
int size = stream.readInt32();
|
||||
for (int a = 0; a < size; a++) {
|
||||
((TLRPC.Vector)response).objects.add(stream.readInt32());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
response.readParams(stream);
|
||||
}
|
||||
return response;
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.e("tmessages", "can't create class");
|
||||
return null;
|
||||
} catch (InstantiationException e2) {
|
||||
Log.e("tmessages", "can't create class");
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
if (ConnectionsManager.DEBUG_VERSION) {
|
||||
Log.e("tmessages", String.format("unknown class %x", constructor));
|
||||
}
|
||||
return null;
|
||||
//throw new RuntimeException(String.format("unknown class %x", constructor));
|
||||
}
|
||||
}
|
||||
}
|
41
TMessagesProj/src/main/java/org/telegram/TL/TLObject.java
Normal file
41
TMessagesProj/src/main/java/org/telegram/TL/TLObject.java
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.TL;
|
||||
|
||||
import org.telegram.messenger.SerializedData;
|
||||
|
||||
public class TLObject {
|
||||
public TLObject () {
|
||||
|
||||
}
|
||||
|
||||
public void readParams(SerializedData stream) {
|
||||
|
||||
}
|
||||
|
||||
public byte[] serialize () {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void serializeToStream(SerializedData stream) {
|
||||
|
||||
}
|
||||
|
||||
public Class<? extends TLObject> responseClass () {
|
||||
return this.getClass();
|
||||
}
|
||||
|
||||
public int layer () {
|
||||
return 8;
|
||||
}
|
||||
|
||||
public void parseVector(TLRPC.Vector vector, SerializedData data) {
|
||||
|
||||
}
|
||||
}
|
8121
TMessagesProj/src/main/java/org/telegram/TL/TLRPC.java
Normal file
8121
TMessagesProj/src/main/java/org/telegram/TL/TLRPC.java
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class Action {
|
||||
public interface ActionDelegate {
|
||||
void ActionDidFinishExecution(Action action, HashMap<String, Object> params);
|
||||
void ActionDidFailExecution(Action action);
|
||||
}
|
||||
|
||||
public ActionDelegate delegate;
|
||||
|
||||
public void execute(HashMap params) {
|
||||
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
|
||||
}
|
||||
|
||||
public int state;
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import android.accounts.AbstractAccountAuthenticator;
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountAuthenticatorResponse;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.NetworkErrorException;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
|
||||
public class AuthenticatorService extends Service {
|
||||
|
||||
private static class Authenticator extends AbstractAccountAuthenticator {
|
||||
private final Context context;
|
||||
|
||||
public Authenticator(Context context) {
|
||||
super(context);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options)
|
||||
throws NetworkErrorException {
|
||||
return null;
|
||||
/*Log.e(TAG, "addAccount");
|
||||
|
||||
// check if an account already exists; we only allow one
|
||||
QuillAccount account = new QuillAccount(context);
|
||||
if (account.exists())
|
||||
return null;
|
||||
|
||||
// ok, go ahead and create new account
|
||||
Intent intent = new Intent(context, LoginActivity.class);
|
||||
intent.setAction(LoginActivity.ACTION_LOGIN);
|
||||
intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
|
||||
Bundle reply = new Bundle();
|
||||
reply.putParcelable(AccountManager.KEY_INTENT, intent);
|
||||
return reply;*/
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response, Account account) throws NetworkErrorException {
|
||||
Bundle result = super.getAccountRemovalAllowed(response, account);
|
||||
|
||||
/*if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
|
||||
&& !result.containsKey(AccountManager.KEY_INTENT)) {
|
||||
final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
|
||||
|
||||
if (removalAllowed) {
|
||||
context.sendBroadcast(new Intent("com.stels.messenger.LOGOUT"));
|
||||
//((StelsApplication) mContext.getApplicationContext()).dropLogin();
|
||||
}
|
||||
}*/
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options)
|
||||
throws NetworkErrorException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthTokenLabel(String authTokenType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle hasFeatures(AccountAuthenticatorResponse response,
|
||||
Account account, String[] features)
|
||||
throws NetworkErrorException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options)
|
||||
throws NetworkErrorException {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static Authenticator authenticator = null;
|
||||
|
||||
protected Authenticator getAuthenticator() {
|
||||
if (authenticator == null) {
|
||||
authenticator = new Authenticator(this);
|
||||
}
|
||||
return authenticator;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
if (intent.getAction().equals(AccountManager.ACTION_AUTHENTICATOR_INTENT)) {
|
||||
return getAuthenticator().getIBinder();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.OperationCanceledException;
|
||||
import android.app.Service;
|
||||
import android.content.AbstractThreadedSyncAdapter;
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SyncResult;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
|
||||
public class ContactsSyncAdapterService extends Service {
|
||||
private static SyncAdapterImpl sSyncAdapter = null;
|
||||
|
||||
public ContactsSyncAdapterService() {
|
||||
super();
|
||||
}
|
||||
|
||||
private static class SyncAdapterImpl extends AbstractThreadedSyncAdapter {
|
||||
private Context mContext;
|
||||
|
||||
public SyncAdapterImpl(Context context) {
|
||||
super(context, true);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
|
||||
try {
|
||||
ContactsSyncAdapterService.performSync(mContext, account, extras, authority, provider, syncResult);
|
||||
} catch (OperationCanceledException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return getSyncAdapter().getSyncAdapterBinder();
|
||||
}
|
||||
|
||||
private SyncAdapterImpl getSyncAdapter() {
|
||||
if (sSyncAdapter == null) {
|
||||
sSyncAdapter = new SyncAdapterImpl(this);
|
||||
}
|
||||
return sSyncAdapter;
|
||||
}
|
||||
|
||||
private static void performSync(Context context, Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult)
|
||||
throws OperationCanceledException {
|
||||
Log.i("telegram", "performSync: " + account.toString());
|
||||
}
|
||||
}
|
@ -0,0 +1,193 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.telegram.TL.TLRPC;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
||||
public class Datacenter {
|
||||
public int datacenterId;
|
||||
public String address;
|
||||
public int port;
|
||||
public boolean authorized;
|
||||
public long authSessionId;
|
||||
public long authDownloadSessionId;
|
||||
public long authUploadSessionId;
|
||||
public byte[] authKey;
|
||||
public byte[] authKeyId;
|
||||
|
||||
public TcpConnection connection;
|
||||
public TcpConnection downloadConnection;
|
||||
public TcpConnection uploadConnection;
|
||||
|
||||
private ArrayList<ServerSalt> authServerSaltSet = new ArrayList<ServerSalt>();
|
||||
|
||||
public Datacenter() {
|
||||
authServerSaltSet = new ArrayList<ServerSalt>();
|
||||
}
|
||||
|
||||
public Datacenter(SerializedData data) {
|
||||
datacenterId = data.readInt32();
|
||||
address = data.readString();
|
||||
port = data.readInt32();
|
||||
if (port == 25) {
|
||||
port = 443;
|
||||
}
|
||||
int len = data.readInt32();
|
||||
if (len != 0) {
|
||||
authKey = data.readData(len);
|
||||
}
|
||||
len = data.readInt32();
|
||||
if (len != 0) {
|
||||
authKeyId = data.readData(len);
|
||||
}
|
||||
authorized = data.readInt32() != 0;
|
||||
len = data.readInt32();
|
||||
for (int a = 0; a < len; a++) {
|
||||
ServerSalt salt = new ServerSalt();
|
||||
salt.validSince = data.readInt32();
|
||||
salt.validUntil = data.readInt32();
|
||||
salt.value = data.readInt64();
|
||||
if (authServerSaltSet == null) {
|
||||
authServerSaltSet = new ArrayList<ServerSalt>();
|
||||
}
|
||||
authServerSaltSet.add(salt);
|
||||
}
|
||||
}
|
||||
|
||||
public void SerializeToStream(SerializedData stream) {
|
||||
stream.writeInt32(datacenterId);
|
||||
stream.writeString(address);
|
||||
stream.writeInt32(port);
|
||||
if (authKey != null) {
|
||||
stream.writeInt32(authKey.length);
|
||||
stream.writeRaw(authKey);
|
||||
} else {
|
||||
stream.writeInt32(0);
|
||||
}
|
||||
if (authKeyId != null) {
|
||||
stream.writeInt32(authKeyId.length);
|
||||
stream.writeRaw(authKeyId);
|
||||
} else {
|
||||
stream.writeInt32(0);
|
||||
}
|
||||
stream.writeInt32(authorized ? 1 : 0);
|
||||
stream.writeInt32(authServerSaltSet.size());
|
||||
for (ServerSalt salt : authServerSaltSet) {
|
||||
stream.writeInt32(salt.validSince);
|
||||
stream.writeInt32(salt.validUntil);
|
||||
stream.writeInt64(salt.value);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
authKey = null;
|
||||
authKeyId = null;
|
||||
authorized = false;
|
||||
authServerSaltSet.clear();
|
||||
}
|
||||
|
||||
public void clearServerSalts() {
|
||||
authServerSaltSet.clear();
|
||||
}
|
||||
|
||||
public long selectServerSalt(int date) {
|
||||
boolean cleanupNeeded = false;
|
||||
|
||||
long result = 0;
|
||||
int maxRemainingInterval = 0;
|
||||
|
||||
for (ServerSalt salt : authServerSaltSet) {
|
||||
if (salt.validUntil < date || (salt.validSince == 0 && salt.validUntil == Integer.MAX_VALUE)) {
|
||||
cleanupNeeded = true;
|
||||
} else if (salt.validSince <= date && salt.validUntil > date) {
|
||||
if (maxRemainingInterval == 0 || Math.abs(salt.validUntil - date) > maxRemainingInterval) {
|
||||
maxRemainingInterval = Math.abs(salt.validUntil - date);
|
||||
result = salt.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cleanupNeeded) {
|
||||
for (int i = 0; i < authServerSaltSet.size(); i++) {
|
||||
ServerSalt salt = authServerSaltSet.get(i);
|
||||
if (salt.validUntil < date) {
|
||||
authServerSaltSet.remove(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ConnectionsManager.DEBUG_VERSION) {
|
||||
if (result == 0) {
|
||||
Log.e("tmessages", "Valid salt not found", null);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private class SaltComparator implements Comparator<ServerSalt> {
|
||||
@Override
|
||||
public int compare(ServerSalt o1, ServerSalt o2) {
|
||||
if (o1.validSince < o2.validSince) {
|
||||
return -1;
|
||||
} else if (o1.validSince > o2.validSince) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void mergeServerSalts(int date, ArrayList<TLRPC.TL_futureSalt> salts) {
|
||||
if (salts == null) {
|
||||
return;
|
||||
}
|
||||
ArrayList<Long> existingSalts = new ArrayList<Long>(authServerSaltSet.size());
|
||||
|
||||
for (ServerSalt salt : authServerSaltSet) {
|
||||
existingSalts.add(salt.value);
|
||||
}
|
||||
for (TLRPC.TL_futureSalt saltDesc : salts) {
|
||||
long salt = saltDesc.salt;
|
||||
if (!existingSalts.contains(salt) && saltDesc.valid_until > date) {
|
||||
ServerSalt serverSalt = new ServerSalt();
|
||||
serverSalt.validSince = saltDesc.valid_since;
|
||||
serverSalt.validUntil = saltDesc.valid_until;
|
||||
serverSalt.value = salt;
|
||||
authServerSaltSet.add(serverSalt);
|
||||
}
|
||||
}
|
||||
Collections.sort(authServerSaltSet, new SaltComparator());
|
||||
}
|
||||
|
||||
public void addServerSalt(ServerSalt serverSalt) {
|
||||
for (ServerSalt salt : authServerSaltSet) {
|
||||
if (salt.value == serverSalt.value) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
authServerSaltSet.add(serverSalt);
|
||||
Collections.sort(authServerSaltSet, new SaltComparator());
|
||||
}
|
||||
|
||||
boolean containsServerSalt(long value) {
|
||||
for (ServerSalt salt : authServerSaltSet) {
|
||||
if (salt.value == value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
|
||||
public class DispatchQueue extends Thread {
|
||||
public Handler handler;
|
||||
private final Object handlerSyncObject = new Object();
|
||||
|
||||
public DispatchQueue(final String threadName) {
|
||||
setName(threadName);
|
||||
start();
|
||||
}
|
||||
|
||||
private void sendMessage(Message msg, int delay) {
|
||||
if (handler == null) {
|
||||
try {
|
||||
synchronized (handlerSyncObject) {
|
||||
handlerSyncObject.wait();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (handler != null) {
|
||||
if (delay <= 0) {
|
||||
handler.sendMessage(msg);
|
||||
} else {
|
||||
handler.sendMessageDelayed(msg, delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void postRunnable(Runnable runnable) {
|
||||
postRunnable(runnable, 0);
|
||||
}
|
||||
|
||||
public void postRunnable(Runnable runnable, int delay) {
|
||||
if (handler == null) {
|
||||
try {
|
||||
synchronized (handlerSyncObject) {
|
||||
handlerSyncObject.wait();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (handler != null) {
|
||||
if (delay <= 0) {
|
||||
handler.post(runnable);
|
||||
} else {
|
||||
handler.postDelayed(runnable, delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
Looper.prepare();
|
||||
handler = new Handler();
|
||||
synchronized (handlerSyncObject) {
|
||||
handlerSyncObject.notify();
|
||||
}
|
||||
Looper.loop();
|
||||
}
|
||||
}
|
620
TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java
Normal file
620
TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java
Normal file
@ -0,0 +1,620 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.Spannable;
|
||||
import android.text.Spanned;
|
||||
import android.text.style.DynamicDrawableSpan;
|
||||
import android.text.style.ImageSpan;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class Emoji {
|
||||
private static final int[] ROW_SIZES = {27, 29, 33, 34, 34};
|
||||
private static HashMap<Long, DrawableInfo> rects = new HashMap<Long, DrawableInfo>();
|
||||
private static int imgSize, drawImgSize, bigImgSize;
|
||||
private static boolean inited = false;
|
||||
private static Paint placeholderPaint;
|
||||
private static Bitmap[] bmps = new Bitmap[5];
|
||||
private static boolean[] loading = new boolean[5];
|
||||
|
||||
private static final char[] emojiChars={
|
||||
0x00A9,
|
||||
0x00AE,
|
||||
0x203C,
|
||||
0x2049,
|
||||
0x2122,
|
||||
0x2139,
|
||||
0x2194,
|
||||
0x2195,
|
||||
0x2196,
|
||||
0x2197,
|
||||
0x2198,
|
||||
0x2199,
|
||||
0x21A9,
|
||||
0x21AA,
|
||||
0x231A,
|
||||
0x231B,
|
||||
0x23E9,
|
||||
0x23EA,
|
||||
0x23EB,
|
||||
0x23EC,
|
||||
0x23F0,
|
||||
0x23F3,
|
||||
0x24C2,
|
||||
0x25AA,
|
||||
0x25AB,
|
||||
0x25B6,
|
||||
0x25C0,
|
||||
0x25FB,
|
||||
0x25FC,
|
||||
0x25FD,
|
||||
0x25FE,
|
||||
0x2600,
|
||||
0x2601,
|
||||
0x260E,
|
||||
0x2611,
|
||||
0x2614,
|
||||
0x2615,
|
||||
0x261D,
|
||||
0x263A,
|
||||
0x2648,
|
||||
0x2649,
|
||||
0x264A,
|
||||
0x264B,
|
||||
0x264C,
|
||||
0x264D,
|
||||
0x264E,
|
||||
0x264F,
|
||||
0x2650,
|
||||
0x2651,
|
||||
0x2652,
|
||||
0x2653,
|
||||
0x2660,
|
||||
0x2663,
|
||||
0x2665,
|
||||
0x2666,
|
||||
0x2668,
|
||||
0x267B,
|
||||
0x267F,
|
||||
0x2693,
|
||||
0x26A0,
|
||||
0x26A1,
|
||||
0x26AA,
|
||||
0x26AB,
|
||||
0x26BD,
|
||||
0x26BE,
|
||||
0x26C4,
|
||||
0x26C5,
|
||||
0x26CE,
|
||||
0x26D4,
|
||||
0x26EA,
|
||||
0x26F2,
|
||||
0x26F3,
|
||||
0x26F5,
|
||||
0x26FA,
|
||||
0x26FD,
|
||||
0x2702,
|
||||
0x2705,
|
||||
0x2708,
|
||||
0x2709,
|
||||
0x270A,
|
||||
0x270B,
|
||||
0x270C,
|
||||
0x270F,
|
||||
0x2712,
|
||||
0x2714,
|
||||
0x2716,
|
||||
0x2728,
|
||||
0x2733,
|
||||
0x2734,
|
||||
0x2744,
|
||||
0x2747,
|
||||
0x274C,
|
||||
0x274E,
|
||||
0x2753,
|
||||
0x2754,
|
||||
0x2755,
|
||||
0x2757,
|
||||
0x2764,
|
||||
0x2795,
|
||||
0x2796,
|
||||
0x2797,
|
||||
0x27A1,
|
||||
0x27B0,
|
||||
0x27BF,
|
||||
0x2934,
|
||||
0x2935,
|
||||
0x2B05,
|
||||
0x2B06,
|
||||
0x2B07,
|
||||
0x2B1B,
|
||||
0x2B1C,
|
||||
0x2B50,
|
||||
0x2B55,
|
||||
0x3030,
|
||||
0x303D,
|
||||
0x3297,
|
||||
0x3299
|
||||
};
|
||||
|
||||
public static long[][] data = {
|
||||
new long[]
|
||||
{},
|
||||
new long[]
|
||||
{0x00000000D83DDE04L, 0x00000000D83DDE03L, 0x00000000D83DDE00L, 0x00000000D83DDE0AL, 0x000000000000263AL, 0x00000000D83DDE09L, 0x00000000D83DDE0DL,
|
||||
0x00000000D83DDE18L, 0x00000000D83DDE1AL, 0x00000000D83DDE17L, 0x00000000D83DDE19L, 0x00000000D83DDE1CL, 0x00000000D83DDE1DL, 0x00000000D83DDE1BL,
|
||||
0x00000000D83DDE33L, 0x00000000D83DDE01L, 0x00000000D83DDE14L, 0x00000000D83DDE0CL, 0x00000000D83DDE12L, 0x00000000D83DDE1EL, 0x00000000D83DDE23L,
|
||||
0x00000000D83DDE22L, 0x00000000D83DDE02L, 0x00000000D83DDE2DL, 0x00000000D83DDE2AL, 0x00000000D83DDE25L, 0x00000000D83DDE30L, 0x00000000D83DDE05L,
|
||||
0x00000000D83DDE13L, 0x00000000D83DDE29L, 0x00000000D83DDE2BL, 0x00000000D83DDE28L, 0x00000000D83DDE31L, 0x00000000D83DDE20L, 0x00000000D83DDE21L,
|
||||
0x00000000D83DDE24L, 0x00000000D83DDE16L, 0x00000000D83DDE06L, 0x00000000D83DDE0BL, 0x00000000D83DDE37L, 0x00000000D83DDE0EL, 0x00000000D83DDE34L,
|
||||
0x00000000D83DDE35L, 0x00000000D83DDE32L, 0x00000000D83DDE1FL, 0x00000000D83DDE26L, 0x00000000D83DDE27L, 0x00000000D83DDE08L, 0x00000000D83DDC7FL,
|
||||
0x00000000D83DDE2EL, 0x00000000D83DDE2CL, 0x00000000D83DDE10L, 0x00000000D83DDE15L, 0x00000000D83DDE2FL, 0x00000000D83DDE36L, 0x00000000D83DDE07L,
|
||||
0x00000000D83DDE0FL, 0x00000000D83DDE11L, 0x00000000D83DDC72L, 0x00000000D83DDC73L, 0x00000000D83DDC6EL, 0x00000000D83DDC77L, 0x00000000D83DDC82L,
|
||||
0x00000000D83DDC76L, 0x00000000D83DDC66L, 0x00000000D83DDC67L, 0x00000000D83DDC68L, 0x00000000D83DDC69L, 0x00000000D83DDC74L, 0x00000000D83DDC75L,
|
||||
0x00000000D83DDC71L, 0x00000000D83DDC7CL, 0x00000000D83DDC78L, 0x00000000D83DDE3AL, 0x00000000D83DDE38L, 0x00000000D83DDE3BL, 0x00000000D83DDE3DL,
|
||||
0x00000000D83DDE3CL, 0x00000000D83DDE40L, 0x00000000D83DDE3FL, 0x00000000D83DDE39L, 0x00000000D83DDE3EL, 0x00000000D83DDC79L, 0x00000000D83DDC7AL,
|
||||
0x00000000D83DDE48L, 0x00000000D83DDE49L, 0x00000000D83DDE4AL, 0x00000000D83DDC80L, 0x00000000D83DDC7DL, 0x00000000D83DDCA9L, 0x00000000D83DDD25L,
|
||||
0x0000000000002728L, 0x00000000D83CDF1FL, 0x00000000D83DDCABL, 0x00000000D83DDCA5L, 0x00000000D83DDCA2L, 0x00000000D83DDCA6L, 0x00000000D83DDCA7L,
|
||||
0x00000000D83DDCA4L, 0x00000000D83DDCA8L, 0x00000000D83DDC42L, 0x00000000D83DDC40L, 0x00000000D83DDC43L, 0x00000000D83DDC45L, 0x00000000D83DDC44L,
|
||||
0x00000000D83DDC4DL, 0x00000000D83DDC4EL, 0x00000000D83DDC4CL, 0x00000000D83DDC4AL, 0x000000000000270AL, 0x000000000000270CL, 0x00000000D83DDC4BL,
|
||||
0x000000000000270BL, 0x00000000D83DDC50L, 0x00000000D83DDC46L, 0x00000000D83DDC47L, 0x00000000D83DDC49L, 0x00000000D83DDC48L, 0x00000000D83DDE4CL,
|
||||
0x00000000D83DDE4FL, 0x000000000000261DL, 0x00000000D83DDC4FL, 0x00000000D83DDCAAL, 0x00000000D83DDEB6L, 0x00000000D83CDFC3L, 0x00000000D83DDC83L,
|
||||
0x00000000D83DDC6BL, 0x00000000D83DDC6AL, 0x00000000D83DDC6CL, 0x00000000D83DDC6DL, 0x00000000D83DDC8FL, 0x00000000D83DDC91L, 0x00000000D83DDC6FL,
|
||||
0x00000000D83DDE46L, 0x00000000D83DDE45L, 0x00000000D83DDC81L, 0x00000000D83DDE4BL, 0x00000000D83DDC86L, 0x00000000D83DDC87L, 0x00000000D83DDC85L,
|
||||
0x00000000D83DDC70L, 0x00000000D83DDE4EL, 0x00000000D83DDE4DL, 0x00000000D83DDE47L, 0x00000000D83CDFA9L, 0x00000000D83DDC51L, 0x00000000D83DDC52L,
|
||||
0x00000000D83DDC5FL, 0x00000000D83DDC5EL, 0x00000000D83DDC61L, 0x00000000D83DDC60L, 0x00000000D83DDC62L, 0x00000000D83DDC55L, 0x00000000D83DDC54L,
|
||||
0x00000000D83DDC5AL, 0x00000000D83DDC57L, 0x00000000D83CDFBDL, 0x00000000D83DDC56L, 0x00000000D83DDC58L, 0x00000000D83DDC59L, 0x00000000D83DDCBCL,
|
||||
0x00000000D83DDC5CL, 0x00000000D83DDC5DL, 0x00000000D83DDC5BL, 0x00000000D83DDC53L, 0x00000000D83CDF80L, 0x00000000D83CDF02L, 0x00000000D83DDC84L,
|
||||
0x00000000D83DDC9BL, 0x00000000D83DDC99L, 0x00000000D83DDC9CL, 0x00000000D83DDC9AL, 0x0000000000002764L, 0x00000000D83DDC94L, 0x00000000D83DDC97L,
|
||||
0x00000000D83DDC93L, 0x00000000D83DDC95L, 0x00000000D83DDC96L, 0x00000000D83DDC9EL, 0x00000000D83DDC98L, 0x00000000D83DDC8CL, 0x00000000D83DDC8BL,
|
||||
0x00000000D83DDC8DL, 0x00000000D83DDC8EL, 0x00000000D83DDC64L, 0x00000000D83DDC65L, 0x00000000D83DDCACL, 0x00000000D83DDC63L, 0x00000000D83DDCADL},
|
||||
new long[]
|
||||
{0x00000000D83DDC36L, 0x00000000D83DDC3AL, 0x00000000D83DDC31L, 0x00000000D83DDC2DL, 0x00000000D83DDC39L, 0x00000000D83DDC30L, 0x00000000D83DDC38L, 0x00000000D83DDC2FL,
|
||||
0x00000000D83DDC28L, 0x00000000D83DDC3BL, 0x00000000D83DDC37L, 0x00000000D83DDC3DL, 0x00000000D83DDC2EL, 0x00000000D83DDC17L, 0x00000000D83DDC35L,
|
||||
0x00000000D83DDC12L, 0x00000000D83DDC34L, 0x00000000D83DDC11L, 0x00000000D83DDC18L, 0x00000000D83DDC3CL, 0x00000000D83DDC27L, 0x00000000D83DDC26L,
|
||||
0x00000000D83DDC24L, 0x00000000D83DDC25L, 0x00000000D83DDC23L, 0x00000000D83DDC14L, 0x00000000D83DDC0DL, 0x00000000D83DDC22L, 0x00000000D83DDC1BL,
|
||||
0x00000000D83DDC1DL, 0x00000000D83DDC1CL, 0x00000000D83DDC1EL, 0x00000000D83DDC0CL, 0x00000000D83DDC19L, 0x00000000D83DDC1AL, 0x00000000D83DDC20L,
|
||||
0x00000000D83DDC1FL, 0x00000000D83DDC2CL, 0x00000000D83DDC33L, 0x00000000D83DDC0BL, 0x00000000D83DDC04L, 0x00000000D83DDC0FL, 0x00000000D83DDC00L,
|
||||
0x00000000D83DDC03L, 0x00000000D83DDC05L, 0x00000000D83DDC07L, 0x00000000D83DDC09L, 0x00000000D83DDC0EL, 0x00000000D83DDC10L, 0x00000000D83DDC13L,
|
||||
0x00000000D83DDC15L, 0x00000000D83DDC16L, 0x00000000D83DDC01L, 0x00000000D83DDC02L, 0x00000000D83DDC32L, 0x00000000D83DDC21L, 0x00000000D83DDC0AL,
|
||||
0x00000000D83DDC2BL, 0x00000000D83DDC2AL, 0x00000000D83DDC06L, 0x00000000D83DDC08L, 0x00000000D83DDC29L, 0x00000000D83DDC3EL, 0x00000000D83DDC90L,
|
||||
0x00000000D83CDF38L, 0x00000000D83CDF37L, 0x00000000D83CDF40L, 0x00000000D83CDF39L, 0x00000000D83CDF3BL, 0x00000000D83CDF3AL, 0x00000000D83CDF41L,
|
||||
0x00000000D83CDF43L, 0x00000000D83CDF42L, 0x00000000D83CDF3FL, 0x00000000D83CDF3EL, 0x00000000D83CDF44L, 0x00000000D83CDF35L, 0x00000000D83CDF34L,
|
||||
0x00000000D83CDF32L, 0x00000000D83CDF33L, 0x00000000D83CDF30L, 0x00000000D83CDF31L, 0x00000000D83CDF3CL, 0x00000000D83CDF10L, 0x00000000D83CDF1EL,
|
||||
0x00000000D83CDF1DL, 0x00000000D83CDF1AL, 0x00000000D83CDF11L, 0x00000000D83CDF12L, 0x00000000D83CDF13L, 0x00000000D83CDF14L, 0x00000000D83CDF15L,
|
||||
0x00000000D83CDF16L, 0x00000000D83CDF17L, 0x00000000D83CDF18L, 0x00000000D83CDF1CL, 0x00000000D83CDF1BL, 0x00000000D83CDF19L, 0x00000000D83CDF0DL,
|
||||
0x00000000D83CDF0EL, 0x00000000D83CDF0FL, 0x00000000D83CDF0BL, 0x00000000D83CDF0CL, 0x00000000D83CDF20L, 0x0000000000002B50L, 0x0000000000002600L,
|
||||
0x00000000000026C5L, 0x0000000000002601L, 0x00000000000026A1L, 0x0000000000002614L, 0x0000000000002744L, 0x00000000000026C4L, 0x00000000D83CDF00L,
|
||||
0x00000000D83CDF01L, 0x00000000D83CDF08L, 0x00000000D83CDF0AL},
|
||||
new long[]
|
||||
{0x00000000D83CDF8DL, 0x00000000D83DDC9DL, 0x00000000D83CDF8EL, 0x00000000D83CDF92L, 0x00000000D83CDF93L, 0x00000000D83CDF8FL, 0x00000000D83CDF86L, 0x00000000D83CDF87L,
|
||||
0x00000000D83CDF90L, 0x00000000D83CDF91L, 0x00000000D83CDF83L, 0x00000000D83DDC7BL, 0x00000000D83CDF85L, 0x00000000D83CDF84L, 0x00000000D83CDF81L,
|
||||
0x00000000D83CDF8BL, 0x00000000D83CDF89L, 0x00000000D83CDF8AL, 0x00000000D83CDF88L, 0x00000000D83CDF8CL, 0x00000000D83DDD2EL, 0x00000000D83CDFA5L,
|
||||
0x00000000D83DDCF7L, 0x00000000D83DDCF9L, 0x00000000D83DDCFCL, 0x00000000D83DDCBFL, 0x00000000D83DDCC0L, 0x00000000D83DDCBDL, 0x00000000D83DDCBEL,
|
||||
0x00000000D83DDCBBL, 0x00000000D83DDCF1L, 0x000000000000260EL, 0x00000000D83DDCDEL, 0x00000000D83DDCDFL, 0x00000000D83DDCE0L, 0x00000000D83DDCE1L,
|
||||
0x00000000D83DDCFAL, 0x00000000D83DDCFBL, 0x00000000D83DDD0AL, 0x00000000D83DDD09L, 0x00000000D83DDD08L, 0x00000000D83DDD07L, 0x00000000D83DDD14L,
|
||||
0x00000000D83DDD14L, 0x00000000D83DDCE2L, 0x00000000D83DDCE3L, 0x00000000000023F3L, 0x000000000000231BL, 0x00000000000023F0L, 0x000000000000231AL,
|
||||
0x00000000D83DDD13L, 0x00000000D83DDD12L, 0x00000000D83DDD0FL, 0x00000000D83DDD10L, 0x00000000D83DDD11L, 0x00000000D83DDD0EL, 0x00000000D83DDCA1L,
|
||||
0x00000000D83DDD26L, 0x00000000D83DDD06L, 0x00000000D83DDD05L, 0x00000000D83DDD0CL, 0x00000000D83DDD0BL, 0x00000000D83DDD0DL, 0x00000000D83DDEC0L,
|
||||
0x00000000D83DDEBFL, 0x00000000D83DDEBDL, 0x00000000D83DDD27L, 0x00000000D83DDD29L, 0x00000000D83DDD28L, 0x00000000D83DDEAAL, 0x00000000D83DDEACL,
|
||||
0x00000000D83DDCA3L, 0x00000000D83DDD2BL, 0x00000000D83DDD2AL, 0x00000000D83DDC8AL, 0x00000000D83DDC89L, 0x00000000D83DDCB0L, 0x00000000D83DDCB4L,
|
||||
0x00000000D83DDCB5L, 0x00000000D83DDCB7L, 0x00000000D83DDCB6L, 0x00000000D83DDCB3L, 0x00000000D83DDCB8L, 0x00000000D83DDCF2L, 0x00000000D83DDCE7L,
|
||||
0x00000000D83DDCE5L, 0x00000000D83DDCE4L, 0x0000000000002709L, 0x00000000D83DDCE9L, 0x00000000D83DDCE8L, 0x00000000D83DDCEFL, 0x00000000D83DDCEBL,
|
||||
0x00000000D83DDCEAL, 0x00000000D83DDCECL, 0x00000000D83DDCEDL, 0x00000000D83DDCEEL, 0x00000000D83DDCE6L, 0x00000000D83DDCDDL, 0x00000000D83DDCC4L,
|
||||
0x00000000D83DDCC3L, 0x00000000D83DDCD1L, 0x00000000D83DDCCAL, 0x00000000D83DDCC8L, 0x00000000D83DDCC9L, 0x00000000D83DDCDCL, 0x00000000D83DDCCBL,
|
||||
0x00000000D83DDCC5L, 0x00000000D83DDCC6L, 0x00000000D83DDCC7L, 0x00000000D83DDCC1L, 0x00000000D83DDCC2L, 0x0000000000002702L, 0x00000000D83DDCCCL,
|
||||
0x00000000D83DDCCEL, 0x0000000000002712L, 0x000000000000270FL, 0x00000000D83DDCCFL, 0x00000000D83DDCD0L, 0x00000000D83DDCD5L, 0x00000000D83DDCD7L,
|
||||
0x00000000D83DDCD8L, 0x00000000D83DDCD9L, 0x00000000D83DDCD3L, 0x00000000D83DDCD4L, 0x00000000D83DDCD2L, 0x00000000D83DDCDAL, 0x00000000D83DDCD6L,
|
||||
0x00000000D83DDD16L, 0x00000000D83DDCDBL, 0x00000000D83DDD2CL, 0x00000000D83DDD2DL, 0x00000000D83DDCF0L, 0x00000000D83CDFA8L, 0x00000000D83CDFACL,
|
||||
0x00000000D83CDFA4L, 0x00000000D83CDFA7L, 0x00000000D83CDFBCL, 0x00000000D83CDFB5L, 0x00000000D83CDFB6L, 0x00000000D83CDFB9L, 0x00000000D83CDFBBL,
|
||||
0x00000000D83CDFBAL, 0x00000000D83CDFB7L, 0x00000000D83CDFB8L, 0x00000000D83DDC7EL, 0x00000000D83CDFAEL, 0x00000000D83CDCCFL, 0x00000000D83CDFB4L,
|
||||
0x00000000D83CDC04L, 0x00000000D83CDFB2L, 0x00000000D83CDFAFL, 0x00000000D83CDFC8L, 0x00000000D83CDFC0L, 0x00000000000026BDL, 0x00000000000026BEL,
|
||||
0x00000000D83CDFBEL, 0x00000000D83CDFB1L, 0x00000000D83CDFC9L, 0x00000000D83CDFB3L, 0x00000000000026F3L, 0x00000000D83DDEB5L, 0x00000000D83DDEB4L,
|
||||
0x00000000D83CDFC1L, 0x00000000D83CDFC7L, 0x00000000D83CDFC6L, 0x00000000D83CDFBFL, 0x00000000D83CDFC2L, 0x00000000D83CDFCAL, 0x00000000D83CDFC4L,
|
||||
0x00000000D83CDFA3L, 0x0000000000002615L, 0x00000000D83CDF75L, 0x00000000D83CDF76L, 0x00000000D83CDF7CL, 0x00000000D83CDF7AL, 0x00000000D83CDF7BL,
|
||||
0x00000000D83CDF78L, 0x00000000D83CDF79L, 0x00000000D83CDF77L, 0x00000000D83CDF74L, 0x00000000D83CDF55L, 0x00000000D83CDF54L, 0x00000000D83CDF5FL,
|
||||
0x00000000D83CDF57L, 0x00000000D83CDF56L, 0x00000000D83CDF5DL, 0x00000000D83CDF5BL, 0x00000000D83CDF64L, 0x00000000D83CDF71L, 0x00000000D83CDF63L,
|
||||
0x00000000D83CDF65L, 0x00000000D83CDF59L, 0x00000000D83CDF58L, 0x00000000D83CDF5AL, 0x00000000D83CDF5CL, 0x00000000D83CDF72L, 0x00000000D83CDF62L,
|
||||
0x00000000D83CDF61L, 0x00000000D83CDF73L, 0x00000000D83CDF5EL, 0x00000000D83CDF69L, 0x00000000D83CDF6EL, 0x00000000D83CDF66L, 0x00000000D83CDF68L,
|
||||
0x00000000D83CDF67L, 0x00000000D83CDF82L, 0x00000000D83CDF70L, 0x00000000D83CDF6AL, 0x00000000D83CDF6BL, 0x00000000D83CDF6CL, 0x00000000D83CDF6DL,
|
||||
0x00000000D83CDF6FL, 0x00000000D83CDF4EL, 0x00000000D83CDF4FL, 0x00000000D83CDF4AL, 0x00000000D83CDF4BL, 0x00000000D83CDF52L, 0x00000000D83CDF47L,
|
||||
0x00000000D83CDF49L, 0x00000000D83CDF53L, 0x00000000D83CDF51L, 0x00000000D83CDF48L, 0x00000000D83CDF4CL, 0x00000000D83CDF50L, 0x00000000D83CDF4DL,
|
||||
0x00000000D83CDF60L, 0x00000000D83CDF46L, 0x00000000D83CDF45L, 0x00000000D83CDF3DL},
|
||||
new long[]
|
||||
{0x00000000D83CDFE0L, 0x00000000D83CDFE1L, 0x00000000D83CDFEBL, 0x00000000D83CDFE2L, 0x00000000D83CDFE3L, 0x00000000D83CDFE5L, 0x00000000D83CDFE6L, 0x00000000D83CDFEAL,
|
||||
0x00000000D83CDFE9L, 0x00000000D83CDFE8L, 0x00000000D83DDC92L, 0x00000000000026EAL, 0x00000000D83CDFECL, 0x00000000D83CDFE4L, 0x00000000D83CDF07L,
|
||||
0x00000000D83CDF06L, 0x00000000D83CDFEFL, 0x00000000D83CDFF0L, 0x00000000000026FAL, 0x00000000D83CDFEDL, 0x00000000D83DDDFCL, 0x00000000D83DDDFEL,
|
||||
0x00000000D83DDDFBL, 0x00000000D83CDF04L, 0x00000000D83CDF05L, 0x00000000D83CDF03L, 0x00000000D83DDDFDL, 0x00000000D83CDF09L, 0x00000000D83CDFA0L,
|
||||
0x00000000D83CDFA1L, 0x00000000000026F2L, 0x00000000D83CDFA2L, 0x00000000D83DDEA2L, 0x00000000000026F5L, 0x00000000D83DDEA4L, 0x00000000D83DDEA3L,
|
||||
0x0000000000002693L, 0x00000000D83DDE80L, 0x0000000000002708L, 0x00000000D83DDCBAL, 0x00000000D83DDE81L, 0x00000000D83DDE82L, 0x00000000D83DDE8AL,
|
||||
0x00000000D83DDE89L, 0x00000000D83DDE9EL, 0x00000000D83DDE86L, 0x00000000D83DDE84L, 0x00000000D83DDE85L, 0x00000000D83DDE88L, 0x00000000D83DDE87L,
|
||||
0x00000000D83DDE9DL, 0x00000000D83DDE8BL, 0x00000000D83DDE83L, 0x00000000D83DDE8EL, 0x00000000D83DDE8CL, 0x00000000D83DDE8DL, 0x00000000D83DDE99L,
|
||||
0x00000000D83DDE98L, 0x00000000D83DDE97L, 0x00000000D83DDE95L, 0x00000000D83DDE96L, 0x00000000D83DDE9BL, 0x00000000D83DDE9AL, 0x00000000D83DDEA8L,
|
||||
0x00000000D83DDE93L, 0x00000000D83DDE94L, 0x00000000D83DDE92L, 0x00000000D83DDE91L, 0x00000000D83DDE90L, 0x00000000D83DDEB2L, 0x00000000D83DDEA1L,
|
||||
0x00000000D83DDE9FL, 0x00000000D83DDEA0L, 0x00000000D83DDE9CL, 0x00000000D83DDC88L, 0x00000000D83DDE8FL, 0x00000000D83CDFABL, 0x00000000D83DDEA6L,
|
||||
0x00000000D83DDEA5L, 0x00000000000026A0L, 0x00000000D83DDEA7L, 0x00000000D83DDD30L, 0x00000000000026FDL, 0x00000000D83CDFEEL, 0x00000000D83CDFB0L,
|
||||
0x0000000000002668L, 0x00000000D83DDDFFL, 0x00000000D83CDFAAL, 0x00000000D83CDFADL, 0x00000000D83DDCCDL, 0x00000000D83DDEA9L, 0xD83CDDEFD83CDDF5L,
|
||||
0xD83CDDF0D83CDDF7L, 0xD83CDDE9D83CDDEAL, 0xD83CDDE8D83CDDF3L, 0xD83CDDFAD83CDDF8L, 0xD83CDDEBD83CDDF7L, 0xD83CDDEAD83CDDF8L, 0xD83CDDEED83CDDF9L,
|
||||
0xD83CDDF7D83CDDFAL, 0xD83CDDECD83CDDE7L},
|
||||
new long[]
|
||||
{0x00000000003120E3L, 0x00000000003220E3L, 0x00000000003320E3L, 0x00000000003420E3L, 0x00000000003520E3L, 0x00000000003620E3L, 0x00000000003720E3L, 0x00000000003820E3L,
|
||||
0x00000000003920E3L, 0x00000000003020E3L, 0x00000000D83DDD1FL, 0x00000000D83DDD22L, 0x00000000002320E3L, 0x00000000D83DDD23L, 0x0000000000002B06L,
|
||||
0x0000000000002B07L, 0x0000000000002B05L, 0x00000000000027A1L, 0x00000000D83DDD20L, 0x00000000D83DDD21L, 0x00000000D83DDD24L, 0x0000000000002197L,
|
||||
0x0000000000002196L, 0x0000000000002198L, 0x0000000000002199L, 0x0000000000002194L, 0x0000000000002195L, 0x00000000D83DDD04L, 0x00000000000025C0L,
|
||||
0x00000000000025B6L, 0x00000000D83DDD3CL, 0x00000000D83DDD3DL, 0x00000000000021A9L, 0x00000000000021AAL, 0x0000000000002139L, 0x00000000000023EAL,
|
||||
0x00000000000023E9L, 0x00000000000023EBL, 0x00000000000023ECL, 0x0000000000002935L, 0x0000000000002934L, 0x00000000D83CDD97L, 0x00000000D83DDD00L,
|
||||
0x00000000D83DDD01L, 0x00000000D83DDD02L, 0x00000000D83CDD95L, 0x00000000D83CDD99L, 0x00000000D83CDD92L, 0x00000000D83CDD93L, 0x00000000D83CDD96L,
|
||||
0x00000000D83DDCF6L, 0x00000000D83CDFA6L, 0x00000000D83CDE01L, 0x00000000D83CDE2FL, 0x00000000D83CDE33L, 0x00000000D83CDE35L, 0x00000000D83CDE32L,
|
||||
0x00000000D83CDE34L, 0x00000000D83CDE32L, 0x00000000D83CDE50L, 0x00000000D83CDE39L, 0x00000000D83CDE3AL, 0x00000000D83CDE36L, 0x00000000D83CDE1AL,
|
||||
0x00000000D83DDEBBL, 0x00000000D83DDEB9L, 0x00000000D83DDEBAL, 0x00000000D83DDEBCL, 0x00000000D83DDEBEL, 0x00000000D83DDEB0L, 0x00000000D83DDEAEL,
|
||||
0x00000000D83CDD7FL, 0x000000000000267FL, 0x00000000D83DDEADL, 0x00000000D83CDE37L, 0x00000000D83CDE38L, 0x00000000D83CDE02L, 0x00000000000024C2L,
|
||||
0x00000000D83CDE51L, 0x0000000000003299L, 0x0000000000003297L, 0x00000000D83CDD91L, 0x00000000D83CDD98L, 0x00000000D83CDD94L, 0x00000000D83DDEABL,
|
||||
0x00000000D83DDD1EL, 0x00000000D83DDCF5L, 0x00000000D83DDEAFL, 0x00000000D83DDEB1L, 0x00000000D83DDEB3L, 0x00000000D83DDEB7L, 0x00000000D83DDEB8L,
|
||||
0x00000000000026D4L, 0x0000000000002733L, 0x0000000000002747L, 0x000000000000274EL, 0x0000000000002705L, 0x0000000000002734L, 0x00000000D83DDC9FL,
|
||||
0x00000000D83CDD9AL, 0x00000000D83DDCF3L, 0x00000000D83DDCF4L, 0x00000000D83CDD70L, 0x00000000D83CDD71L, 0x00000000D83CDD8EL, 0x00000000D83CDD7EL,
|
||||
0x00000000D83DDCA0L, 0x00000000000027BFL, 0x000000000000267BL, 0x0000000000002648L, 0x0000000000002649L, 0x000000000000264AL, 0x000000000000264BL,
|
||||
0x000000000000264CL, 0x000000000000264DL, 0x000000000000264EL, 0x000000000000264FL, 0x0000000000002650L, 0x0000000000002651L, 0x0000000000002652L,
|
||||
0x0000000000002653L, 0x00000000000026CEL, 0x00000000D83DDD2FL, 0x00000000D83CDFE7L, 0x00000000D83DDCB9L, 0x00000000D83DDCB2L, 0x00000000D83DDCB1L,
|
||||
0x00000000000000A9L, 0x00000000000000AEL, 0x0000000000002122L, 0x000000000000303DL, 0x0000000000003030L, 0x00000000D83DDD1DL, 0x00000000D83DDD1AL,
|
||||
0x00000000D83DDD19L, 0x00000000D83DDD1BL, 0x00000000D83DDD1CL, 0x000000000000274CL, 0x0000000000002B55L, 0x0000000000002757L, 0x0000000000002753L,
|
||||
0x0000000000002755L, 0x0000000000002754L, 0x00000000D83DDD03L, 0x00000000D83DDD5BL, 0x00000000D83DDD67L, 0x00000000D83DDD50L, 0x00000000D83DDD5CL,
|
||||
0x00000000D83DDD51L, 0x00000000D83DDD5DL, 0x00000000D83DDD52L, 0x00000000D83DDD5EL, 0x00000000D83DDD53L, 0x00000000D83DDD5FL, 0x00000000D83DDD54L,
|
||||
0x00000000D83DDD60L, 0x00000000D83DDD55L, 0x00000000D83DDD56L, 0x00000000D83DDD57L, 0x00000000D83DDD58L, 0x00000000D83DDD59L, 0x00000000D83DDD5AL,
|
||||
0x00000000D83DDD61L, 0x00000000D83DDD62L, 0x00000000D83DDD63L, 0x00000000D83DDD64L, 0x00000000D83DDD65L, 0x00000000D83DDD66L, 0x0000000000002716L,
|
||||
0x0000000000002795L, 0x0000000000002796L, 0x0000000000002797L, 0x0000000000002660L, 0x0000000000002665L, 0x0000000000002663L, 0x0000000000002666L,
|
||||
0x00000000D83DDCAEL, 0x00000000D83DDCAFL, 0x0000000000002714L, 0x0000000000002611L, 0x00000000D83DDD18L, 0x00000000D83DDD17L, 0x00000000000027B0L,
|
||||
0x00000000D83DDD31L, 0x00000000D83DDD32L, 0x00000000D83DDD33L, 0x00000000000025FCL, 0x00000000000025FBL, 0x00000000000025FEL, 0x00000000000025FDL,
|
||||
0x00000000000025AAL, 0x00000000000025ABL, 0x00000000D83DDD3AL, 0x0000000000002B1CL, 0x0000000000002B1BL, 0x00000000000026ABL, 0x00000000000026AAL,
|
||||
0x00000000D83DDD34L, 0x00000000D83DDD35L, 0x00000000D83DDD3BL, 0x00000000D83DDD36L, 0x00000000D83DDD37L, 0x00000000D83DDD38L, 0x00000000D83DDD39L}};
|
||||
|
||||
static {
|
||||
imgSize = Math.min(scale(30), Utilities.applicationContext.getResources().getDisplayMetrics().density < 1.5f ? 28 : 56);
|
||||
drawImgSize = scale(20);
|
||||
bigImgSize = scale(30);
|
||||
if(Math.abs(imgSize - bigImgSize) < 5) {
|
||||
bigImgSize = imgSize;
|
||||
}
|
||||
|
||||
for (int j = 1; j < data.length; j++) {
|
||||
int rsize = ROW_SIZES[j - 1];
|
||||
for(int i = 0; i < data[j].length; i++) {
|
||||
Rect rect = new Rect((i % rsize) * imgSize, (i / rsize) * imgSize, (i % rsize + 1) * imgSize, (i / rsize + 1) * imgSize);
|
||||
rects.put(data[j][i], new DrawableInfo(rect, j - 1));
|
||||
}
|
||||
}
|
||||
placeholderPaint = new Paint();
|
||||
placeholderPaint.setColor(0x55000000);
|
||||
}
|
||||
|
||||
public static int scale(float value) {
|
||||
return (int)(Utilities.applicationContext.getResources().getDisplayMetrics().density * value);
|
||||
}
|
||||
|
||||
private static Bitmap loadPage(final int page){
|
||||
try {
|
||||
int rsize = ROW_SIZES[page];
|
||||
|
||||
BitmapFactory.Options opts = new BitmapFactory.Options();
|
||||
opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
|
||||
|
||||
opts.inDither = false;
|
||||
if (Utilities.applicationContext.getResources().getDisplayMetrics().density < 1.5f) {
|
||||
opts.inSampleSize = 2;
|
||||
}
|
||||
|
||||
int iw, ih;
|
||||
|
||||
InputStream is = Utilities.applicationContext.getAssets().open("emojisprite_" + page + ".png");
|
||||
Bitmap color = BitmapFactory.decodeStream(is, null, opts);
|
||||
is.close();
|
||||
|
||||
iw = color.getWidth();
|
||||
ih = color.getHeight();
|
||||
|
||||
ih = (int)Math.round(((double)imgSize * rsize) * ((double)ih / iw));
|
||||
iw = imgSize * rsize;
|
||||
|
||||
if(iw < color.getWidth() && ih < color.getWidth()) {
|
||||
color = Bitmap.createScaledBitmap(color, iw, ih, true);
|
||||
}
|
||||
|
||||
bmps[page] = color;
|
||||
|
||||
final Bitmap img = color;
|
||||
Utilities.RunOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
/*for (int a = 0; a < drawables.size(); a++) {
|
||||
WeakReference<EmojiDrawable> it = drawables.get(a);
|
||||
if (it.get() == null) {
|
||||
drawables.remove(a);
|
||||
a--;
|
||||
} else {
|
||||
EmojiDrawable drawable = it.get();
|
||||
if (drawable.page == page) {
|
||||
drawable.bmp = img;
|
||||
}
|
||||
drawable.invalidateSelf();
|
||||
}
|
||||
}*/
|
||||
NotificationCenter.Instance.postNotificationName(999);
|
||||
}
|
||||
});
|
||||
|
||||
return color;
|
||||
} catch(Throwable x) {
|
||||
Log.e("tmessages", "Error loading emoji", x);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void loadPageAsync(final int page) {
|
||||
if(loading[page]) {
|
||||
return;
|
||||
}
|
||||
loading[page] = true;
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
loadPage(page);
|
||||
loading[page] = false;
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
public static void invalidateAll(View view){
|
||||
if(view instanceof ViewGroup) {
|
||||
ViewGroup g = (ViewGroup)view;
|
||||
for(int i = 0; i < g.getChildCount(); i++){
|
||||
invalidateAll(g.getChildAt(i));
|
||||
}
|
||||
} else if(view instanceof TextView) {
|
||||
view.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public static Drawable getEmojiDrawable(long code){
|
||||
DrawableInfo info = rects.get(code);
|
||||
if(info == null){
|
||||
Log.e("tmessages", "No emoji drawable for code " + String.format("%016X", code));
|
||||
return null;
|
||||
}
|
||||
EmojiDrawable ed = new EmojiDrawable(info);
|
||||
ed.setBounds(0, 0, drawImgSize, drawImgSize);
|
||||
if(bmps[info.page] == null) {
|
||||
loadPageAsync(info.page);
|
||||
}
|
||||
/*drawables.add(new WeakReference<EmojiDrawable>(ed));
|
||||
try {
|
||||
for (int a = 0; a < drawables.size(); a++) {
|
||||
WeakReference<EmojiDrawable> it = drawables.get(a);
|
||||
if (it.get() == null) {
|
||||
drawables.remove(a);
|
||||
a--;
|
||||
}
|
||||
}
|
||||
} catch(Throwable x) {
|
||||
x.printStackTrace();
|
||||
}*/
|
||||
return ed;
|
||||
}
|
||||
|
||||
public static Drawable getEmojiBigDrawable(long code) {
|
||||
EmojiDrawable ed = (EmojiDrawable)getEmojiDrawable(code);
|
||||
if (ed == null) {
|
||||
return null;
|
||||
}
|
||||
ed.setBounds(0, 0, bigImgSize, bigImgSize);
|
||||
ed.fullSize = true;
|
||||
return ed;
|
||||
}
|
||||
|
||||
public static class EmojiDrawable extends Drawable {
|
||||
Rect rect;
|
||||
int page;
|
||||
boolean fullSize = false;
|
||||
private static Paint paint;
|
||||
Bitmap bmp;
|
||||
|
||||
static {
|
||||
paint = new Paint();
|
||||
paint.setFilterBitmap(true);
|
||||
}
|
||||
|
||||
public EmojiDrawable(DrawableInfo info){
|
||||
rect = info.rect;
|
||||
page = info.page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
if(bmps[page] == null){
|
||||
canvas.drawRect(getBounds(), placeholderPaint);
|
||||
return;
|
||||
}
|
||||
if(bmp == null) {
|
||||
bmp = bmps[page];
|
||||
}
|
||||
Rect b = copyBounds();
|
||||
int cX = b.centerX(), cY = b.centerY();
|
||||
b.left = cX - (fullSize ? bigImgSize : drawImgSize) / 2;
|
||||
b.right = cX + (fullSize ? bigImgSize : drawImgSize) / 2;
|
||||
b.top = cY - (fullSize ? bigImgSize : drawImgSize) / 2;
|
||||
b.bottom = cY + (fullSize ? bigImgSize : drawImgSize) / 2;
|
||||
canvas.drawBitmap(bmp, rect, b, paint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter cf) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static class DrawableInfo {
|
||||
Rect rect;
|
||||
int page;
|
||||
public DrawableInfo(Rect rect, int p) {
|
||||
this.rect = rect;
|
||||
page = p;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean inArray(char c, char[] a) {
|
||||
for(char cc : a) {
|
||||
if(cc == c) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static CharSequence replaceEmoji(CharSequence cs) {
|
||||
if (cs == null || cs.length() == 0) {
|
||||
return cs;
|
||||
}
|
||||
Spannable s;
|
||||
if (cs instanceof Spannable){
|
||||
s = (Spannable)cs;
|
||||
} else {
|
||||
s = Spannable.Factory.getInstance().newSpannable(cs);
|
||||
}
|
||||
long buf = 0;
|
||||
for (int i = 0; i < cs.length(); i++){
|
||||
char c = cs.charAt(i);
|
||||
if (c == 0xD83C || c == 0xD83D || (buf != 0 && (buf & 0xFFFFFFFF00000000L) == 0 && (c >= 0xDDE6 && c <= 0xDDFA))) {
|
||||
buf <<= 16;
|
||||
buf |= c;
|
||||
} else if (buf > 0 && (c & 0xF000) == 0xD000) {
|
||||
buf <<= 16;
|
||||
buf |= c;
|
||||
Drawable d = Emoji.getEmojiDrawable(buf);
|
||||
if (d != null){
|
||||
EmojiSpan span = new EmojiSpan(d, DynamicDrawableSpan.ALIGN_BOTTOM);
|
||||
if (c>= 0xDDE6 && c <= 0xDDFA) {
|
||||
s.setSpan(span, i - 3, i + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
} else {
|
||||
s.setSpan(span, i - 1, i + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
}
|
||||
buf = 0;
|
||||
} else if (c == 0x20E3) {
|
||||
if (i > 0) {
|
||||
char c2 = cs.charAt(i - 1);
|
||||
if((c2 >= '0' && c2 <= '9') || c2 == '#') {
|
||||
buf = c2;
|
||||
buf <<= 16;
|
||||
buf |= c;
|
||||
Drawable d = Emoji.getEmojiDrawable(buf);
|
||||
if(d != null) {
|
||||
EmojiSpan span = new EmojiSpan(d, DynamicDrawableSpan.ALIGN_BOTTOM);
|
||||
s.setSpan(span, i - 1, i + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
buf = 0;
|
||||
}
|
||||
}
|
||||
} else if(inArray(c, emojiChars)){
|
||||
Drawable d = Emoji.getEmojiDrawable(c);
|
||||
if(d != null){
|
||||
EmojiSpan span = new EmojiSpan(d, DynamicDrawableSpan.ALIGN_BOTTOM);
|
||||
s.setSpan(span, i, i + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
public static class EmojiSpan extends ImageSpan {
|
||||
public EmojiSpan(Drawable d, int verticalAlignment) {
|
||||
super(d, verticalAlignment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
|
||||
if (fm == null) {
|
||||
fm = new Paint.FontMetricsInt();
|
||||
}
|
||||
|
||||
int sz = super.getSize(paint, text, start, end, fm);
|
||||
|
||||
int offset = (int)(8 * Utilities.applicationContext.getResources().getDisplayMetrics().density);
|
||||
int w = (int)(20 * Utilities.applicationContext.getResources().getDisplayMetrics().density / 2);
|
||||
fm.top = -w - offset;
|
||||
fm.bottom = w - offset;
|
||||
fm.ascent = -w - offset;
|
||||
fm.leading = 0;
|
||||
fm.descent = w - offset;
|
||||
|
||||
return sz;
|
||||
}
|
||||
}
|
||||
|
||||
public static class XImageSpan extends ImageSpan {
|
||||
public int uid;
|
||||
|
||||
public XImageSpan(Drawable d, int verticalAlignment) {
|
||||
super(d, verticalAlignment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
|
||||
if (fm == null) {
|
||||
fm = new Paint.FontMetricsInt();
|
||||
}
|
||||
|
||||
int sz = super.getSize(paint, text, start, end, fm);
|
||||
|
||||
int offset = (int)(6 * Utilities.applicationContext.getResources().getDisplayMetrics().density);
|
||||
int w = (fm.bottom - fm.top) / 2;
|
||||
fm.top = -w - offset;
|
||||
fm.bottom = w - offset;
|
||||
fm.ascent = -w - offset;
|
||||
fm.leading = 0;
|
||||
fm.descent = w - offset;
|
||||
|
||||
return sz;
|
||||
}
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
|
||||
// if (fm == null) {
|
||||
// fm = new Paint.FontMetricsInt();
|
||||
// }
|
||||
// paint.getFontMetricsInt(fm);
|
||||
//
|
||||
// int sz = super.getSize(paint, text, start, end, fm);
|
||||
// if(fm != null) {
|
||||
// fm.ascent = (int)paint.ascent();
|
||||
// fm.descent = (int)paint.descent();
|
||||
// }
|
||||
// return sz;
|
||||
// }
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import org.telegram.TL.TLObject;
|
||||
import org.telegram.TL.TLRPC;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class ExportAuthorizationAction extends Action {
|
||||
public Datacenter datacenter;
|
||||
TLRPC.TL_auth_exportedAuthorization exportedAuthorization;
|
||||
int retryCount;
|
||||
|
||||
public ExportAuthorizationAction(Datacenter d) {
|
||||
datacenter = d;
|
||||
}
|
||||
|
||||
public void execute(HashMap options) {
|
||||
if (datacenter == null) {
|
||||
delegate.ActionDidFailExecution(this);
|
||||
return;
|
||||
}
|
||||
beginExport();
|
||||
}
|
||||
|
||||
void beginExport() {
|
||||
TLRPC.TL_auth_exportAuthorization exportAuthorization = new TLRPC.TL_auth_exportAuthorization();
|
||||
exportAuthorization.dc_id = datacenter.datacenterId;
|
||||
|
||||
ConnectionsManager.Instance.performRpc(exportAuthorization, new RPCRequest.RPCRequestDelegate() {
|
||||
@Override
|
||||
public void run(TLObject response, TLRPC.TL_error error) {
|
||||
if (error == null) {
|
||||
exportedAuthorization = (TLRPC.TL_auth_exportedAuthorization)response;
|
||||
beginImport();
|
||||
} else {
|
||||
retryCount++;
|
||||
if (retryCount >= 3) {
|
||||
delegate.ActionDidFailExecution(ExportAuthorizationAction.this);
|
||||
} else {
|
||||
Utilities.stageQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
beginExport();
|
||||
}
|
||||
}, retryCount * 1500);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, null, true, RPCRequest.RPCRequestClassGeneric);
|
||||
}
|
||||
|
||||
void beginImport() {
|
||||
TLRPC.TL_auth_importAuthorization importAuthorization = new TLRPC.TL_auth_importAuthorization();
|
||||
importAuthorization.bytes = exportedAuthorization.bytes;
|
||||
importAuthorization.id = exportedAuthorization.id;
|
||||
|
||||
ConnectionsManager.Instance.performRpc(importAuthorization, new RPCRequest.RPCRequestDelegate() {
|
||||
@Override
|
||||
public void run(TLObject response, TLRPC.TL_error error) {
|
||||
if (error == null) {
|
||||
delegate.ActionDidFinishExecution(ExportAuthorizationAction.this, null);
|
||||
} else {
|
||||
exportedAuthorization = null;
|
||||
retryCount++;
|
||||
if (retryCount >= 3) {
|
||||
delegate.ActionDidFailExecution(ExportAuthorizationAction.this);
|
||||
} else {
|
||||
Utilities.stageQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
beginExport();
|
||||
}
|
||||
}, retryCount * 1500);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, null, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassEnableUnauthorized, datacenter.datacenterId);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,500 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
|
||||
import org.telegram.TL.TLObject;
|
||||
import org.telegram.TL.TLRPC;
|
||||
|
||||
import java.io.RandomAccessFile;
|
||||
import java.net.URL;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Scanner;
|
||||
|
||||
public class FileLoadOperation {
|
||||
private int downloadChunkSize = 1024 * 32;
|
||||
|
||||
public int datacenter_id;
|
||||
private TLRPC.InputFileLocation location;
|
||||
public volatile int state = 0;
|
||||
private int downloadedBytes;
|
||||
public int totalBytesCount;
|
||||
public FileLoadOperationDelegate delegate;
|
||||
public Bitmap image;
|
||||
public String filter;
|
||||
private byte[] key;
|
||||
private byte[] iv;
|
||||
private long requestToken = 0;
|
||||
|
||||
private File cacheFileTemp;
|
||||
private File cacheFileFinal;
|
||||
|
||||
private String httpUrl;
|
||||
private URLConnection httpConnection;
|
||||
public boolean needBitmapCreate = true;
|
||||
private InputStream httpConnectionStream;
|
||||
private RandomAccessFile fileOutputStream;
|
||||
|
||||
public static interface FileLoadOperationDelegate {
|
||||
public abstract void didFinishLoadingFile(FileLoadOperation operation);
|
||||
public abstract void didFailedLoadingFile(FileLoadOperation operation);
|
||||
public abstract void didChangedLoadProgress(FileLoadOperation operation, float progress);
|
||||
}
|
||||
|
||||
public FileLoadOperation(TLRPC.FileLocation fileLocation) {
|
||||
if (fileLocation instanceof TLRPC.TL_fileEncryptedLocation) {
|
||||
location = new TLRPC.TL_inputEncryptedFileLocation();
|
||||
location.id = fileLocation.volume_id;
|
||||
location.volume_id = fileLocation.volume_id;
|
||||
location.access_hash = fileLocation.secret;
|
||||
location.local_id = fileLocation.local_id;
|
||||
iv = new byte[32];
|
||||
System.arraycopy(fileLocation.iv, 0, iv, 0, iv.length);
|
||||
key = fileLocation.key;
|
||||
datacenter_id = fileLocation.dc_id;
|
||||
} else if (fileLocation instanceof TLRPC.TL_fileLocation) {
|
||||
location = new TLRPC.TL_inputFileLocation();
|
||||
location.volume_id = fileLocation.volume_id;
|
||||
location.secret = fileLocation.secret;
|
||||
location.local_id = fileLocation.local_id;
|
||||
datacenter_id = fileLocation.dc_id;
|
||||
}
|
||||
}
|
||||
|
||||
public FileLoadOperation(TLRPC.Video videoLocation) {
|
||||
if (videoLocation instanceof TLRPC.TL_video) {
|
||||
location = new TLRPC.TL_inputVideoFileLocation();
|
||||
datacenter_id = videoLocation.dc_id;
|
||||
location.id = videoLocation.id;
|
||||
location.access_hash = videoLocation.access_hash;
|
||||
} else if (videoLocation instanceof TLRPC.TL_videoEncrypted) {
|
||||
location = new TLRPC.TL_inputEncryptedFileLocation();
|
||||
location.id = videoLocation.id;
|
||||
location.access_hash = videoLocation.access_hash;
|
||||
datacenter_id = videoLocation.dc_id;
|
||||
iv = new byte[32];
|
||||
System.arraycopy(videoLocation.iv, 0, iv, 0, iv.length);
|
||||
key = videoLocation.key;
|
||||
}
|
||||
}
|
||||
|
||||
public FileLoadOperation(String url) {
|
||||
httpUrl = url;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (state != 0) {
|
||||
return;
|
||||
}
|
||||
state = 1;
|
||||
boolean ignoreCache = false;
|
||||
boolean onlyCache = false;
|
||||
String fileNameFinal;
|
||||
String fileNameTemp;
|
||||
if (httpUrl != null) {
|
||||
fileNameFinal = Utilities.MD5(httpUrl);
|
||||
fileNameTemp = fileNameFinal + "_temp.jpg";
|
||||
fileNameFinal += ".jpg";
|
||||
} else if (location.volume_id != 0 && location.local_id != 0) {
|
||||
fileNameTemp = location.volume_id + "_" + location.local_id + "_temp.jpg";
|
||||
fileNameFinal = location.volume_id + "_" + location.local_id + ".jpg";
|
||||
if (datacenter_id == Integer.MIN_VALUE || location.volume_id == Integer.MIN_VALUE) {
|
||||
onlyCache = true;
|
||||
}
|
||||
} else {
|
||||
ignoreCache = true;
|
||||
needBitmapCreate = false;
|
||||
fileNameTemp = datacenter_id + "_" + location.id + "_temp.mp4";
|
||||
fileNameFinal = datacenter_id + "_" + location.id + ".mp4";
|
||||
}
|
||||
|
||||
boolean exist;
|
||||
cacheFileFinal = new File(Utilities.getCacheDir(), fileNameFinal);
|
||||
if ((exist = cacheFileFinal.exists()) && !ignoreCache) {
|
||||
Utilities.cacheOutQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
int delay = 20;
|
||||
if (FileLoader.Instance.runtimeHack != null) {
|
||||
delay = 60;
|
||||
}
|
||||
if (FileLoader.lastCacheOutTime != 0 && FileLoader.lastCacheOutTime > System.currentTimeMillis() - delay) {
|
||||
Thread.sleep(delay);
|
||||
}
|
||||
FileLoader.lastCacheOutTime = System.currentTimeMillis();
|
||||
if (state != 1) {
|
||||
return;
|
||||
}
|
||||
if (needBitmapCreate) {
|
||||
FileInputStream is = new FileInputStream(cacheFileFinal);
|
||||
BitmapFactory.Options opts = new BitmapFactory.Options();
|
||||
|
||||
float w_filter = 0;
|
||||
float h_filter;
|
||||
if (filter != null) {
|
||||
String args[] = filter.split("_");
|
||||
w_filter = Float.parseFloat(args[0]) * FileLoader.Instance.density;
|
||||
h_filter = Float.parseFloat(args[1]) * FileLoader.Instance.density;
|
||||
|
||||
opts.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFile(cacheFileFinal.getAbsolutePath(), opts);
|
||||
float photoW = opts.outWidth;
|
||||
float photoH = opts.outHeight;
|
||||
float scaleFactor = Math.max(photoW / w_filter, photoH / h_filter);
|
||||
if (scaleFactor < 1) {
|
||||
scaleFactor = 1;
|
||||
}
|
||||
opts.inJustDecodeBounds = false;
|
||||
opts.inSampleSize = (int)scaleFactor;
|
||||
}
|
||||
|
||||
opts.inPreferredConfig = Bitmap.Config.RGB_565;
|
||||
opts.inDither = false;
|
||||
image = BitmapFactory.decodeStream(is, null, opts);
|
||||
is.close();
|
||||
if (image == null) {
|
||||
cacheFileFinal.delete();
|
||||
} else {
|
||||
if (filter != null && image != null) {
|
||||
float bitmapW = image.getWidth();
|
||||
float bitmapH = image.getHeight();
|
||||
if (bitmapW != w_filter && bitmapW > w_filter) {
|
||||
float scaleFactor = bitmapW / w_filter;
|
||||
Bitmap scaledBitmap = Bitmap.createScaledBitmap(image, (int)w_filter, (int)(bitmapH / scaleFactor), true);
|
||||
if (image != scaledBitmap) {
|
||||
image.recycle();
|
||||
image = scaledBitmap;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (FileLoader.Instance.runtimeHack != null) {
|
||||
FileLoader.Instance.runtimeHack.trackFree(image.getRowBytes() * image.getHeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
Utilities.stageQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
delegate.didFinishLoadingFile(FileLoadOperation.this);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
cacheFileFinal.delete();
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (onlyCache) {
|
||||
Utilities.stageQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
cacheFileTemp = new File(Utilities.getCacheDir(), fileNameTemp);
|
||||
if (cacheFileTemp.exists()) {
|
||||
downloadedBytes = (int)cacheFileTemp.length();
|
||||
downloadedBytes = downloadedBytes / 1024 * 1024;
|
||||
}
|
||||
if (exist) {
|
||||
cacheFileFinal.delete();
|
||||
}
|
||||
try {
|
||||
fileOutputStream = new RandomAccessFile(cacheFileTemp, "rws");
|
||||
if (downloadedBytes != 0) {
|
||||
fileOutputStream.seek(downloadedBytes);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (fileOutputStream == null) {
|
||||
Utilities.stageQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (httpUrl != null) {
|
||||
startDownloadHTTPRequest();
|
||||
} else {
|
||||
startDownloadRequest();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
if (state != 1) {
|
||||
return;
|
||||
}
|
||||
state = 2;
|
||||
if (httpUrl != null) {
|
||||
try {
|
||||
httpConnectionStream.close();
|
||||
httpConnection = null;
|
||||
httpConnectionStream = null;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
if (fileOutputStream != null) {
|
||||
try {
|
||||
fileOutputStream.close();
|
||||
fileOutputStream = null;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (requestToken != 0) {
|
||||
ConnectionsManager.Instance.cancelRpc(requestToken, true);
|
||||
}
|
||||
}
|
||||
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
||||
}
|
||||
|
||||
private void onFinishLoadingFile() throws Exception {
|
||||
if (state != 1) {
|
||||
return;
|
||||
}
|
||||
state = 3;
|
||||
fileOutputStream.close();
|
||||
fileOutputStream = null;
|
||||
final boolean renamed = cacheFileTemp.renameTo(cacheFileFinal);
|
||||
|
||||
if (needBitmapCreate) {
|
||||
Utilities.cacheOutQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int delay = 20;
|
||||
if (FileLoader.Instance.runtimeHack != null) {
|
||||
delay = 60;
|
||||
}
|
||||
if (FileLoader.lastCacheOutTime != 0 && FileLoader.lastCacheOutTime > System.currentTimeMillis() - delay) {
|
||||
try {
|
||||
Thread.sleep(delay);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
BitmapFactory.Options opts = new BitmapFactory.Options();
|
||||
|
||||
float w_filter = 0;
|
||||
float h_filter;
|
||||
if (filter != null) {
|
||||
String args[] = filter.split("_");
|
||||
w_filter = Float.parseFloat(args[0]) * FileLoader.Instance.density;
|
||||
h_filter = Float.parseFloat(args[1]) * FileLoader.Instance.density;
|
||||
|
||||
opts.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFile(cacheFileFinal.getAbsolutePath(), opts);
|
||||
float photoW = opts.outWidth;
|
||||
float photoH = opts.outHeight;
|
||||
float scaleFactor = Math.max(photoW / w_filter, photoH / h_filter);
|
||||
if (scaleFactor < 1) {
|
||||
scaleFactor = 1;
|
||||
}
|
||||
opts.inJustDecodeBounds = false;
|
||||
opts.inSampleSize = (int) scaleFactor;
|
||||
}
|
||||
|
||||
opts.inPreferredConfig = Bitmap.Config.RGB_565;
|
||||
opts.inDither = false;
|
||||
try {
|
||||
if (renamed) {
|
||||
image = BitmapFactory.decodeStream(new FileInputStream(cacheFileFinal), null, opts);
|
||||
} else {
|
||||
image = BitmapFactory.decodeStream(new FileInputStream(cacheFileTemp), null, opts);
|
||||
}
|
||||
if (filter != null && image != null) {
|
||||
float bitmapW = image.getWidth();
|
||||
float bitmapH = image.getHeight();
|
||||
if (bitmapW != w_filter && bitmapW > w_filter) {
|
||||
float scaleFactor = bitmapW / w_filter;
|
||||
Bitmap scaledBitmap = Bitmap.createScaledBitmap(image, (int) w_filter, (int) (bitmapH / scaleFactor), true);
|
||||
if (image != scaledBitmap) {
|
||||
image.recycle();
|
||||
image = scaledBitmap;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (FileLoader.Instance.runtimeHack != null) {
|
||||
FileLoader.Instance.runtimeHack.trackFree(image.getRowBytes() * image.getHeight());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
delegate.didFinishLoadingFile(FileLoadOperation.this);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
delegate.didFinishLoadingFile(FileLoadOperation.this);
|
||||
}
|
||||
}
|
||||
|
||||
private void startDownloadHTTPRequest() {
|
||||
if (state != 1) {
|
||||
return;
|
||||
}
|
||||
if (httpConnection == null) {
|
||||
try {
|
||||
URL downloadUrl = new URL(httpUrl);
|
||||
httpConnection = downloadUrl.openConnection();
|
||||
httpConnection.setConnectTimeout(5000);
|
||||
httpConnection.setReadTimeout(5000);
|
||||
httpConnection.connect();
|
||||
httpConnectionStream = httpConnection.getInputStream();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Utilities.stageQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
byte[] data = new byte[1024 * 2];
|
||||
int readed = httpConnectionStream.read(data);
|
||||
if (readed > 0) {
|
||||
fileOutputStream.write(data, 0, readed);
|
||||
Utilities.imageLoadQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
startDownloadHTTPRequest();
|
||||
}
|
||||
});
|
||||
} else if (readed == -1) {
|
||||
Utilities.stageQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
onFinishLoadingFile();
|
||||
} catch (Exception e) {
|
||||
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Utilities.stageQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Utilities.stageQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
||||
}
|
||||
});
|
||||
try {
|
||||
httpConnectionStream.close();
|
||||
} catch (Exception e2) {
|
||||
e2.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startDownloadRequest() {
|
||||
if (state != 1) {
|
||||
return;
|
||||
}
|
||||
TLRPC.TL_upload_getFile req = new TLRPC.TL_upload_getFile();
|
||||
req.location = location;
|
||||
req.offset = downloadedBytes;
|
||||
req.limit = downloadChunkSize;
|
||||
requestToken = ConnectionsManager.Instance.performRpc(req, new RPCRequest.RPCRequestDelegate() {
|
||||
@Override
|
||||
public void run(TLObject response, TLRPC.TL_error error) {
|
||||
requestToken = 0;
|
||||
if (error == null) {
|
||||
TLRPC.TL_upload_file res = (TLRPC.TL_upload_file)response;
|
||||
try {
|
||||
if (res.bytes.length == 0) {
|
||||
onFinishLoadingFile();
|
||||
return;
|
||||
}
|
||||
if (key != null) {
|
||||
res.bytes = Utilities.aesIgeEncryption(res.bytes, key, iv, false, true);
|
||||
}
|
||||
if (fileOutputStream != null) {
|
||||
fileOutputStream.write(res.bytes);
|
||||
}
|
||||
downloadedBytes += res.bytes.length;
|
||||
res.bytes = null;
|
||||
if (totalBytesCount != 0) {
|
||||
delegate.didChangedLoadProgress(FileLoadOperation.this, Math.min(1.0f, (float)downloadedBytes / (float)totalBytesCount));
|
||||
}
|
||||
if (downloadedBytes % downloadChunkSize == 0 || totalBytesCount != 0 && totalBytesCount != downloadedBytes) {
|
||||
startDownloadRequest();
|
||||
} else {
|
||||
onFinishLoadingFile();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
if (error.text.contains("FILE_MIGRATE_")) {
|
||||
String errorMsg = error.text.replace("FILE_MIGRATE_", "");
|
||||
Scanner scanner = new Scanner(errorMsg);
|
||||
scanner.useDelimiter("");
|
||||
Integer val;
|
||||
try {
|
||||
val = scanner.nextInt();
|
||||
} catch (Exception e) {
|
||||
val = null;
|
||||
}
|
||||
if (val == null) {
|
||||
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
||||
} else {
|
||||
datacenter_id = val;
|
||||
startDownloadRequest();
|
||||
}
|
||||
} else if (error.text.contains("OFFSET_INVALID")) {
|
||||
if (downloadedBytes % downloadChunkSize == 0) {
|
||||
try {
|
||||
onFinishLoadingFile();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
||||
}
|
||||
} else {
|
||||
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
||||
}
|
||||
} else {
|
||||
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, new RPCRequest.RPCProgressDelegate() {
|
||||
@Override
|
||||
public void progress(int length, int progress) {
|
||||
|
||||
}
|
||||
}, null, true, RPCRequest.RPCRequestClassDownloadMedia, datacenter_id);
|
||||
}
|
||||
}
|
@ -0,0 +1,969 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Matrix;
|
||||
import android.media.ExifInterface;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import org.telegram.TL.TLRPC;
|
||||
import org.telegram.ui.Views.BackupImageView;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class FileLoader {
|
||||
public static FileLoader Instance = new FileLoader();
|
||||
public LruCache memCache;
|
||||
|
||||
private String ignoreRemoval = null;
|
||||
private HashMap<String, CacheImage> imageLoading;
|
||||
private HashMap<Integer, CacheImage> imageLoadingByKeys;
|
||||
private Queue<FileLoadOperation> operationsQueue;
|
||||
private Queue<FileLoadOperation> runningOperation;
|
||||
private final int maxConcurentLoadingOpertaionsCount = 2;
|
||||
private Queue<FileUploadOperation> uploadOperationQueue;
|
||||
private HashMap<String, FileUploadOperation> uploadOperationPaths;
|
||||
private int currentUploadOperationsCount = 0;
|
||||
private Queue<FileLoadOperation> loadOperationQueue;
|
||||
private HashMap<String, FileLoadOperation> loadOperationPaths;
|
||||
private int currentLoadOperationsCount = 0;
|
||||
public static long lastCacheOutTime = 0;
|
||||
public ConcurrentHashMap<String, Float> fileProgresses = new ConcurrentHashMap<String, Float>();
|
||||
private long lastProgressUpdateTime = 0;
|
||||
public float density = 1;
|
||||
private HashMap<String, Integer> BitmapUseCounts = new HashMap<String, Integer>();
|
||||
|
||||
int lastImageNum;
|
||||
|
||||
public static final int FileDidUpload = 10000;
|
||||
public static final int FileDidFailUpload = 10001;
|
||||
public static final int FileUploadProgressChanged = 10002;
|
||||
public static final int FileLoadProgressChanged = 10003;
|
||||
public static final int FileDidLoaded = 10004;
|
||||
public static final int FileDidFailedLoad = 10005;
|
||||
|
||||
public class VMRuntimeHack {
|
||||
private Object runtime = null;
|
||||
private Method trackAllocation = null;
|
||||
private Method trackFree = null;
|
||||
|
||||
public boolean trackAlloc(long size) {
|
||||
if (runtime == null)
|
||||
return false;
|
||||
try {
|
||||
Object res = trackAllocation.invoke(runtime, size);
|
||||
return (res instanceof Boolean) ? (Boolean)res : true;
|
||||
} catch (IllegalArgumentException e) {
|
||||
return false;
|
||||
} catch (IllegalAccessException e) {
|
||||
return false;
|
||||
} catch (InvocationTargetException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean trackFree(long size) {
|
||||
if (runtime == null)
|
||||
return false;
|
||||
try {
|
||||
Object res = trackFree.invoke(runtime, size);
|
||||
return (res instanceof Boolean) ? (Boolean)res : true;
|
||||
} catch (IllegalArgumentException e) {
|
||||
return false;
|
||||
} catch (IllegalAccessException e) {
|
||||
return false;
|
||||
} catch (InvocationTargetException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public VMRuntimeHack() {
|
||||
boolean success = false;
|
||||
try {
|
||||
Class cl = Class.forName("dalvik.system.VMRuntime");
|
||||
Method getRt = cl.getMethod("getRuntime", new Class[0]);
|
||||
runtime = getRt.invoke(null, new Object[0]);
|
||||
trackAllocation = cl.getMethod("trackExternalAllocation", new Class[] {long.class});
|
||||
trackFree = cl.getMethod("trackExternalFree", new Class[] {long.class});
|
||||
success = true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (SecurityException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (!success) {
|
||||
Log.i("tmessages", "VMRuntime hack does not work!");
|
||||
runtime = null;
|
||||
trackAllocation = null;
|
||||
trackFree = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public VMRuntimeHack runtimeHack = null;
|
||||
|
||||
private class CacheImage {
|
||||
public String key;
|
||||
public ArrayList<View> imageViewArray;
|
||||
public FileLoadOperation loadOperation;
|
||||
|
||||
public void addImageView(View imageView) {
|
||||
if (imageViewArray == null) {
|
||||
imageViewArray = new ArrayList<View>();
|
||||
}
|
||||
boolean exist = false;
|
||||
for (View v : imageViewArray) {
|
||||
if (v == imageView) {
|
||||
exist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!exist) {
|
||||
imageViewArray.add(imageView);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeImageView(View imageView) {
|
||||
if (imageViewArray != null) {
|
||||
for (int a = 0; a < imageViewArray.size(); a++) {
|
||||
View obj = imageViewArray.get(a);
|
||||
if (obj == null || obj == imageView) {
|
||||
imageViewArray.remove(a);
|
||||
a--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void callAndClear(Bitmap image) {
|
||||
if (image != null) {
|
||||
for (View imgView : imageViewArray) {
|
||||
if (imgView instanceof BackupImageView) {
|
||||
((BackupImageView)imgView).setImageBitmap(image, key);
|
||||
} else if (imgView instanceof ImageView) {
|
||||
((ImageView)imgView).setImageBitmap(image);
|
||||
}
|
||||
}
|
||||
}
|
||||
Utilities.imageLoadQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
imageViewArray.clear();
|
||||
loadOperation = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void cancelAndClear() {
|
||||
if (loadOperation != null) {
|
||||
loadOperation.cancel();
|
||||
loadOperation = null;
|
||||
}
|
||||
imageViewArray.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void incrementUseCount(String key) {
|
||||
Integer count = BitmapUseCounts.get(key);
|
||||
if (count == null) {
|
||||
BitmapUseCounts.put(key, 1);
|
||||
} else {
|
||||
BitmapUseCounts.put(key, count + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean decrementUseCount(String key) {
|
||||
Integer count = BitmapUseCounts.get(key);
|
||||
if (count == null) {
|
||||
return true;
|
||||
}
|
||||
if (count == 1) {
|
||||
BitmapUseCounts.remove(key);
|
||||
return true;
|
||||
} else {
|
||||
BitmapUseCounts.put(key, count - 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
|
||||
private CacheImage cacheImage;
|
||||
private Bitmap bitmap;
|
||||
private int data = 0;
|
||||
|
||||
public BitmapWorkerTask(ArrayList<WeakReference<View>> arr) {
|
||||
// Use a WeakReference to ensure the ImageView can be garbage collected
|
||||
imageViewReference = new WeakReference<ImageView>(imageView);
|
||||
}
|
||||
|
||||
// Decode image in background.
|
||||
@Override
|
||||
protected Bitmap doInBackground(Integer... params) {
|
||||
data = params[0];
|
||||
return decodeSampledBitmapFromResource(getResources(), data, 100, 100));
|
||||
}
|
||||
|
||||
// Once complete, see if ImageView is still around and set bitmap.
|
||||
@Override
|
||||
protected void onPostExecute(Bitmap bitmap) {
|
||||
if (imageViewReference != null && bitmap != null) {
|
||||
final ImageView imageView = imageViewReference.get();
|
||||
if (imageView != null) {
|
||||
imageView.setImageBitmap(bitmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
public FileLoader() {
|
||||
int maxMemory = (int)Runtime.getRuntime().maxMemory();
|
||||
int cacheSize = maxMemory / 10;
|
||||
density = Utilities.applicationContext.getResources().getDisplayMetrics().density;
|
||||
if (Build.VERSION.SDK_INT < 11) {
|
||||
runtimeHack = new VMRuntimeHack();
|
||||
cacheSize = 1024 * 1024 * 3;
|
||||
}
|
||||
memCache = new LruCache(cacheSize) {
|
||||
@Override
|
||||
protected int sizeOf(String key, Bitmap bitmap) {
|
||||
if(Build.VERSION.SDK_INT < 12) {
|
||||
return bitmap.getRowBytes() * bitmap.getHeight();
|
||||
} else {
|
||||
return bitmap.getByteCount();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void entryRemoved(boolean evicted, String key, Bitmap oldBitmap, Bitmap newBitmap) {
|
||||
if (ignoreRemoval != null && key != null && ignoreRemoval.equals(key)) {
|
||||
return;
|
||||
}
|
||||
Integer count = BitmapUseCounts.get(key);
|
||||
if (count == null || count == 0) {
|
||||
if (runtimeHack != null) {
|
||||
runtimeHack.trackAlloc(oldBitmap.getRowBytes() * oldBitmap.getHeight());
|
||||
}
|
||||
oldBitmap.recycle();
|
||||
}
|
||||
}
|
||||
};
|
||||
imageLoading = new HashMap<String, CacheImage>();
|
||||
imageLoadingByKeys = new HashMap<Integer, CacheImage>();
|
||||
operationsQueue = new LinkedList<FileLoadOperation>();
|
||||
runningOperation = new LinkedList<FileLoadOperation>();
|
||||
uploadOperationQueue = new LinkedList<FileUploadOperation>();
|
||||
uploadOperationPaths = new HashMap<String, FileUploadOperation>();
|
||||
loadOperationPaths = new HashMap<String, FileLoadOperation>();
|
||||
loadOperationQueue = new LinkedList<FileLoadOperation>();
|
||||
}
|
||||
|
||||
public void cancelUploadFile(final String location) {
|
||||
Utilities.fileUploadQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
FileUploadOperation operation = uploadOperationPaths.get(location);
|
||||
if (operation != null) {
|
||||
uploadOperationQueue.remove(operation);
|
||||
operation.cancel();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isInCache(String key) {
|
||||
return memCache.get(key) != null;
|
||||
}
|
||||
|
||||
public void uploadFile(final String location, final byte[] key, final byte[] iv) {
|
||||
Utilities.fileUploadQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
FileUploadOperation operation = new FileUploadOperation(location, key, iv);
|
||||
uploadOperationPaths.put(location, operation);
|
||||
operation.delegate = new FileUploadOperation.FileUploadOperationDelegate() {
|
||||
@Override
|
||||
public void didFinishUploadingFile(FileUploadOperation operation, final TLRPC.TL_inputFile inputFile, final TLRPC.TL_inputEncryptedFileUploaded inputEncryptedFile) {
|
||||
NotificationCenter.Instance.postNotificationName(FileDidUpload, location, inputFile, inputEncryptedFile);
|
||||
Utilities.fileUploadQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
uploadOperationPaths.remove(location);
|
||||
currentUploadOperationsCount--;
|
||||
if (currentUploadOperationsCount < 2) {
|
||||
FileUploadOperation operation = uploadOperationQueue.poll();
|
||||
if (operation != null) {
|
||||
currentUploadOperationsCount++;
|
||||
operation.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didFailedUploadingFile(FileUploadOperation operation) {
|
||||
fileProgresses.remove(location);
|
||||
if (operation.state != 2) {
|
||||
NotificationCenter.Instance.postNotificationName(FileDidFailUpload, location);
|
||||
}
|
||||
Utilities.fileUploadQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
uploadOperationPaths.remove(location);
|
||||
currentUploadOperationsCount--;
|
||||
if (currentUploadOperationsCount < 2) {
|
||||
FileUploadOperation operation = uploadOperationQueue.poll();
|
||||
if (operation != null) {
|
||||
currentUploadOperationsCount++;
|
||||
operation.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didChangedUploadProgress(FileUploadOperation operation, final float progress) {
|
||||
if (operation.state != 2) {
|
||||
fileProgresses.put(location, progress);
|
||||
}
|
||||
long currentTime = System.currentTimeMillis();
|
||||
if (lastProgressUpdateTime == 0 || lastProgressUpdateTime < currentTime - 500) {
|
||||
lastProgressUpdateTime = currentTime;
|
||||
Utilities.RunOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
NotificationCenter.Instance.postNotificationName(FileUploadProgressChanged, location, progress);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
if (currentUploadOperationsCount < 2) {
|
||||
currentUploadOperationsCount++;
|
||||
operation.start();
|
||||
} else {
|
||||
uploadOperationQueue.add(operation);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void cancelLoadFile(final TLRPC.Video video, final TLRPC.PhotoSize photo) {
|
||||
if (video == null && photo == null) {
|
||||
return;
|
||||
}
|
||||
Utilities.fileUploadQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String fileName = null;
|
||||
if (video != null) {
|
||||
fileName = video.dc_id + "_" + video.id + ".mp4";
|
||||
} else if (photo != null) {
|
||||
fileName = photo.location.volume_id + "_" + photo.location.local_id + ".jpg";
|
||||
}
|
||||
FileLoadOperation operation = loadOperationPaths.get(fileName);
|
||||
if (operation != null) {
|
||||
loadOperationQueue.remove(operation);
|
||||
operation.cancel();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void loadFile(final TLRPC.Video video, final TLRPC.PhotoSize photo) {
|
||||
Utilities.fileUploadQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String fileName = null;
|
||||
if (video != null) {
|
||||
fileName = video.dc_id + "_" + video.id + ".mp4";
|
||||
} else if (photo != null) {
|
||||
fileName = photo.location.volume_id + "_" + photo.location.local_id + ".jpg";
|
||||
}
|
||||
if (loadOperationPaths.containsKey(fileName)) {
|
||||
return;
|
||||
}
|
||||
FileLoadOperation operation = null;
|
||||
if (video != null) {
|
||||
operation = new FileLoadOperation(video);
|
||||
operation.totalBytesCount = video.size;
|
||||
} else if (photo != null) {
|
||||
operation = new FileLoadOperation(photo.location);
|
||||
operation.totalBytesCount = photo.size;
|
||||
operation.needBitmapCreate = false;
|
||||
}
|
||||
|
||||
final String arg1 = fileName;
|
||||
loadOperationPaths.put(fileName, operation);
|
||||
operation.delegate = new FileLoadOperation.FileLoadOperationDelegate() {
|
||||
@Override
|
||||
public void didFinishLoadingFile(FileLoadOperation operation) {
|
||||
Utilities.RunOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
NotificationCenter.Instance.postNotificationName(FileLoadProgressChanged, arg1, 1.0f);
|
||||
}
|
||||
});
|
||||
Utilities.RunOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
NotificationCenter.Instance.postNotificationName(FileDidLoaded, arg1);
|
||||
}
|
||||
});
|
||||
Utilities.fileUploadQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
loadOperationPaths.remove(arg1);
|
||||
currentLoadOperationsCount--;
|
||||
if (currentLoadOperationsCount < 2) {
|
||||
FileLoadOperation operation = loadOperationQueue.poll();
|
||||
if (operation != null) {
|
||||
currentLoadOperationsCount++;
|
||||
operation.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didFailedLoadingFile(FileLoadOperation operation) {
|
||||
fileProgresses.remove(arg1);
|
||||
if (operation.state != 2) {
|
||||
Utilities.RunOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
NotificationCenter.Instance.postNotificationName(FileDidFailedLoad, arg1);
|
||||
}
|
||||
});
|
||||
}
|
||||
Utilities.fileUploadQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
loadOperationPaths.remove(arg1);
|
||||
currentLoadOperationsCount--;
|
||||
if (currentLoadOperationsCount < 2) {
|
||||
FileLoadOperation operation = loadOperationQueue.poll();
|
||||
if (operation != null) {
|
||||
currentLoadOperationsCount++;
|
||||
operation.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didChangedLoadProgress(FileLoadOperation operation, final float progress) {
|
||||
if (operation.state != 2) {
|
||||
fileProgresses.put(arg1, progress);
|
||||
}
|
||||
long currentTime = System.currentTimeMillis();
|
||||
if (lastProgressUpdateTime == 0 || lastProgressUpdateTime < currentTime - 500) {
|
||||
lastProgressUpdateTime = currentTime;
|
||||
Utilities.RunOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
NotificationCenter.Instance.postNotificationName(FileLoadProgressChanged, arg1, progress);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
if (currentLoadOperationsCount < 2) {
|
||||
currentLoadOperationsCount++;
|
||||
operation.start();
|
||||
} else {
|
||||
loadOperationQueue.add(operation);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Bitmap imageFromKey(String key) {
|
||||
if (key == null) {
|
||||
return null;
|
||||
}
|
||||
return memCache.get(key);
|
||||
}
|
||||
|
||||
public void clearMemory() {
|
||||
memCache.evictAll();
|
||||
}
|
||||
|
||||
public void cleanDisk(boolean all) {
|
||||
/*if (all) {
|
||||
[cacheInQueue cancelAllOperations];
|
||||
[[NSFileManager defaultManager] removeItemAtPath:diskCachePath error:nil];
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL];
|
||||
} else {
|
||||
NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-cacheMaxCacheAge];
|
||||
NSDirectoryEnumerator *fileEnumerator = [[NSFileManager defaultManager] enumeratorAtPath:diskCachePath];
|
||||
for (NSString *fileName in fileEnumerator) {
|
||||
NSString *filePath = [diskCachePath stringByAppendingPathComponent:fileName];
|
||||
NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
|
||||
if ([[[attrs fileModificationDate] laterDate:expirationDate] isEqualToDate:expirationDate]) {
|
||||
[[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
public void cancelLoadingForImageView(final View imageView) {
|
||||
if (imageView == null) {
|
||||
return;
|
||||
}
|
||||
Utilities.imageLoadQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Integer num = (Integer)imageView.getTag(R.string.CacheTag);
|
||||
if (num == null) {
|
||||
num = lastImageNum;
|
||||
imageView.setTag(R.string.CacheTag, num);
|
||||
lastImageNum++;
|
||||
if (lastImageNum == Integer.MAX_VALUE) {
|
||||
lastImageNum = 0;
|
||||
}
|
||||
}
|
||||
CacheImage ei = imageLoadingByKeys.get(num);
|
||||
if (ei != null) {
|
||||
imageLoadingByKeys.remove(num);
|
||||
ei.removeImageView(imageView);
|
||||
if (ei.imageViewArray.size() == 0) {
|
||||
checkOperationsAndClear(ei.loadOperation);
|
||||
ei.cancelAndClear();
|
||||
imageLoading.remove(ei.key);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Bitmap getImageFromMemory(TLRPC.FileLocation url, View imageView, String filter, boolean cancel) {
|
||||
return getImageFromMemory(url, null, imageView, filter, cancel);
|
||||
}
|
||||
|
||||
public Bitmap getImageFromMemory(String url, View imageView, String filter, boolean cancel) {
|
||||
return getImageFromMemory(null, url, imageView, filter, cancel);
|
||||
}
|
||||
|
||||
public Bitmap getImageFromMemory(TLRPC.FileLocation url, String httpUrl, View imageView, String filter, boolean cancel) {
|
||||
if ((url == null && httpUrl == null) || imageView == null)
|
||||
return null;
|
||||
String key;
|
||||
if (httpUrl != null) {
|
||||
key = Utilities.MD5(httpUrl);
|
||||
} else if (filter == null) {
|
||||
key = url.volume_id + "_" + url.local_id;
|
||||
} else {
|
||||
key = url.volume_id + "_" + url.local_id + "@" + filter;
|
||||
}
|
||||
|
||||
Bitmap img = imageFromKey(key);
|
||||
if (img != null && cancel) {
|
||||
cancelLoadingForImageView(imageView);
|
||||
}
|
||||
return img;
|
||||
}
|
||||
|
||||
private void performReplace(String oldKey, String newKey) {
|
||||
Bitmap b = memCache.get(oldKey);
|
||||
if (b != null) {
|
||||
ignoreRemoval = oldKey;
|
||||
memCache.remove(oldKey);
|
||||
memCache.put(newKey, b);
|
||||
ignoreRemoval = null;
|
||||
}
|
||||
Integer val = BitmapUseCounts.get(oldKey);
|
||||
if (val != null) {
|
||||
BitmapUseCounts.put(newKey, val);
|
||||
BitmapUseCounts.remove(oldKey);
|
||||
}
|
||||
}
|
||||
|
||||
public void replaceImageInCache(final String oldKey, final String newKey) {
|
||||
Utilities.RunOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ArrayList<String> arr = memCache.getFilterKeys(oldKey);
|
||||
if (arr != null) {
|
||||
for (String filter : arr) {
|
||||
performReplace(oldKey + "@" + filter, newKey + "@" + filter);
|
||||
}
|
||||
} else {
|
||||
performReplace(oldKey, newKey);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void loadImage(final String url, final View imageView, final String filter, final boolean cancel) {
|
||||
loadImage(null, url, imageView, filter, cancel);
|
||||
}
|
||||
|
||||
public void loadImage(final TLRPC.FileLocation url, final View imageView, final String filter, final boolean cancel) {
|
||||
loadImage(url, null, imageView, filter, cancel);
|
||||
}
|
||||
|
||||
public void loadImage(final TLRPC.FileLocation url, final String httpUrl, final View imageView, final String filter, final boolean cancel) {
|
||||
if ((url == null && httpUrl == null) || imageView == null || (url != null && !(url instanceof TLRPC.TL_fileLocation) && !(url instanceof TLRPC.TL_fileEncryptedLocation))) {
|
||||
return;
|
||||
}
|
||||
Utilities.imageLoadQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String key;
|
||||
if (httpUrl != null) {
|
||||
key = Utilities.MD5(httpUrl);
|
||||
} else if (filter == null) {
|
||||
key = url.volume_id + "_" + url.local_id;
|
||||
} else {
|
||||
key = url.volume_id + "_" + url.local_id + "@" + filter;
|
||||
}
|
||||
|
||||
Integer num = (Integer)imageView.getTag(R.string.CacheTag);
|
||||
if (num == null) {
|
||||
num = lastImageNum;
|
||||
imageView.setTag(R.string.CacheTag, num);
|
||||
lastImageNum++;
|
||||
if (lastImageNum == Integer.MAX_VALUE)
|
||||
lastImageNum = 0;
|
||||
}
|
||||
|
||||
boolean added = false;
|
||||
boolean addToByKeys = true;
|
||||
CacheImage alreadyLoadingImage = imageLoading.get(key);
|
||||
if (cancel) {
|
||||
CacheImage ei = imageLoadingByKeys.get(num);
|
||||
if (ei != null) {
|
||||
if (ei != alreadyLoadingImage) {
|
||||
ei.removeImageView(imageView);
|
||||
if (ei.imageViewArray.size() == 0) {
|
||||
checkOperationsAndClear(ei.loadOperation);
|
||||
ei.cancelAndClear();
|
||||
imageLoading.remove(ei.key);
|
||||
}
|
||||
} else {
|
||||
addToByKeys = false;
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (alreadyLoadingImage != null && addToByKeys) {
|
||||
alreadyLoadingImage.addImageView(imageView);
|
||||
imageLoadingByKeys.put(num, alreadyLoadingImage);
|
||||
added = true;
|
||||
}
|
||||
|
||||
if (!added) {
|
||||
final CacheImage img = new CacheImage();
|
||||
img.key = key;
|
||||
img.addImageView(imageView);
|
||||
imageLoadingByKeys.put(num, img);
|
||||
imageLoading.put(key, img);
|
||||
|
||||
final String arg2 = key;
|
||||
FileLoadOperation loadOperation;
|
||||
if (httpUrl != null) {
|
||||
loadOperation = new FileLoadOperation(httpUrl);
|
||||
} else {
|
||||
loadOperation = new FileLoadOperation(url);
|
||||
}
|
||||
loadOperation.filter = filter;
|
||||
loadOperation.delegate = new FileLoadOperation.FileLoadOperationDelegate() {
|
||||
@Override
|
||||
public void didFinishLoadingFile(final FileLoadOperation operation) {
|
||||
enqueueImageProcessingOperationWithImage(operation.image, filter, arg2, img);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didFailedLoadingFile(final FileLoadOperation operation) {
|
||||
if (url != null) {
|
||||
if (url.volume_id != 0 && url.local_id != 0) {
|
||||
fileProgresses.remove(url.volume_id + "_" + url.local_id + ".jpg");
|
||||
}
|
||||
}
|
||||
Utilities.imageLoadQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (View view : img.imageViewArray) {
|
||||
Integer num = (Integer)view.getTag(R.string.CacheTag);
|
||||
imageLoadingByKeys.remove(num);
|
||||
imageLoading.remove(arg2);
|
||||
checkOperationsAndClear(operation);
|
||||
}
|
||||
}
|
||||
});
|
||||
Utilities.RunOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
img.callAndClear(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didChangedLoadProgress(FileLoadOperation operation, float progress) {
|
||||
if (url != null) {
|
||||
if (url.volume_id != 0 && url.local_id != 0) {
|
||||
fileProgresses.put(url.volume_id + "_" + url.local_id + ".jpg", progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
img.loadOperation = loadOperation;
|
||||
if (runningOperation.size() < maxConcurentLoadingOpertaionsCount) {
|
||||
loadOperation.start();
|
||||
runningOperation.add(loadOperation);
|
||||
} else {
|
||||
operationsQueue.add(loadOperation);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void checkOperationsAndClear(FileLoadOperation operation) {
|
||||
operationsQueue.remove(operation);
|
||||
runningOperation.remove(operation);
|
||||
while (runningOperation.size() < maxConcurentLoadingOpertaionsCount && operationsQueue.size() != 0) {
|
||||
FileLoadOperation loadOperation = operationsQueue.poll();
|
||||
runningOperation.add(loadOperation);
|
||||
loadOperation.start();
|
||||
}
|
||||
}
|
||||
|
||||
public void processImage(Bitmap image, View imageView, String filter, boolean cancel) {
|
||||
if (filter == null || imageView == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Integer num = (Integer)imageView.getTag(R.string.CacheTag);
|
||||
if (num == null) {
|
||||
num = lastImageNum;
|
||||
imageView.setTag(R.string.CacheTag, num);
|
||||
lastImageNum++;
|
||||
if (lastImageNum == Integer.MAX_VALUE)
|
||||
lastImageNum = 0;
|
||||
}
|
||||
|
||||
boolean added = false;
|
||||
boolean addToByKeys = true;
|
||||
CacheImage alreadyLoadingImage = imageLoading.get(filter);
|
||||
if (cancel) {
|
||||
CacheImage ei = imageLoadingByKeys.get(num);
|
||||
if (ei != null) {
|
||||
if (ei != alreadyLoadingImage) {
|
||||
ei.removeImageView(imageView);
|
||||
if (ei.imageViewArray.size() == 0) {
|
||||
checkOperationsAndClear(ei.loadOperation);
|
||||
ei.cancelAndClear();
|
||||
imageLoading.remove(ei.key);
|
||||
}
|
||||
} else {
|
||||
addToByKeys = false;
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (alreadyLoadingImage != null && addToByKeys) {
|
||||
alreadyLoadingImage.addImageView(imageView);
|
||||
imageLoadingByKeys.put(num, alreadyLoadingImage);
|
||||
added = true;
|
||||
}
|
||||
|
||||
if (!added) {
|
||||
CacheImage img = new CacheImage();
|
||||
img.key = filter;
|
||||
img.addImageView(imageView);
|
||||
imageLoadingByKeys.put(num, img);
|
||||
imageLoading.put(filter, img);
|
||||
|
||||
enqueueImageProcessingOperationWithImage(image, filter, filter, img);
|
||||
}
|
||||
}
|
||||
|
||||
void enqueueImageProcessingOperationWithImage(final Bitmap image, final String filter, final String key, final CacheImage img) {
|
||||
if (image == null || key == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Utilities.imageLoadQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (View v : img.imageViewArray) {
|
||||
Integer num = (Integer)v.getTag(R.string.CacheTag);
|
||||
imageLoadingByKeys.remove(num);
|
||||
}
|
||||
checkOperationsAndClear(img.loadOperation);
|
||||
imageLoading.remove(key);
|
||||
}
|
||||
});
|
||||
|
||||
Utilities.RunOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
img.callAndClear(image);
|
||||
if (memCache.get(key) == null) {
|
||||
memCache.put(key, image);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
/*AsyncTask
|
||||
NSBlockOperation *processingOperation = [NSBlockOperation blockOperationWithBlock:^(void) {
|
||||
if (countCores() == 1)
|
||||
[NSThread sleepForTimeInterval:0.1];
|
||||
UIImage *filterImage = [UIImage decodedImageWithImage:image andFilter:filter];
|
||||
if (!filterImage)
|
||||
filterImage = image;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (filterImage) {
|
||||
if (![memCache objectForKey:key]) {
|
||||
[memCache setObject:filterImage forKey:key];
|
||||
[memArray addObject:key];
|
||||
}
|
||||
}
|
||||
for (UIView *view in img.imageViewArray) {
|
||||
NSNumber *num = objc_getAssociatedObject(view, &VIEW_CACHE_KEY);
|
||||
[imageLoadingByKeys removeObjectForKey:num];
|
||||
}
|
||||
[img callAndClear:filterImage];
|
||||
[imageLoading removeObjectForKey:key];
|
||||
});
|
||||
}];
|
||||
[imageProcessingQueue addOperation:processingOperation];
|
||||
|
||||
*/
|
||||
public static Bitmap loadBitmap(String path, float maxWidth, float maxHeight) {
|
||||
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
|
||||
bmOptions.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFile(path, bmOptions);
|
||||
float photoW = bmOptions.outWidth;
|
||||
float photoH = bmOptions.outHeight;
|
||||
float scaleFactor = Math.max(photoW / maxWidth, photoH / maxHeight);
|
||||
if (scaleFactor < 1) {
|
||||
scaleFactor = 1;
|
||||
}
|
||||
bmOptions.inJustDecodeBounds = false;
|
||||
bmOptions.inSampleSize = (int)scaleFactor;
|
||||
|
||||
ExifInterface exif;
|
||||
Matrix matrix = null;
|
||||
try {
|
||||
exif = new ExifInterface(path);
|
||||
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
|
||||
matrix = new Matrix();
|
||||
switch (orientation) {
|
||||
case ExifInterface.ORIENTATION_ROTATE_90:
|
||||
matrix.postRotate(90);
|
||||
break;
|
||||
case ExifInterface.ORIENTATION_ROTATE_180:
|
||||
matrix.postRotate(180);
|
||||
break;
|
||||
case ExifInterface.ORIENTATION_ROTATE_270:
|
||||
matrix.postRotate(270);
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
Bitmap b;
|
||||
try {
|
||||
b = BitmapFactory.decodeFile(path, bmOptions);
|
||||
if (b != null && matrix != null) {
|
||||
b = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), matrix, true);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
FileLoader.Instance.memCache.evictAll();
|
||||
b = BitmapFactory.decodeFile(path, bmOptions);
|
||||
if (b != null && matrix != null) {
|
||||
b = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), matrix, true);
|
||||
}
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
public static TLRPC.PhotoSize scaleAndSaveImage(Bitmap bitmap, float maxWidth, float maxHeight, int quality, boolean cache) {
|
||||
if (bitmap == null) {
|
||||
return null;
|
||||
}
|
||||
float photoW = bitmap.getWidth();
|
||||
float photoH = bitmap.getHeight();
|
||||
if (photoW == 0 || photoH == 0) {
|
||||
return null;
|
||||
}
|
||||
float scaleFactor = Math.max(photoW / maxWidth, photoH / maxHeight);
|
||||
|
||||
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, (int)(photoW / scaleFactor), (int)(photoH / scaleFactor), true);
|
||||
|
||||
TLRPC.TL_fileLocation location = new TLRPC.TL_fileLocation();
|
||||
location.volume_id = Integer.MIN_VALUE;
|
||||
location.dc_id = Integer.MIN_VALUE;
|
||||
location.local_id = UserConfig.lastLocalId;
|
||||
UserConfig.lastLocalId--;
|
||||
TLRPC.PhotoSize size;
|
||||
if (!cache) {
|
||||
size = new TLRPC.TL_photoSize();
|
||||
} else {
|
||||
size = new TLRPC.TL_photoCachedSize();
|
||||
}
|
||||
size.location = location;
|
||||
size.w = (int)(photoW / scaleFactor);
|
||||
size.h = (int)(photoH / scaleFactor);
|
||||
try {
|
||||
if (!cache) {
|
||||
String fileName = location.volume_id + "_" + location.local_id + ".jpg";
|
||||
final File cacheFile = new File(Utilities.getCacheDir(), fileName);
|
||||
FileOutputStream stream = new FileOutputStream(cacheFile);
|
||||
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, quality, stream);
|
||||
size.size = (int)stream.getChannel().size();
|
||||
} else {
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, quality, stream);
|
||||
size.bytes = stream.toByteArray();
|
||||
size.size = size.bytes.length;
|
||||
}
|
||||
if (scaledBitmap != bitmap) {
|
||||
scaledBitmap.recycle();
|
||||
}
|
||||
return size;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import org.telegram.TL.TLObject;
|
||||
import org.telegram.TL.TLRPC;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Locale;
|
||||
|
||||
public class FileUploadOperation {
|
||||
private final int uploadChunkSize = 1024 * 32;
|
||||
private String uploadingFilePath;
|
||||
public int state = 0;
|
||||
private byte[] readBuffer = new byte[uploadChunkSize];
|
||||
public FileUploadOperationDelegate delegate;
|
||||
private long requestToken = 0;
|
||||
private int currentPartNum = 0;
|
||||
private long currentFileId;
|
||||
private boolean isLastPart = false;
|
||||
private long totalFileSize = 0;
|
||||
private long currentUploaded = 0;
|
||||
private byte[] key;
|
||||
private byte[] iv;
|
||||
private int fingerprint;
|
||||
FileInputStream stream;
|
||||
MessageDigest mdEnc = null;
|
||||
|
||||
public static interface FileUploadOperationDelegate {
|
||||
public abstract void didFinishUploadingFile(FileUploadOperation operation, TLRPC.TL_inputFile inputFile, TLRPC.TL_inputEncryptedFileUploaded inputEncryptedFile);
|
||||
public abstract void didFailedUploadingFile(FileUploadOperation operation);
|
||||
public abstract void didChangedUploadProgress(FileUploadOperation operation, float progress);
|
||||
}
|
||||
|
||||
public FileUploadOperation(String location, byte[] keyarr, byte[] ivarr) {
|
||||
uploadingFilePath = location;
|
||||
if (ivarr != null && keyarr != null) {
|
||||
iv = new byte[32];
|
||||
key = keyarr;
|
||||
System.arraycopy(ivarr, 0, iv, 0, 32);
|
||||
try {
|
||||
java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
|
||||
byte[] arr = new byte[64];
|
||||
System.arraycopy(key, 0, arr, 0, 32);
|
||||
System.arraycopy(iv, 0, arr, 32, 32);
|
||||
byte[] digest = md.digest(arr);
|
||||
byte[] fingerprintBytes = new byte[4];
|
||||
for (int a = 0; a < 4; a++) {
|
||||
fingerprintBytes[a] = (byte)(digest[a] ^ digest[a + 4]);
|
||||
}
|
||||
fingerprint = Utilities.bytesToInt(fingerprintBytes);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
currentFileId = (long)(MessagesController.random.nextDouble() * Long.MAX_VALUE);
|
||||
try {
|
||||
mdEnc = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (state != 0) {
|
||||
return;
|
||||
}
|
||||
state = 1;
|
||||
startUploadRequest();
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
if (state != 1) {
|
||||
return;
|
||||
}
|
||||
state = 2;
|
||||
if (requestToken != 0) {
|
||||
ConnectionsManager.Instance.cancelRpc(requestToken, true);
|
||||
}
|
||||
delegate.didFailedUploadingFile(this);
|
||||
}
|
||||
|
||||
private void startUploadRequest() {
|
||||
if (state != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
TLRPC.TL_upload_saveFilePart req = new TLRPC.TL_upload_saveFilePart();
|
||||
req.file_part = currentPartNum;
|
||||
req.file_id = currentFileId;
|
||||
try {
|
||||
if (stream == null) {
|
||||
File cacheFile = new File(uploadingFilePath);
|
||||
stream = new FileInputStream(cacheFile);
|
||||
totalFileSize = cacheFile.length();
|
||||
}
|
||||
int readed = stream.read(readBuffer);
|
||||
int toAdd = 0;
|
||||
if (key != null && readed % 16 != 0) {
|
||||
toAdd += 16 - readed % 16;
|
||||
}
|
||||
byte[] sendBuffer = new byte[readed + toAdd];
|
||||
if (readed != uploadChunkSize) {
|
||||
isLastPart = true;
|
||||
}
|
||||
System.arraycopy(readBuffer, 0, sendBuffer, 0, readed);
|
||||
if (key != null) {
|
||||
sendBuffer = Utilities.aesIgeEncryption(sendBuffer, key, iv, true, true);
|
||||
}
|
||||
mdEnc.update(sendBuffer, 0, readed + toAdd);
|
||||
req.bytes = sendBuffer;
|
||||
currentUploaded += readed;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
delegate.didFailedUploadingFile(this);
|
||||
return;
|
||||
}
|
||||
requestToken = ConnectionsManager.Instance.performRpc(req, new RPCRequest.RPCRequestDelegate() {
|
||||
@Override
|
||||
public void run(TLObject response, TLRPC.TL_error error) {
|
||||
requestToken = 0;
|
||||
if (error == null) {
|
||||
if (response instanceof TLRPC.TL_boolTrue) {
|
||||
currentPartNum++;
|
||||
delegate.didChangedUploadProgress(FileUploadOperation.this, (float)currentUploaded / (float)totalFileSize);
|
||||
if (isLastPart) {
|
||||
state = 3;
|
||||
if (key == null) {
|
||||
TLRPC.TL_inputFile result = new TLRPC.TL_inputFile();
|
||||
result.md5_checksum = String.format(Locale.US, "%32s", new BigInteger(1, mdEnc.digest()).toString(16)).replace(' ', '0');
|
||||
result.parts = currentPartNum;
|
||||
result.id = currentFileId;
|
||||
result.name = uploadingFilePath.substring(uploadingFilePath.lastIndexOf("/") + 1);
|
||||
delegate.didFinishUploadingFile(FileUploadOperation.this, result, null);
|
||||
} else {
|
||||
TLRPC.TL_inputEncryptedFileUploaded result = new TLRPC.TL_inputEncryptedFileUploaded();
|
||||
result.md5_checksum = String.format(Locale.US, "%32s", new BigInteger(1, mdEnc.digest()).toString(16)).replace(' ', '0');
|
||||
result.parts = currentPartNum;
|
||||
result.id = currentFileId;
|
||||
result.key_fingerprint = fingerprint;
|
||||
delegate.didFinishUploadingFile(FileUploadOperation.this, null, result);
|
||||
}
|
||||
} else {
|
||||
startUploadRequest();
|
||||
}
|
||||
} else {
|
||||
delegate.didFailedUploadingFile(FileUploadOperation.this);
|
||||
}
|
||||
} else {
|
||||
delegate.didFailedUploadingFile(FileUploadOperation.this);
|
||||
}
|
||||
}
|
||||
}, new RPCRequest.RPCProgressDelegate() {
|
||||
@Override
|
||||
public void progress(int length, int progress) {
|
||||
|
||||
}
|
||||
}, null, true, RPCRequest.RPCRequestClassUploadMedia, ConnectionsManager.DEFAULT_DATACENTER_ID);
|
||||
}
|
||||
}
|
@ -0,0 +1,233 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.gcm.GoogleCloudMessaging;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.telegram.TL.TLRPC;
|
||||
import org.telegram.ui.ApplicationLoader;
|
||||
import org.telegram.ui.LaunchActivity;
|
||||
|
||||
public class GcmBroadcastReceiver extends BroadcastReceiver {
|
||||
|
||||
public static final int NOTIFICATION_ID = 1;
|
||||
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
if (ConnectionsManager.DEBUG_VERSION) {
|
||||
Log.i("tmessages", "GCM received intent: " + intent);
|
||||
}
|
||||
setResultCode(Activity.RESULT_OK);
|
||||
|
||||
if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) {
|
||||
SharedPreferences preferences = context.getSharedPreferences("Notifications", Context.MODE_PRIVATE);
|
||||
boolean globalEnabled = preferences.getBoolean("EnableAll", true);
|
||||
if (!globalEnabled) {
|
||||
if (ConnectionsManager.DEBUG_VERSION) {
|
||||
Log.i("tmessages", "GCM disabled");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
|
||||
String messageType = gcm.getMessageType(intent);
|
||||
sendNotification(context, intent.getExtras());
|
||||
}
|
||||
});
|
||||
thread.setPriority(Thread.MAX_PRIORITY);
|
||||
thread.start();
|
||||
} else if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) {
|
||||
if (ConnectionsManager.DEBUG_VERSION) {
|
||||
String registration = intent.getStringExtra("registration_id");
|
||||
if (intent.getStringExtra("error") != null) {
|
||||
Log.e("tmessages", "Registration failed, should try again later.");
|
||||
} else if (intent.getStringExtra("unregistered") != null) {
|
||||
Log.e("tmessages", "unregistration done, new messages from the authorized sender will be rejected");
|
||||
} else if (registration != null) {
|
||||
Log.e("tmessages", "registration id = " + registration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendNotification(Context context, Bundle extras) {
|
||||
if (!UserConfig.clientActivated || context == null || extras == null) {
|
||||
return;
|
||||
}
|
||||
if (ConnectionsManager.DEBUG_VERSION) {
|
||||
Log.d("tmessages", "received push " + extras);
|
||||
}
|
||||
SharedPreferences preferences = context.getSharedPreferences("Notifications", Context.MODE_PRIVATE);
|
||||
|
||||
boolean groupEnabled = preferences.getBoolean("EnableGroup", true);
|
||||
boolean globalVibrate = preferences.getBoolean("EnableVibrateAll", true);
|
||||
boolean groupVibrate = preferences.getBoolean("EnableVibrateGroup", true);
|
||||
|
||||
|
||||
if (ApplicationLoader.Instance != null && (ApplicationLoader.lastPauseTime == 0 || ApplicationLoader.lastPauseTime > System.currentTimeMillis() - 200)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String defaultPath = null;
|
||||
Uri defaultUri = Settings.System.DEFAULT_NOTIFICATION_URI;
|
||||
if (defaultUri != null) {
|
||||
defaultPath = defaultUri.getPath();
|
||||
}
|
||||
|
||||
String globalSound = preferences.getString("GlobalSoundPath", defaultPath);
|
||||
String chatSound = preferences.getString("GroupSoundPath", defaultPath);
|
||||
String userSoundPath = null;
|
||||
String chatSoundPath = null;
|
||||
|
||||
NotificationManager mNotificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
Intent intent = new Intent(context, LaunchActivity.class);
|
||||
String msg = extras.getString("message");
|
||||
|
||||
try {
|
||||
String to_id = extras.getString("user_id");
|
||||
int to = Integer.parseInt(to_id);
|
||||
if (to != UserConfig.clientUserId) {
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
int chat_id = 0;
|
||||
int user_id = 0;
|
||||
TLRPC.User user = null;
|
||||
TLRPC.Chat chat = null;
|
||||
String custom = extras.getString("custom");
|
||||
try {
|
||||
if (custom != null) {
|
||||
JSONObject obj = new JSONObject(custom);
|
||||
if (obj.has("chat_id")) {
|
||||
Object object = obj.get("chat_id");
|
||||
if (object instanceof Integer) {
|
||||
chat_id = (Integer)object;
|
||||
} else if (object instanceof String) {
|
||||
chat_id = Integer.parseInt((String)object);
|
||||
}
|
||||
if (chat_id != 0) {
|
||||
intent.putExtra("chatId", chat_id);
|
||||
}
|
||||
} else if (obj.has("from_id")) {
|
||||
Object object = obj.get("from_id");
|
||||
if (object instanceof Integer) {
|
||||
user_id = (Integer)object;
|
||||
} else if (object instanceof String) {
|
||||
user_id = Integer.parseInt((String)object);
|
||||
}
|
||||
if (user_id != 0) {
|
||||
intent.putExtra("userId", user_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (user_id != 0) {
|
||||
String key = "notify_" + user_id;
|
||||
boolean value = preferences.getBoolean(key, true);
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
userSoundPath = preferences.getString("sound_path_" + user_id, null);
|
||||
}
|
||||
if (chat_id != 0) {
|
||||
if (!groupEnabled) {
|
||||
return;
|
||||
}
|
||||
String key = "notify_" + (-chat_id);
|
||||
boolean value = preferences.getBoolean(key, true);
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
chatSoundPath = preferences.getString("sound_chat_path_" + chat_id, null);
|
||||
}
|
||||
|
||||
boolean needVibrate;
|
||||
boolean needPreview = true;
|
||||
String choosenSoundPath = null;
|
||||
|
||||
if (chat_id != 0) {
|
||||
needVibrate = groupVibrate;
|
||||
} else {
|
||||
needVibrate = globalVibrate;
|
||||
}
|
||||
|
||||
if (user_id != 0) {
|
||||
if (userSoundPath != null) {
|
||||
choosenSoundPath = userSoundPath;
|
||||
} else if (globalSound != null) {
|
||||
choosenSoundPath = globalSound;
|
||||
}
|
||||
} else if (chat_id != 0) {
|
||||
if (chatSoundPath != null) {
|
||||
choosenSoundPath = chatSoundPath;
|
||||
} else if (chatSound != null) {
|
||||
choosenSoundPath = chatSound;
|
||||
}
|
||||
}
|
||||
|
||||
intent.setAction("com.tmessages.openchat" + Math.random() + Integer.MAX_VALUE);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
//intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_ONE_SHOT);
|
||||
|
||||
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
|
||||
.setContentTitle(Utilities.applicationContext.getString(R.string.AppName))
|
||||
.setSmallIcon(R.drawable.notification)
|
||||
.setStyle(new NotificationCompat.BigTextStyle()
|
||||
.bigText(msg))
|
||||
.setContentText(msg)
|
||||
.setAutoCancel(true);
|
||||
|
||||
if (needPreview) {
|
||||
mBuilder.setTicker(msg);
|
||||
}
|
||||
if (needVibrate) {
|
||||
mBuilder.setVibrate(new long[]{0, 100, 0, 100});
|
||||
}
|
||||
if (choosenSoundPath != null && !choosenSoundPath.equals("NoSound")) {
|
||||
if (choosenSoundPath.equals(defaultPath)) {
|
||||
mBuilder.setSound(defaultUri);
|
||||
} else {
|
||||
mBuilder.setSound(Uri.parse(choosenSoundPath));
|
||||
}
|
||||
}
|
||||
|
||||
mBuilder.setContentIntent(contentIntent);
|
||||
mNotificationManager.cancel(NOTIFICATION_ID);
|
||||
Notification notification = mBuilder.build();
|
||||
notification.ledARGB = 0xff00ff00;
|
||||
notification.ledOnMS = 1000;
|
||||
notification.ledOffMS = 1000;
|
||||
notification.flags |= Notification.FLAG_SHOW_LIGHTS;
|
||||
mNotificationManager.notify(NOTIFICATION_ID, notification);
|
||||
}
|
||||
}
|
@ -0,0 +1,573 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.telegram.TL.TLClassStore;
|
||||
import org.telegram.TL.TLObject;
|
||||
import org.telegram.TL.TLRPC;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
|
||||
public class HandshakeAction extends Action implements TcpConnection.TcpConnectionDelegate {
|
||||
|
||||
private ArrayList<Long> processedMessageIds;
|
||||
|
||||
private byte[] authNonce;
|
||||
private byte[] authServerNonce;
|
||||
private byte[] authNewNonce;
|
||||
|
||||
private byte[] authKey;
|
||||
private byte[] authKeyId;
|
||||
|
||||
private boolean processedPQRes;
|
||||
|
||||
private byte[] reqPQMsgData;
|
||||
private byte[] reqDHMsgData;
|
||||
private byte[] setClientDHParamsMsgData;
|
||||
private boolean wasDisconnect = false;
|
||||
|
||||
private long lastOutgoingMessageId;
|
||||
|
||||
int timeDifference;
|
||||
ServerSalt serverSalt;
|
||||
public Datacenter datacenter;
|
||||
|
||||
public HandshakeAction(Datacenter datacenter) {
|
||||
this.datacenter = datacenter;
|
||||
}
|
||||
|
||||
public void execute(HashMap params) {
|
||||
Log.d("tmessages", String.format("Begin handshake with DC%d", datacenter.datacenterId));
|
||||
beginHandshake(true);
|
||||
}
|
||||
|
||||
void beginHandshake(boolean dropConnection) {
|
||||
if (datacenter.connection == null) {
|
||||
datacenter.connection = new TcpConnection(datacenter.address, datacenter.port);
|
||||
datacenter.connection.delegate = this;
|
||||
datacenter.connection.datacenterId = datacenter.datacenterId;
|
||||
datacenter.connection.transportRequestClass = RPCRequest.RPCRequestClassGeneric;
|
||||
}
|
||||
|
||||
processedMessageIds = new ArrayList<Long>();
|
||||
authNonce = null;
|
||||
authServerNonce = null;
|
||||
authNewNonce = null;
|
||||
authKey = null;
|
||||
authKeyId = null;
|
||||
processedPQRes = false;
|
||||
reqPQMsgData = null;
|
||||
reqDHMsgData = null;
|
||||
setClientDHParamsMsgData = null;
|
||||
|
||||
if (dropConnection) {
|
||||
datacenter.connection.suspendConnection(true);
|
||||
datacenter.connection.connect();
|
||||
}
|
||||
|
||||
TLRPC.TL_req_pq reqPq = new TLRPC.TL_req_pq();
|
||||
byte[] nonceBytes = new byte[16];
|
||||
for (int a = 0; a < 16; a++) {
|
||||
nonceBytes[a] = (byte)(MessagesController.random.nextDouble() * 255);
|
||||
}
|
||||
authNonce = reqPq.nonce = nonceBytes;
|
||||
reqPQMsgData = sendMessageData(reqPq, generateMessageId());
|
||||
}
|
||||
|
||||
final Integer lock = 1;
|
||||
static ArrayList<HashMap<String, Object>> serverPublicKeys = null;
|
||||
HashMap<String, Object> selectPublicKey(ArrayList<Long> fingerprints) {
|
||||
synchronized (lock) {
|
||||
if (serverPublicKeys == null) {
|
||||
serverPublicKeys = new ArrayList<HashMap<String, Object>>();
|
||||
HashMap<String, Object> map;
|
||||
|
||||
map = new HashMap<String, Object>();
|
||||
map.put("key", new BigInteger[]{
|
||||
new BigInteger("c150023e2f70db7985ded064759cfecf0af328e69a41daf4d6f01b538135" +
|
||||
"a6f91f8f8b2a0ec9ba9720ce352efcf6c5680ffc424bd634864902de0b4bd6d49f4e580230e" +
|
||||
"3ae97d95c8b19442b3c0a10d8f5633fecedd6926a7f6dab0ddb7d457f9ea81b8465fcd6fffe" +
|
||||
"ed114011df91c059caedaf97625f6c96ecc74725556934ef781d866b34f011fce4d835a0901" +
|
||||
"96e9a5f0e4449af7eb697ddb9076494ca5f81104a305b6dd27665722c46b60e5df680fb16b2" +
|
||||
"10607ef217652e60236c255f6a28315f4083a96791d7214bf64c1df4fd0db1944fb26a2a570" +
|
||||
"31b32eee64ad15a8ba68885cde74a5bfc920f6abf59ba5c75506373e7130f9042da922179251f", 16),
|
||||
new BigInteger("010001", 16)});
|
||||
map.put("fingerprint", 0xc3b42b026ce86b21L);
|
||||
serverPublicKeys.add(map);
|
||||
}
|
||||
}
|
||||
|
||||
for (HashMap<String, Object> keyDesc : serverPublicKeys) {
|
||||
long keyFingerprint = (Long)keyDesc.get("fingerprint");
|
||||
for (long nFingerprint : fingerprints) {
|
||||
if (nFingerprint == keyFingerprint) {
|
||||
return keyDesc;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
long generateMessageId() {
|
||||
long messageId = (long)((((double)System.currentTimeMillis()) * 4294967296.0) / 1000.0);
|
||||
if (messageId <= lastOutgoingMessageId) {
|
||||
messageId = lastOutgoingMessageId + 1;
|
||||
}
|
||||
while (messageId % 4 != 0) {
|
||||
messageId++;
|
||||
}
|
||||
|
||||
lastOutgoingMessageId = messageId;
|
||||
return messageId;
|
||||
}
|
||||
|
||||
byte[] sendMessageData(TLObject message, long messageId) {
|
||||
byte[] messageData;
|
||||
SerializedData innerOs = new SerializedData();
|
||||
message.serializeToStream(innerOs);
|
||||
messageData = innerOs.toByteArray();
|
||||
|
||||
SerializedData messageOs = new SerializedData();
|
||||
messageOs.writeInt64(0);
|
||||
messageOs.writeInt64(messageId);
|
||||
messageOs.writeInt32(messageData.length);
|
||||
messageOs.writeRaw(messageData);
|
||||
|
||||
byte[] transportData = messageOs.toByteArray();
|
||||
|
||||
datacenter.connection.sendData(transportData, false, false);
|
||||
|
||||
return transportData;
|
||||
}
|
||||
|
||||
void processMessage(TLObject message, long messageId) {
|
||||
if (message instanceof TLRPC.TL_resPQ) {
|
||||
if (processedPQRes) {
|
||||
TLRPC.TL_msgs_ack msgsAck = new TLRPC.TL_msgs_ack();
|
||||
msgsAck.msg_ids = new ArrayList<Long>();
|
||||
msgsAck.msg_ids.add(messageId);
|
||||
sendMessageData(msgsAck, generateMessageId());
|
||||
return;
|
||||
}
|
||||
|
||||
processedPQRes = true;
|
||||
final TLRPC.TL_resPQ resPq = (TLRPC.TL_resPQ)message;
|
||||
if (Arrays.equals(authNonce, resPq.nonce)) {
|
||||
final HashMap<String, Object> publicKey = selectPublicKey(resPq.server_public_key_fingerprints);
|
||||
if (publicKey == null) {
|
||||
Log.e("tmessages", "***** Couldn't find valid server public key");
|
||||
beginHandshake(false);
|
||||
return;
|
||||
}
|
||||
|
||||
authServerNonce = resPq.server_nonce;
|
||||
|
||||
ByteBuffer data = ByteBuffer.wrap(resPq.pq);
|
||||
final long pqf = data.getLong();
|
||||
final long messageIdf = messageId;
|
||||
Utilities.globalQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final Utilities.TPFactorizedValue factorizedPq = Utilities.getFactorizedValue(pqf);
|
||||
|
||||
Utilities.stageQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ByteBuffer pBytes = ByteBuffer.allocate(4);
|
||||
pBytes.putInt((int)factorizedPq.p);
|
||||
byte[] pData = pBytes.array();
|
||||
|
||||
ByteBuffer qBytes = ByteBuffer.allocate(4);
|
||||
qBytes.putInt((int)factorizedPq.q);
|
||||
byte[] qData = qBytes.array();
|
||||
|
||||
TLRPC.TL_req_DH_params reqDH = new TLRPC.TL_req_DH_params();
|
||||
reqDH.nonce = authNonce;
|
||||
reqDH.server_nonce = authServerNonce;
|
||||
reqDH.p = pData;
|
||||
reqDH.q = qData;
|
||||
reqDH.public_key_fingerprint = (Long)publicKey.get("fingerprint");
|
||||
|
||||
SerializedData os = new SerializedData();
|
||||
|
||||
TLRPC.TL_p_q_inner_data innerData = new TLRPC.TL_p_q_inner_data();
|
||||
innerData.nonce = authNonce;
|
||||
innerData.server_nonce = authServerNonce;
|
||||
innerData.pq = resPq.pq;
|
||||
innerData.p = reqDH.p;
|
||||
innerData.q = reqDH.q;
|
||||
|
||||
byte[] nonceBytes = new byte[32];
|
||||
for (int a = 0; a < 32; a++) {
|
||||
nonceBytes[a] = (byte)(MessagesController.random.nextDouble() * 255);
|
||||
}
|
||||
innerData.new_nonce = authNewNonce = nonceBytes;
|
||||
innerData.serializeToStream(os);
|
||||
|
||||
byte[] innerDataBytes = os.toByteArray();
|
||||
|
||||
SerializedData dataWithHash = new SerializedData();
|
||||
dataWithHash.writeRaw(Utilities.computeSHA1(innerDataBytes));
|
||||
dataWithHash.writeRaw(innerDataBytes);
|
||||
while (dataWithHash.length() < 255) {
|
||||
dataWithHash.writeByte(0);
|
||||
}
|
||||
|
||||
byte[] encryptedBytes = Utilities.encryptWithRSA((BigInteger[])publicKey.get("key"), dataWithHash.toByteArray());
|
||||
SerializedData encryptedData = new SerializedData();
|
||||
encryptedData.writeRaw(encryptedBytes);
|
||||
if (encryptedData.length() < 256) {
|
||||
SerializedData newEncryptedData = new SerializedData();
|
||||
for (int i = 0; i < 256 - encryptedData.length(); i++) {
|
||||
newEncryptedData.writeByte(0);
|
||||
}
|
||||
newEncryptedData.writeRaw(encryptedData.toByteArray());
|
||||
encryptedData = newEncryptedData;
|
||||
}
|
||||
reqDH.encrypted_data = encryptedData.toByteArray();
|
||||
|
||||
TLRPC.TL_msgs_ack msgsAck = new TLRPC.TL_msgs_ack();
|
||||
msgsAck.msg_ids = new ArrayList<Long>();
|
||||
msgsAck.msg_ids.add(messageIdf);
|
||||
sendMessageData(msgsAck, generateMessageId());
|
||||
|
||||
reqPQMsgData = null;
|
||||
reqDHMsgData = sendMessageData(reqDH, generateMessageId());
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Log.e("tmessages", "***** Error: invalid handshake nonce");
|
||||
beginHandshake(false);
|
||||
}
|
||||
} else if (message instanceof TLRPC.Server_DH_Params) {
|
||||
if (message instanceof TLRPC.TL_server_DH_params_ok) {
|
||||
TLRPC.TL_server_DH_params_ok serverDhParams = (TLRPC.TL_server_DH_params_ok)message;
|
||||
|
||||
SerializedData tmpAesKey = new SerializedData();
|
||||
|
||||
SerializedData newNonceAndServerNonce = new SerializedData();
|
||||
newNonceAndServerNonce.writeRaw(authNewNonce);
|
||||
newNonceAndServerNonce.writeRaw(authServerNonce);
|
||||
|
||||
SerializedData serverNonceAndNewNonce = new SerializedData();
|
||||
serverNonceAndNewNonce.writeRaw(authServerNonce);
|
||||
serverNonceAndNewNonce.writeRaw(authNewNonce);
|
||||
tmpAesKey.writeRaw(Utilities.computeSHA1(newNonceAndServerNonce.toByteArray()));
|
||||
|
||||
byte[] serverNonceAndNewNonceHash = Utilities.computeSHA1(serverNonceAndNewNonce.toByteArray());
|
||||
byte[] serverNonceAndNewNonceHash0_12 = new byte[12];
|
||||
System.arraycopy(serverNonceAndNewNonceHash, 0, serverNonceAndNewNonceHash0_12, 0, 12);
|
||||
|
||||
tmpAesKey.writeRaw(serverNonceAndNewNonceHash0_12);
|
||||
|
||||
SerializedData tmpAesIv = new SerializedData();
|
||||
|
||||
byte[] serverNonceAndNewNonceHash12_8 = new byte[8];
|
||||
System.arraycopy(serverNonceAndNewNonceHash, 12, serverNonceAndNewNonceHash12_8, 0, 8);
|
||||
tmpAesIv.writeRaw(serverNonceAndNewNonceHash12_8);
|
||||
|
||||
SerializedData newNonceAndNewNonce = new SerializedData();
|
||||
newNonceAndNewNonce.writeRaw(authNewNonce);
|
||||
newNonceAndNewNonce.writeRaw(authNewNonce);
|
||||
tmpAesIv.writeRaw(Utilities.computeSHA1(newNonceAndNewNonce.toByteArray()));
|
||||
|
||||
byte[] newNonce0_4 = new byte[4];
|
||||
System.arraycopy(authNewNonce, 0, newNonce0_4, 0, 4);
|
||||
tmpAesIv.writeRaw(newNonce0_4);
|
||||
|
||||
byte[] answerWithHash = Utilities.aesIgeEncryption(serverDhParams.encrypted_answer, tmpAesKey.toByteArray(), tmpAesIv.toByteArray(), false, false);
|
||||
byte[] answerHash = new byte[20];
|
||||
System.arraycopy(answerWithHash, 0, answerHash, 0, 20);
|
||||
|
||||
byte[] answerData = new byte[answerWithHash.length - 20];
|
||||
System.arraycopy(answerWithHash, 20, answerData, 0, answerWithHash.length - 20);
|
||||
boolean hashVerified = false;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
byte[] computedAnswerHash = Utilities.computeSHA1(answerData);
|
||||
if (Arrays.equals(computedAnswerHash, answerHash)) {
|
||||
hashVerified = true;
|
||||
break;
|
||||
}
|
||||
byte[] answerData2 = new byte[answerData.length - 1];
|
||||
System.arraycopy(answerData, 0, answerData2, 0, answerData.length - 1);
|
||||
answerData = answerData2;
|
||||
}
|
||||
|
||||
if (!hashVerified) {
|
||||
Log.e("tmessages", "***** Couldn't decode DH params");
|
||||
beginHandshake(false);
|
||||
return;
|
||||
}
|
||||
|
||||
SerializedData answerIs = new SerializedData(answerData);
|
||||
int constructor = answerIs.readInt32();
|
||||
TLRPC.TL_server_DH_inner_data dhInnerData = (TLRPC.TL_server_DH_inner_data)TLClassStore.Instance().TLdeserialize(answerIs, constructor);
|
||||
|
||||
if (!(dhInnerData instanceof TLRPC.TL_server_DH_inner_data)) {
|
||||
Log.e("tmessages", "***** Couldn't parse decoded DH params");
|
||||
beginHandshake(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Arrays.equals(authNonce, dhInnerData.nonce)) {
|
||||
Log.e("tmessages", "***** Invalid DH nonce");
|
||||
beginHandshake(false);
|
||||
return;
|
||||
}
|
||||
if (!Arrays.equals(authServerNonce, dhInnerData.server_nonce)) {
|
||||
Log.e("tmessages", "***** Invalid DH server nonce");
|
||||
beginHandshake(false);
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] b = new byte[256];
|
||||
for (int a = 0; a < 256; a++) {
|
||||
b[a] = (byte)(MessagesController.random.nextDouble() * 255);
|
||||
}
|
||||
|
||||
BigInteger i_g_b = BigInteger.valueOf(dhInnerData.g);
|
||||
i_g_b = i_g_b.modPow(new BigInteger(1, b), new BigInteger(1, dhInnerData.dh_prime));
|
||||
byte[] g_b = i_g_b.toByteArray();
|
||||
|
||||
BigInteger i_authKey = new BigInteger(1, dhInnerData.g_a);
|
||||
i_authKey = i_authKey.modPow(new BigInteger(1, b), new BigInteger(1, dhInnerData.dh_prime));
|
||||
|
||||
authKey = i_authKey.toByteArray();
|
||||
if (authKey.length > 256) {
|
||||
byte[] correctedAuth = new byte[256];
|
||||
System.arraycopy(authKey, 1, correctedAuth, 0, 256);
|
||||
authKey = correctedAuth;
|
||||
} else if (authKey.length < 256) {
|
||||
byte[] correctedAuth = new byte[256];
|
||||
System.arraycopy(authKey, 0, correctedAuth, 256 - authKey.length, authKey.length);
|
||||
for (int a = 0; a < 256 - authKey.length; a++) {
|
||||
authKey[a] = 0;
|
||||
}
|
||||
authKey = correctedAuth;
|
||||
}
|
||||
byte[] authKeyHash = Utilities.computeSHA1(authKey);
|
||||
authKeyId = new byte[8];
|
||||
System.arraycopy(authKeyHash, authKeyHash.length - 8, authKeyId, 0, 8);
|
||||
|
||||
SerializedData serverSaltData = new SerializedData();
|
||||
for (int i = 7; i >= 0; i--) {
|
||||
byte a_ = authNewNonce[i];
|
||||
byte b_ = authServerNonce[i];
|
||||
byte x = (byte)(a_ ^ b_);
|
||||
serverSaltData.writeByte(x);
|
||||
}
|
||||
ByteBuffer saltBuffer = ByteBuffer.wrap(serverSaltData.toByteArray());
|
||||
|
||||
timeDifference = dhInnerData.server_time - (int)(System.currentTimeMillis() / 1000);
|
||||
|
||||
serverSalt = new ServerSalt();
|
||||
serverSalt.validSince = (int)(System.currentTimeMillis() / 1000) + timeDifference;
|
||||
serverSalt.validUntil = (int)(System.currentTimeMillis() / 1000) + timeDifference + 30 * 60;
|
||||
serverSalt.value = saltBuffer.getLong();
|
||||
|
||||
if (ConnectionsManager.DEBUG_VERSION) {
|
||||
Log.d("tmessages", String.format(Locale.US, "===== Time difference: %d", timeDifference));
|
||||
}
|
||||
|
||||
TLRPC.TL_client_DH_inner_data clientInnerData = new TLRPC.TL_client_DH_inner_data();
|
||||
clientInnerData.nonce = authNonce;
|
||||
clientInnerData.server_nonce = authServerNonce;
|
||||
clientInnerData.g_b = g_b;
|
||||
clientInnerData.retry_id = 0;
|
||||
SerializedData os = new SerializedData();
|
||||
clientInnerData.serializeToStream(os);
|
||||
byte[] clientInnerDataBytes = os.toByteArray();
|
||||
|
||||
SerializedData clientDataWithHash = new SerializedData();
|
||||
clientDataWithHash.writeRaw(Utilities.computeSHA1(clientInnerDataBytes));
|
||||
clientDataWithHash.writeRaw(clientInnerDataBytes);
|
||||
while (clientDataWithHash.length() % 16 != 0) {
|
||||
clientDataWithHash.writeByte(0);
|
||||
}
|
||||
|
||||
TLRPC.TL_set_client_DH_params setClientDhParams = new TLRPC.TL_set_client_DH_params();
|
||||
setClientDhParams.nonce = authNonce;
|
||||
setClientDhParams.server_nonce = authServerNonce;
|
||||
setClientDhParams.encrypted_data = Utilities.aesIgeEncryption(clientDataWithHash.toByteArray(), tmpAesKey.toByteArray(), tmpAesIv.toByteArray(), true, false);
|
||||
|
||||
TLRPC.TL_msgs_ack msgsAck = new TLRPC.TL_msgs_ack();
|
||||
msgsAck.msg_ids = new ArrayList<Long>();
|
||||
msgsAck.msg_ids.add(messageId);
|
||||
sendMessageData(msgsAck, generateMessageId());
|
||||
|
||||
reqDHMsgData = null;
|
||||
setClientDHParamsMsgData = sendMessageData(setClientDhParams, generateMessageId());
|
||||
} else {
|
||||
Log.e("tmessages", "***** Couldn't set DH params");
|
||||
beginHandshake(false);
|
||||
}
|
||||
} else if (message instanceof TLRPC.Set_client_DH_params_answer) {
|
||||
TLRPC.Set_client_DH_params_answer dhAnswer = (TLRPC.Set_client_DH_params_answer)message;
|
||||
|
||||
if (!Arrays.equals(authNonce, dhAnswer.nonce)) {
|
||||
Log.e("tmessages", "***** Invalid DH answer nonce");
|
||||
beginHandshake(false);
|
||||
return;
|
||||
}
|
||||
if (!Arrays.equals(authServerNonce, dhAnswer.server_nonce)) {
|
||||
Log.e("tmessages", "***** Invalid DH answer server nonce");
|
||||
beginHandshake(false);
|
||||
return;
|
||||
}
|
||||
|
||||
reqDHMsgData = null;
|
||||
|
||||
TLRPC.TL_msgs_ack msgsAck = new TLRPC.TL_msgs_ack();
|
||||
msgsAck.msg_ids = new ArrayList<Long>();
|
||||
msgsAck.msg_ids.add(messageId);
|
||||
sendMessageData(msgsAck, generateMessageId());
|
||||
|
||||
byte[] authKeyAuxHashFull = Utilities.computeSHA1(authKey);
|
||||
byte[] authKeyAuxHash = new byte[8];
|
||||
System.arraycopy(authKeyAuxHashFull, 0, authKeyAuxHash, 0, 8);
|
||||
|
||||
SerializedData newNonce1 = new SerializedData();
|
||||
newNonce1.writeRaw(authNewNonce);
|
||||
newNonce1.writeByte(1);
|
||||
newNonce1.writeRaw(authKeyAuxHash);
|
||||
byte[] newNonceHash1Full = Utilities.computeSHA1(newNonce1.toByteArray());
|
||||
byte[] newNonceHash1 = new byte[16];
|
||||
System.arraycopy(newNonceHash1Full, newNonceHash1Full.length - 16, newNonceHash1, 0, 16);
|
||||
|
||||
SerializedData newNonce2 = new SerializedData();
|
||||
newNonce2.writeRaw(authNewNonce);
|
||||
newNonce2.writeByte(2);
|
||||
newNonce2.writeRaw(authKeyAuxHash);
|
||||
byte[] newNonceHash2Full = Utilities.computeSHA1(newNonce2.toByteArray());
|
||||
byte[] newNonceHash2 = new byte[16];
|
||||
System.arraycopy(newNonceHash2Full, newNonceHash2Full.length - 16, newNonceHash2, 0, 16);
|
||||
|
||||
SerializedData newNonce3 = new SerializedData();
|
||||
newNonce3.writeRaw(authNewNonce);
|
||||
newNonce3.writeByte(3);
|
||||
newNonce3.writeRaw(authKeyAuxHash);
|
||||
byte[] newNonceHash3Full = Utilities.computeSHA1(newNonce3.toByteArray());
|
||||
byte[] newNonceHash3 = new byte[16];
|
||||
System.arraycopy(newNonceHash3Full, newNonceHash3Full.length - 16, newNonceHash3, 0, 16);
|
||||
|
||||
if (message instanceof TLRPC.TL_dh_gen_ok) {
|
||||
TLRPC.TL_dh_gen_ok dhGenOk = (TLRPC.TL_dh_gen_ok)message;
|
||||
if (!Arrays.equals(newNonceHash1, dhGenOk.new_nonce_hash1)) {
|
||||
Log.e("tmessages", "***** Invalid DH answer nonce hash 1");
|
||||
beginHandshake(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d("tmessages", String.format("Handshake with DC%d completed", datacenter.datacenterId));
|
||||
datacenter.connection.delegate = null;
|
||||
|
||||
final Action parent = this;
|
||||
Utilities.stageQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
datacenter.authKey = authKey;
|
||||
datacenter.authKeyId = authKeyId;
|
||||
datacenter.addServerSalt(serverSalt);
|
||||
HashMap<String, Object> resultDict = new HashMap<String, Object>();
|
||||
resultDict.put("timeDifference", timeDifference);
|
||||
if (delegate != null) {
|
||||
delegate.ActionDidFinishExecution(parent, resultDict);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (message instanceof TLRPC.TL_dh_gen_retry) {
|
||||
TLRPC.TL_dh_gen_retry dhRetry = (TLRPC.TL_dh_gen_retry)message;
|
||||
if (!Arrays.equals(newNonceHash2, dhRetry.new_nonce_hash2)) {
|
||||
Log.e("tmessages", "***** Invalid DH answer nonce hash 2");
|
||||
beginHandshake(false);
|
||||
return;
|
||||
}
|
||||
Log.d("tmessages", "***** Retry DH");
|
||||
beginHandshake(false);
|
||||
} else if (message instanceof TLRPC.TL_dh_gen_fail) {
|
||||
TLRPC.TL_dh_gen_fail dhFail = (TLRPC.TL_dh_gen_fail)message;
|
||||
if (!Arrays.equals(newNonceHash3, dhFail.new_nonce_hash3)) {
|
||||
Log.e("tmessages", "***** Invalid DH answer nonce hash 3");
|
||||
beginHandshake(false);
|
||||
return;
|
||||
}
|
||||
Log.d("tmessages", "***** Server declined DH params");
|
||||
beginHandshake(false);
|
||||
} else {
|
||||
Log.e("tmessages", "***** Unknown DH params response");
|
||||
beginHandshake(false);
|
||||
}
|
||||
} else {
|
||||
TLRPC.TL_msgs_ack msgsAck = new TLRPC.TL_msgs_ack();
|
||||
msgsAck.msg_ids = new ArrayList<Long>();
|
||||
msgsAck.msg_ids.add(messageId);
|
||||
sendMessageData(msgsAck, generateMessageId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tcpConnectionClosed(TcpConnection connection) {
|
||||
wasDisconnect = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tcpConnectionConnected(TcpConnection connection) {
|
||||
if (!wasDisconnect) {
|
||||
return;
|
||||
}
|
||||
if (reqPQMsgData != null) {
|
||||
datacenter.connection.sendData(reqPQMsgData, false, false);
|
||||
} else if (reqDHMsgData != null) {
|
||||
datacenter.connection.sendData(reqDHMsgData, false, false);
|
||||
} else if (setClientDHParamsMsgData != null) {
|
||||
datacenter.connection.sendData(setClientDHParamsMsgData, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tcpConnectionQuiackAckReceived(TcpConnection connection, int ack) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tcpConnectionReceivedData(TcpConnection connection, byte[] data) {
|
||||
SerializedData is = new SerializedData(data);
|
||||
|
||||
long keyId = is.readInt64();
|
||||
|
||||
if (keyId == 0) {
|
||||
long messageId = is.readInt64();
|
||||
if (processedMessageIds.contains(messageId)) {
|
||||
Log.d("tmessages", String.format("===== Duplicate message id %d received, ignoring", messageId));
|
||||
return;
|
||||
}
|
||||
int messageLength = is.readInt32();
|
||||
|
||||
int constructor = is.readInt32();
|
||||
TLObject object = TLClassStore.Instance().TLdeserialize(is, constructor);
|
||||
|
||||
if (object != null) {
|
||||
processedMessageIds.add(messageId);
|
||||
}
|
||||
processMessage(object, messageId);
|
||||
} else {
|
||||
Log.d("tmessages", "***** Received encrypted message while in handshake, restarting");
|
||||
beginHandshake(true);
|
||||
}
|
||||
}
|
||||
}
|
298
TMessagesProj/src/main/java/org/telegram/messenger/LruCache.java
Normal file
298
TMessagesProj/src/main/java/org/telegram/messenger/LruCache.java
Normal file
@ -0,0 +1,298 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Static library version of {@link android.util.LruCache}. Used to write apps
|
||||
* that run on API levels prior to 12. When running on API level 12 or above,
|
||||
* this implementation is still used; it does not try to switch to the
|
||||
* framework's implementation. See the framework SDK documentation for a class
|
||||
* overview.
|
||||
*/
|
||||
public class LruCache {
|
||||
private final LinkedHashMap<String, Bitmap> map;
|
||||
private final LinkedHashMap<String, ArrayList<String>> mapFilters;
|
||||
|
||||
/** Size of this cache in units. Not necessarily the number of elements. */
|
||||
private int size;
|
||||
private int maxSize;
|
||||
|
||||
private int putCount;
|
||||
private int evictionCount;
|
||||
private int hitCount;
|
||||
private int missCount;
|
||||
|
||||
/**
|
||||
* @param maxSize for caches that do not override {@link #sizeOf}, this is
|
||||
* the maximum number of entries in the cache. For all other caches,
|
||||
* this is the maximum sum of the sizes of the entries in this cache.
|
||||
*/
|
||||
public LruCache(int maxSize) {
|
||||
if (maxSize <= 0) {
|
||||
throw new IllegalArgumentException("maxSize <= 0");
|
||||
}
|
||||
this.maxSize = maxSize;
|
||||
this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true);
|
||||
this.mapFilters = new LinkedHashMap<String, ArrayList<String>>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value for {@code key} if it exists in the cache or can be
|
||||
* created by {@code #create}. If a value was returned, it is moved to the
|
||||
* head of the queue. This returns null if a value is not cached and cannot
|
||||
* be created.
|
||||
*/
|
||||
public final Bitmap get(String key) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key == null");
|
||||
}
|
||||
|
||||
Bitmap mapValue;
|
||||
synchronized (this) {
|
||||
mapValue = map.get(key);
|
||||
if (mapValue != null) {
|
||||
hitCount++;
|
||||
return mapValue;
|
||||
}
|
||||
missCount++;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ArrayList<String> getFilterKeys(String key) {
|
||||
ArrayList<String> arr = mapFilters.get(key);
|
||||
if (arr != null) {
|
||||
return new ArrayList<String>(arr);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches {@code value} for {@code key}. The value is moved to the head of
|
||||
* the queue.
|
||||
*
|
||||
* @return the previous value mapped by {@code key}.
|
||||
*/
|
||||
public Bitmap put(String key, Bitmap value) {
|
||||
if (key == null || value == null) {
|
||||
throw new NullPointerException("key == null || value == null");
|
||||
}
|
||||
|
||||
Bitmap previous;
|
||||
synchronized (this) {
|
||||
putCount++;
|
||||
size += safeSizeOf(key, value);
|
||||
previous = map.put(key, value);
|
||||
if (previous != null) {
|
||||
size -= safeSizeOf(key, previous);
|
||||
}
|
||||
}
|
||||
|
||||
String[] args = key.split("@");
|
||||
if (args.length > 1) {
|
||||
ArrayList<String> arr = mapFilters.get(args[0]);
|
||||
if (arr == null) {
|
||||
arr = new ArrayList<String>();
|
||||
mapFilters.put(args[0], arr);
|
||||
}
|
||||
arr.add(args[1]);
|
||||
}
|
||||
|
||||
if (previous != null) {
|
||||
entryRemoved(false, key, previous, value);
|
||||
}
|
||||
|
||||
trimToSize(maxSize);
|
||||
return previous;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param maxSize the maximum size of the cache before returning. May be -1
|
||||
* to evict even 0-sized elements.
|
||||
*/
|
||||
private void trimToSize(int maxSize) {
|
||||
while (true) {
|
||||
String key;
|
||||
Bitmap value;
|
||||
synchronized (this) {
|
||||
if (size < 0 || (map.isEmpty() && size != 0)) {
|
||||
throw new IllegalStateException(getClass().getName()
|
||||
+ ".sizeOf() is reporting inconsistent results!");
|
||||
}
|
||||
|
||||
if (size <= maxSize || map.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
Map.Entry<String, Bitmap> toEvict = map.entrySet().iterator().next();
|
||||
key = toEvict.getKey();
|
||||
value = toEvict.getValue();
|
||||
map.remove(key);
|
||||
size -= safeSizeOf(key, value);
|
||||
evictionCount++;
|
||||
}
|
||||
|
||||
String[] args = key.split("$");
|
||||
if (args.length > 1) {
|
||||
ArrayList<String> arr = mapFilters.get(args[0]);
|
||||
if (arr != null) {
|
||||
arr.remove(key);
|
||||
if (arr.isEmpty()) {
|
||||
mapFilters.remove(args[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entryRemoved(true, key, value, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the entry for {@code key} if it exists.
|
||||
*
|
||||
* @return the previous value mapped by {@code key}.
|
||||
*/
|
||||
public final Bitmap remove(String key) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key == null");
|
||||
}
|
||||
|
||||
Bitmap previous;
|
||||
synchronized (this) {
|
||||
previous = map.remove(key);
|
||||
if (previous != null) {
|
||||
size -= safeSizeOf(key, previous);
|
||||
}
|
||||
}
|
||||
|
||||
if (previous != null) {
|
||||
String[] args = key.split("$");
|
||||
if (args.length > 1) {
|
||||
ArrayList<String> arr = mapFilters.get(args[0]);
|
||||
if (arr != null) {
|
||||
arr.remove(key);
|
||||
if (arr.isEmpty()) {
|
||||
mapFilters.remove(args[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entryRemoved(false, key, previous, null);
|
||||
}
|
||||
|
||||
return previous;
|
||||
}
|
||||
|
||||
public boolean contains(String key){
|
||||
return map.containsKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called for entries that have been evicted or removed. This method is
|
||||
* invoked when a value is evicted to make space, removed by a call to
|
||||
* {@link #remove}, or replaced by a call to {@link #put}. The default
|
||||
* implementation does nothing.
|
||||
*
|
||||
* <p>The method is called without synchronization: other threads may
|
||||
* access the cache while this method is executing.
|
||||
*
|
||||
* @param evicted true if the entry is being removed to make space, false
|
||||
* if the removal was caused by a {@link #put} or {@link #remove}.
|
||||
* @param newValue the new value for {@code key}, if it exists. If non-null,
|
||||
* this removal was caused by a {@link #put}. Otherwise it was caused by
|
||||
* an eviction or a {@link #remove}.
|
||||
*/
|
||||
protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {}
|
||||
|
||||
private int safeSizeOf(String key, Bitmap value) {
|
||||
int result = sizeOf(key, value);
|
||||
if (result < 0) {
|
||||
throw new IllegalStateException("Negative size: " + key + "=" + value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the entry for {@code key} and {@code value} in
|
||||
* user-defined units. The default implementation returns 1 so that size
|
||||
* is the number of entries and max size is the maximum number of entries.
|
||||
*
|
||||
* <p>An entry's size must not change while it is in the cache.
|
||||
*/
|
||||
protected int sizeOf(String key, Bitmap value) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the cache, calling {@link #entryRemoved} on each removed entry.
|
||||
*/
|
||||
public final void evictAll() {
|
||||
trimToSize(-1); // -1 will evict 0-sized elements
|
||||
}
|
||||
|
||||
/**
|
||||
* For caches that do not override {@link #sizeOf}, this returns the number
|
||||
* of entries in the cache. For all other caches, this returns the sum of
|
||||
* the sizes of the entries in this cache.
|
||||
*/
|
||||
public synchronized final int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* For caches that do not override {@link #sizeOf}, this returns the maximum
|
||||
* number of entries in the cache. For all other caches, this returns the
|
||||
* maximum sum of the sizes of the entries in this cache.
|
||||
*/
|
||||
public synchronized final int maxSize() {
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of times {@link #get} returned a value.
|
||||
*/
|
||||
public synchronized final int hitCount() {
|
||||
return hitCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of times {@link #get} returned null or required a new
|
||||
* value to be created.
|
||||
*/
|
||||
public synchronized final int missCount() {
|
||||
return missCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of times {@link #put} was called.
|
||||
*/
|
||||
public synchronized final int putCount() {
|
||||
return putCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of values that have been evicted.
|
||||
*/
|
||||
public synchronized final int evictionCount() {
|
||||
return evictionCount;
|
||||
}
|
||||
|
||||
@Override public synchronized final String toString() {
|
||||
int accesses = hitCount + missCount;
|
||||
int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0;
|
||||
return String.format("LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]",
|
||||
maxSize, hitCount, missCount, hitPercent);
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
public class MessageKeyData {
|
||||
public byte[] aesKey;
|
||||
public byte[] aesIv;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import org.telegram.TL.TLRPC;
|
||||
|
||||
public class NetworkMessage {
|
||||
public TLRPC.TL_protoMessage protoMessage;
|
||||
public Object rawRequest;
|
||||
public long requestId;
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class NotificationCenter {
|
||||
final private HashMap<Integer, ArrayList<Object>> observers = new HashMap<Integer, ArrayList<Object>>();
|
||||
final private HashMap<Integer, Object> memCache = new HashMap<Integer, Object>();
|
||||
final private HashMap<String, Object> memCacheString = new HashMap<String, Object>();
|
||||
private boolean broadcasting = false;
|
||||
final private HashMap<Integer, Object> removeAfterBroadcast = new HashMap<Integer, Object>();
|
||||
|
||||
public interface NotificationCenterDelegate {
|
||||
public abstract void didReceivedNotification(int id, Object... args);
|
||||
}
|
||||
|
||||
public static NotificationCenter Instance = new NotificationCenter();
|
||||
|
||||
public void addToMemCache(int id, Object object) {
|
||||
memCache.put(id, object);
|
||||
}
|
||||
|
||||
public void addToMemCache(String id, Object object) {
|
||||
memCacheString.put(id, object);
|
||||
}
|
||||
|
||||
public Object getFromMemCache(int id) {
|
||||
Object obj = memCache.get(id);
|
||||
if (obj != null) {
|
||||
memCache.remove(id);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
public Object getFromMemCache(String id, Object defaultValue) {
|
||||
Object obj = memCacheString.get(id);
|
||||
if (obj != null) {
|
||||
memCacheString.remove(id);
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
public void postNotificationName(int id, Object... args) {
|
||||
synchronized (observers) {
|
||||
broadcasting = true;
|
||||
ArrayList<Object> objects = observers.get(id);
|
||||
if (objects != null) {
|
||||
for (Object obj : objects) {
|
||||
((NotificationCenterDelegate)obj).didReceivedNotification(id, args);
|
||||
}
|
||||
}
|
||||
broadcasting = false;
|
||||
if (!removeAfterBroadcast.isEmpty()) {
|
||||
for (HashMap.Entry<Integer, Object> entry : removeAfterBroadcast.entrySet()) {
|
||||
removeObserver(entry.getValue(), entry.getKey());
|
||||
}
|
||||
removeAfterBroadcast.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addObserver(Object observer, int id) {
|
||||
synchronized (observers) {
|
||||
ArrayList<Object> objects = observers.get(id);
|
||||
if (objects == null) {
|
||||
objects = new ArrayList<Object>();
|
||||
observers.put(id, objects);
|
||||
}
|
||||
if (objects.contains(observer)) {
|
||||
return;
|
||||
}
|
||||
objects.add(observer);
|
||||
}
|
||||
}
|
||||
|
||||
// public void removeObserver(Object observer) {
|
||||
// synchronized (observers) {
|
||||
// if (broadcasting) {
|
||||
// removeAfterBroadcast.put(-1, observer);
|
||||
// return;
|
||||
// }
|
||||
// Integer[] keyArr = (Integer[])observers.keySet().toArray();
|
||||
// for (int a = 0; a < observers.size(); a++) {
|
||||
// Integer id = keyArr[a];
|
||||
// ArrayList<Object> objects = observers.get(id);
|
||||
// objects.remove(observer);
|
||||
// if (objects.size() == 0) {
|
||||
// observers.remove(id);
|
||||
// a--;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
public void removeObserver(Object observer, int id) {
|
||||
synchronized (observers) {
|
||||
if (broadcasting) {
|
||||
removeAfterBroadcast.put(id, observer);
|
||||
return;
|
||||
}
|
||||
ArrayList<Object> objects = observers.get(id);
|
||||
if (objects != null) {
|
||||
objects.remove(observer);
|
||||
if (objects.size() == 0) {
|
||||
observers.remove(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import org.telegram.TL.TLObject;
|
||||
import org.telegram.TL.TLRPC;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class RPCRequest {
|
||||
public interface RPCRequestDelegate {
|
||||
void run(TLObject response, TLRPC.TL_error error);
|
||||
}
|
||||
public interface RPCProgressDelegate {
|
||||
void progress(int length, int progress);
|
||||
}
|
||||
public interface RPCQuickAckDelegate {
|
||||
void quickAck();
|
||||
}
|
||||
|
||||
public static int RPCRequestClassGeneric = 1;
|
||||
public static int RPCRequestClassDownloadMedia = 2;
|
||||
public static int RPCRequestClassUploadMedia = 4;
|
||||
public static int RPCRequestClassEnableUnauthorized = 8;
|
||||
public static int RPCRequestClassFailOnServerErrors = 16;
|
||||
|
||||
static int RPCRequestClassTransportMask = (RPCRequestClassGeneric | RPCRequestClassDownloadMedia | RPCRequestClassUploadMedia);
|
||||
|
||||
long token;
|
||||
boolean cancelled;
|
||||
|
||||
int serverFailureCount;
|
||||
int flags;
|
||||
|
||||
TLObject rawRequest;
|
||||
TLObject rpcRequest;
|
||||
int serializedLength;
|
||||
|
||||
RPCRequestDelegate completionBlock;
|
||||
RPCProgressDelegate progressBlock;
|
||||
RPCQuickAckDelegate quickAckBlock;
|
||||
|
||||
boolean requiresCompletion;
|
||||
|
||||
long runningMessageId;
|
||||
int runningMessageSeqNo;
|
||||
int runningDatacenterId;
|
||||
int transportChannelToken;
|
||||
|
||||
int runningStartTime;
|
||||
int runningMinStartTime;
|
||||
|
||||
boolean confirmed;
|
||||
|
||||
ArrayList<Long> respondsToMessageIds = new ArrayList<Long>();
|
||||
|
||||
public void addRespondMessageId(long messageId) {
|
||||
respondsToMessageIds.add(messageId);
|
||||
}
|
||||
|
||||
boolean respondsToMessageId(long messageId) {
|
||||
return runningMessageId == messageId || respondsToMessageIds.contains(messageId);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,293 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class SerializedData {
|
||||
protected boolean isOut = true;
|
||||
private ByteArrayOutputStream outbuf;
|
||||
private DataOutputStream out;
|
||||
private ByteArrayInputStream inbuf;
|
||||
private DataInputStream in;
|
||||
|
||||
public SerializedData() {
|
||||
outbuf = new ByteArrayOutputStream();
|
||||
out = new DataOutputStream(outbuf);
|
||||
}
|
||||
|
||||
public SerializedData(byte[] data){
|
||||
isOut = false;
|
||||
inbuf = new ByteArrayInputStream(data);
|
||||
in = new DataInputStream(inbuf);
|
||||
}
|
||||
|
||||
public SerializedData(File file) throws IOException {
|
||||
FileInputStream is = new FileInputStream(file);
|
||||
byte[] data = new byte[(int)file.length()];
|
||||
new DataInputStream(is).readFully(data);
|
||||
is.close();
|
||||
|
||||
isOut = false;
|
||||
inbuf = new ByteArrayInputStream(data);
|
||||
in = new DataInputStream(inbuf);
|
||||
}
|
||||
|
||||
public void writeInt32(int x){
|
||||
writeInt32(x, out);
|
||||
}
|
||||
|
||||
protected void writeInt32(int x, DataOutputStream out){
|
||||
try {
|
||||
for(int i = 0; i < 4; i++){
|
||||
out.write(x >> (i * 8));
|
||||
}
|
||||
} catch(IOException gfdsgd) {
|
||||
Log.e("tmessages", "write int32 error");
|
||||
}
|
||||
}
|
||||
|
||||
public void writeInt64(long i) {
|
||||
writeInt64(i, out);
|
||||
}
|
||||
|
||||
protected void writeInt64(long x, DataOutputStream out){
|
||||
try {
|
||||
for(int i = 0; i < 8; i++){
|
||||
out.write((int)(x >> (i * 8)));
|
||||
}
|
||||
} catch(IOException gfdsgd) {
|
||||
Log.e("tmessages", "write int64 error");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean readBool() {
|
||||
int consructor = readInt32();
|
||||
if (consructor == 0x997275b5) {
|
||||
return true;
|
||||
} else if (consructor == 0xbc799737) {
|
||||
return false;
|
||||
}
|
||||
Log.e("tmessages", "Not bool value!");
|
||||
return false;
|
||||
}
|
||||
|
||||
public void writeBool(boolean value) {
|
||||
if (value) {
|
||||
writeInt32(0x997275b5);
|
||||
} else {
|
||||
writeInt32(0xbc799737);
|
||||
}
|
||||
}
|
||||
|
||||
public int readInt32(){
|
||||
try {
|
||||
int i = 0;
|
||||
for(int j = 0; j < 4; j++){
|
||||
i |= (in.read() << (j * 8));
|
||||
}
|
||||
return i;
|
||||
} catch(IOException x) {
|
||||
Log.e("tmessages", "read int32 error");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long readInt64(){
|
||||
try {
|
||||
long i = 0;
|
||||
for(int j = 0; j < 8; j++){
|
||||
i |= ((long)in.read() << (j * 8));
|
||||
}
|
||||
return i;
|
||||
} catch(IOException x) {
|
||||
Log.e("tmessages", "read int64 error");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void writeRaw(byte[] b){
|
||||
try {
|
||||
out.write(b);
|
||||
} catch(Exception x) {
|
||||
Log.e("tmessages", "write raw error");
|
||||
}
|
||||
}
|
||||
|
||||
public void writeRaw(byte[] b, int offset, int count) {
|
||||
try {
|
||||
out.write(b, offset, count);
|
||||
} catch(Exception x) {
|
||||
Log.e("tmessages", "write raw error");
|
||||
}
|
||||
}
|
||||
|
||||
public void writeByte(int i) {
|
||||
try {
|
||||
out.writeByte((byte)i);
|
||||
} catch (Exception e) {
|
||||
Log.e("tmessages", "write byte error");
|
||||
}
|
||||
}
|
||||
|
||||
public void writeByte(byte b) {
|
||||
try {
|
||||
out.writeByte(b);
|
||||
} catch (Exception e) {
|
||||
Log.e("tmessages", "write byte error");
|
||||
}
|
||||
}
|
||||
|
||||
public void readRaw(byte[] b){
|
||||
try {
|
||||
in.read(b);
|
||||
} catch(Exception x) {
|
||||
Log.e("tmessages", "read raw error");
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] readData(int count) {
|
||||
byte[] arr = new byte[count];
|
||||
readRaw(arr);
|
||||
return arr;
|
||||
}
|
||||
|
||||
public String readString(){
|
||||
try {
|
||||
int sl = 1;
|
||||
int l = in.read();
|
||||
if(l >= 254){
|
||||
l = in.read() | (in.read() << 8) | (in.read() << 16);
|
||||
sl = 4;
|
||||
}
|
||||
byte[] b = new byte[l];
|
||||
in.read(b);
|
||||
int i=sl;
|
||||
while((l + i) % 4 != 0) {
|
||||
in.read();
|
||||
i++;
|
||||
}
|
||||
return new String(b, "UTF-8");
|
||||
} catch(Exception x) {
|
||||
Log.e("tmessages", "read string error");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] readByteArray() {
|
||||
try {
|
||||
int sl = 1;
|
||||
int l = in.read();
|
||||
if (l >= 254){
|
||||
l = in.read() | (in.read() << 8) | (in.read() << 16);
|
||||
sl = 4;
|
||||
}
|
||||
byte[] b = new byte[l];
|
||||
in.read(b);
|
||||
int i = sl;
|
||||
while((l + i) % 4 != 0){
|
||||
in.read();
|
||||
i++;
|
||||
}
|
||||
return b;
|
||||
} catch(Exception x) {
|
||||
Log.e("tmessages", "read byte array error");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void writeByteArray(byte[] b){
|
||||
try {
|
||||
if (b.length <= 253){
|
||||
out.write(b.length);
|
||||
} else {
|
||||
out.write(254);
|
||||
out.write(b.length);
|
||||
out.write(b.length >> 8);
|
||||
out.write(b.length >> 16);
|
||||
}
|
||||
out.write(b);
|
||||
int i = b.length <= 253 ? 1 : 4;
|
||||
while((b.length + i) % 4 != 0){
|
||||
out.write(0);
|
||||
i++;
|
||||
}
|
||||
}catch(Exception x) {
|
||||
Log.e("tmessages", "write byte array error");
|
||||
}
|
||||
}
|
||||
|
||||
public void writeString(String s){
|
||||
try {
|
||||
writeByteArray(s.getBytes("UTF-8"));
|
||||
} catch(Exception x) {
|
||||
Log.e("tmessages", "write string error");
|
||||
}
|
||||
}
|
||||
|
||||
public void writeByteArray(byte[] b, int offset, int count) {
|
||||
try {
|
||||
if(count <= 253){
|
||||
out.write(count);
|
||||
} else {
|
||||
out.write(254);
|
||||
out.write(count);
|
||||
out.write(count >> 8);
|
||||
out.write(count >> 16);
|
||||
}
|
||||
out.write(b, offset, count);
|
||||
int i = count <= 253 ? 1 : 4;
|
||||
while ((count + i) % 4 != 0){
|
||||
out.write(0);
|
||||
i++;
|
||||
}
|
||||
} catch(Exception x) {
|
||||
Log.e("tmessages", "write byte array error");
|
||||
}
|
||||
}
|
||||
|
||||
public double readDouble(){
|
||||
try {
|
||||
return Double.longBitsToDouble(readInt64());
|
||||
} catch(Exception x) {
|
||||
Log.e("tmessages", "read double error");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void writeDouble(double d){
|
||||
try {
|
||||
writeInt64(Double.doubleToRawLongBits(d));
|
||||
} catch(Exception x) {
|
||||
Log.e("tmessages", "write double error");
|
||||
}
|
||||
}
|
||||
|
||||
public int length() {
|
||||
return isOut ? outbuf.size() : inbuf.available();
|
||||
}
|
||||
|
||||
protected void set(byte[] newData) {
|
||||
isOut = false;
|
||||
inbuf = new ByteArrayInputStream(newData);
|
||||
in = new DataInputStream(inbuf);
|
||||
}
|
||||
|
||||
public byte[] toByteArray() {
|
||||
return outbuf.toByteArray();
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
public class ServerSalt {
|
||||
public int validSince;
|
||||
public int validUntil;
|
||||
public long value;
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.telephony.SmsMessage;
|
||||
|
||||
import org.telegram.messenger.NotificationCenter;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class SmsListener extends BroadcastReceiver {
|
||||
|
||||
private SharedPreferences preferences;
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if(intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
|
||||
Bundle bundle = intent.getExtras();
|
||||
SmsMessage[] msgs;
|
||||
if (bundle != null) {
|
||||
try {
|
||||
Object[] pdus = (Object[]) bundle.get("pdus");
|
||||
msgs = new SmsMessage[pdus.length];
|
||||
String wholeString = "";
|
||||
for(int i = 0; i < msgs.length; i++){
|
||||
msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
|
||||
wholeString += msgs[i].getMessageBody();
|
||||
}
|
||||
|
||||
try {
|
||||
Pattern pattern = Pattern.compile("[0-9]+");
|
||||
Matcher matcher = pattern.matcher(wholeString);
|
||||
if (matcher.find()) {
|
||||
String str = matcher.group(0);
|
||||
if (str.length() >= 3) {
|
||||
NotificationCenter.Instance.postNotificationName(998, matcher.group(0));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,431 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import jawnae.pyronet.PyroClient;
|
||||
import jawnae.pyronet.PyroSelector;
|
||||
import jawnae.pyronet.events.PyroClientAdapter;
|
||||
|
||||
public class TcpConnection extends PyroClientAdapter {
|
||||
public enum TcpConnectionState {
|
||||
TcpConnectionStageIdle,
|
||||
TcpConnectionStageConnecting,
|
||||
TcpConnectionStageReconnecting,
|
||||
TcpConnectionStageConnected,
|
||||
TcpConnectionStageSuspended
|
||||
}
|
||||
|
||||
public abstract static interface TcpConnectionDelegate {
|
||||
public abstract void tcpConnectionClosed(TcpConnection connection);
|
||||
public abstract void tcpConnectionConnected(TcpConnection connection);
|
||||
public abstract void tcpConnectionQuiackAckReceived(TcpConnection connection, int ack);
|
||||
public abstract void tcpConnectionReceivedData(TcpConnection connection, byte[] data);
|
||||
}
|
||||
|
||||
private static PyroSelector selector;
|
||||
private PyroClient client;
|
||||
public TcpConnectionState connectionState;
|
||||
private Queue<byte[]> packetsQueue;
|
||||
public volatile int channelToken = 0;
|
||||
private String hostAddress;
|
||||
private int hostPort;
|
||||
public int datacenterId;
|
||||
private int failedConnectionCount;
|
||||
public TcpConnectionDelegate delegate;
|
||||
private ByteBuffer restOfTheData;
|
||||
|
||||
public int transportRequestClass;
|
||||
|
||||
private boolean firstPacket;
|
||||
|
||||
private Timer reconnectTimer;
|
||||
|
||||
public TcpConnection(String ip, int port) {
|
||||
if (selector == null) {
|
||||
selector = new PyroSelector();
|
||||
selector.spawnNetworkThread("network thread");
|
||||
}
|
||||
packetsQueue = new LinkedList<byte[]>();
|
||||
hostAddress = ip;
|
||||
hostPort = port;
|
||||
connectionState = TcpConnectionState.TcpConnectionStageIdle;
|
||||
}
|
||||
|
||||
static volatile Integer nextChannelToken = 1;
|
||||
static int generateChannelToken() {
|
||||
return nextChannelToken++;
|
||||
}
|
||||
|
||||
public void connect() {
|
||||
selector.scheduleTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (connectionState == TcpConnectionState.TcpConnectionStageConnected || connectionState == TcpConnectionState.TcpConnectionStageConnecting) {
|
||||
return;
|
||||
}
|
||||
|
||||
connectionState = TcpConnectionState.TcpConnectionStageConnecting;
|
||||
try {
|
||||
if (ConnectionsManager.DEBUG_VERSION) {
|
||||
Log.d("tmessages", String.format(this + " Connecting (%s:%d)", hostAddress, hostPort));
|
||||
}
|
||||
firstPacket = true;
|
||||
restOfTheData = null;
|
||||
if (client != null) {
|
||||
client.removeListener(TcpConnection.this);
|
||||
client.dropConnection();
|
||||
}
|
||||
client = selector.connect(new InetSocketAddress(hostAddress, hostPort));
|
||||
client.addListener(TcpConnection.this);
|
||||
client.setTimeout(35000);
|
||||
selector.wakeup();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void suspendConnection(boolean task) {
|
||||
if (ConnectionsManager.DEBUG_VERSION) {
|
||||
Log.d("tmessages", "suspend connnection " + this);
|
||||
}
|
||||
if (task) {
|
||||
selector.scheduleTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (reconnectTimer != null) {
|
||||
reconnectTimer.cancel();
|
||||
reconnectTimer = null;
|
||||
}
|
||||
if (connectionState == TcpConnectionState.TcpConnectionStageIdle || connectionState == TcpConnectionState.TcpConnectionStageSuspended) {
|
||||
return;
|
||||
}
|
||||
connectionState = TcpConnectionState.TcpConnectionStageSuspended;
|
||||
if (client != null) {
|
||||
client.dropConnection();
|
||||
client = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (reconnectTimer != null) {
|
||||
reconnectTimer.cancel();
|
||||
reconnectTimer = null;
|
||||
}
|
||||
if (connectionState == TcpConnectionState.TcpConnectionStageIdle) {
|
||||
return;
|
||||
}
|
||||
connectionState = TcpConnectionState.TcpConnectionStageSuspended;
|
||||
if (client != null) {
|
||||
client.dropConnection();
|
||||
client = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void resumeConnection() {
|
||||
|
||||
}
|
||||
|
||||
private void reconnect() {
|
||||
suspendConnection(false);
|
||||
connectionState = TcpConnectionState.TcpConnectionStageReconnecting;
|
||||
connect();
|
||||
}
|
||||
|
||||
public void sendData(final byte[] data, final boolean reportAck, final boolean startResponseTimeout) {
|
||||
selector.scheduleTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (connectionState == TcpConnectionState.TcpConnectionStageIdle ||
|
||||
connectionState == TcpConnectionState.TcpConnectionStageReconnecting ||
|
||||
connectionState == TcpConnectionState.TcpConnectionStageSuspended) {
|
||||
connect();
|
||||
}
|
||||
|
||||
int packetLength = data.length / 4;
|
||||
|
||||
SerializedData buffer = new SerializedData();
|
||||
if (packetLength < 0x7f) {
|
||||
if (reportAck) {
|
||||
packetLength |= (1 << 7);
|
||||
}
|
||||
buffer.writeByte(packetLength);
|
||||
} else {
|
||||
packetLength = (packetLength << 8) + 0x7f;
|
||||
if (reportAck) {
|
||||
packetLength |= (1 << 7);
|
||||
}
|
||||
buffer.writeInt32(packetLength);
|
||||
}
|
||||
buffer.writeRaw(data);
|
||||
|
||||
final byte[] packet = buffer.toByteArray();
|
||||
|
||||
if (client != null && !client.isDisconnected()) {
|
||||
ByteBuffer sendBuffer = ByteBuffer.allocate((firstPacket ? 1 : 0) + packet.length);
|
||||
sendBuffer.rewind();
|
||||
sendBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
if (firstPacket) {
|
||||
sendBuffer.put((byte)0xef);
|
||||
firstPacket = false;
|
||||
}
|
||||
sendBuffer.put(packet);
|
||||
sendBuffer.rewind();
|
||||
client.write(sendBuffer);
|
||||
} else {
|
||||
packetsQueue.add(packet);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void readData(ByteBuffer buffer) throws Exception {
|
||||
if (ConnectionsManager.DEBUG_VERSION) {
|
||||
Log.d("tmessages", "received data = " + buffer.limit());
|
||||
}
|
||||
|
||||
if (restOfTheData != null) {
|
||||
if (ConnectionsManager.DEBUG_VERSION) {
|
||||
Log.d("tmessages", "there is rest of data " + restOfTheData.limit());
|
||||
}
|
||||
ByteBuffer newBuffer = ByteBuffer.allocate(restOfTheData.limit() + buffer.limit());
|
||||
newBuffer.put(restOfTheData);
|
||||
newBuffer.put(buffer);
|
||||
buffer = newBuffer;
|
||||
restOfTheData = null;
|
||||
}
|
||||
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.rewind();
|
||||
|
||||
while (buffer.hasRemaining()) {
|
||||
|
||||
int currentPacketLength;
|
||||
buffer.mark();
|
||||
byte fByte = buffer.get();
|
||||
|
||||
if ((fByte & (1 << 7)) != 0) {
|
||||
buffer.reset();
|
||||
if (buffer.remaining() < 4) {
|
||||
restOfTheData = ByteBuffer.allocate(buffer.remaining());
|
||||
restOfTheData.put(buffer);
|
||||
restOfTheData.rewind();
|
||||
break;
|
||||
}
|
||||
buffer.order(ByteOrder.BIG_ENDIAN);
|
||||
final int ackId = buffer.getInt() & (~(1 << 31));
|
||||
if (delegate != null) {
|
||||
Utilities.stageQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
delegate.tcpConnectionQuiackAckReceived(TcpConnection.this, ackId);
|
||||
}
|
||||
});
|
||||
}
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fByte != 0x7f) {
|
||||
currentPacketLength = ((int)fByte) * 4;
|
||||
} else {
|
||||
buffer.reset();
|
||||
if (buffer.remaining() < 4) {
|
||||
restOfTheData = ByteBuffer.allocate(buffer.remaining());
|
||||
restOfTheData.put(buffer);
|
||||
restOfTheData.rewind();
|
||||
break;
|
||||
}
|
||||
currentPacketLength = (buffer.getInt() >> 8) * 4;
|
||||
}
|
||||
|
||||
if (currentPacketLength < buffer.remaining()) {
|
||||
if (ConnectionsManager.DEBUG_VERSION) {
|
||||
Log.d("tmessages", this + " Received message len " + currentPacketLength + " but packet larger " + buffer.remaining());
|
||||
}
|
||||
} else if (currentPacketLength == buffer.remaining()) {
|
||||
if (ConnectionsManager.DEBUG_VERSION) {
|
||||
Log.d("tmessages", this + " Received message len " + currentPacketLength + " equal to packet size");
|
||||
}
|
||||
} else {
|
||||
if (ConnectionsManager.DEBUG_VERSION) {
|
||||
Log.d("tmessages", this + " Received packet size less(" + buffer.remaining() + ") then message size(" + currentPacketLength + ")");
|
||||
}
|
||||
buffer.reset();
|
||||
restOfTheData = ByteBuffer.allocate(buffer.remaining());
|
||||
restOfTheData.order(ByteOrder.LITTLE_ENDIAN);
|
||||
restOfTheData.put(buffer);
|
||||
restOfTheData.rewind();
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentPacketLength % 4 != 0 || currentPacketLength > 2 * 1024 * 1024) {
|
||||
if (ConnectionsManager.DEBUG_VERSION) {
|
||||
Log.e("tmessages", "Invalid packet length");
|
||||
}
|
||||
reconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
final byte[] packetData = new byte[currentPacketLength];
|
||||
buffer.get(packetData);
|
||||
|
||||
if (delegate != null) {
|
||||
Utilities.stageQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
delegate.tcpConnectionReceivedData(TcpConnection.this, packetData);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handleDisconnect(PyroClient client, IOException e) {
|
||||
if (reconnectTimer != null) {
|
||||
reconnectTimer.cancel();
|
||||
reconnectTimer = null;
|
||||
}
|
||||
if (ConnectionsManager.DEBUG_VERSION) {
|
||||
if (e != null) {
|
||||
Log.d("tmessages", "Disconnected " + this + " with error " + e);
|
||||
} else {
|
||||
Log.d("tmessages", "Disconnected " + this);
|
||||
}
|
||||
}
|
||||
firstPacket = true;
|
||||
restOfTheData = null;
|
||||
packetsQueue.clear();
|
||||
channelToken = 0;
|
||||
if (connectionState != TcpConnectionState.TcpConnectionStageSuspended && connectionState != TcpConnectionState.TcpConnectionStageIdle) {
|
||||
connectionState = TcpConnectionState.TcpConnectionStageIdle;
|
||||
}
|
||||
if (delegate != null) {
|
||||
Utilities.stageQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
delegate.tcpConnectionClosed(TcpConnection.this);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (connectionState == TcpConnectionState.TcpConnectionStageIdle && (!packetsQueue.isEmpty() ||
|
||||
(transportRequestClass & RPCRequest.RPCRequestClassGeneric) != 0 && (datacenterId == ConnectionsManager.Instance.currentDatacenterId || datacenterId == ConnectionsManager.Instance.movingToDatacenterId))) {
|
||||
failedConnectionCount++;
|
||||
if (ConnectionsManager.DEBUG_VERSION) {
|
||||
Log.d("tmessages", "Reconnect " + hostAddress + ":" + hostPort + " " + this);
|
||||
}
|
||||
try {
|
||||
reconnectTimer = new Timer();
|
||||
reconnectTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
selector.scheduleTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (reconnectTimer != null) {
|
||||
reconnectTimer.cancel();
|
||||
reconnectTimer = null;
|
||||
}
|
||||
} catch (Exception e2) {
|
||||
e2.printStackTrace();
|
||||
}
|
||||
connect();
|
||||
}
|
||||
});
|
||||
}
|
||||
}, failedConnectionCount > 10 ? 500 : 200, failedConnectionCount > 10 ? 500 : 200);
|
||||
} catch (Exception e3) {
|
||||
e3.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectedClient(PyroClient client) {
|
||||
//if (!ConnectionsManager.isNetworkOnline()) {
|
||||
// return;
|
||||
//}
|
||||
connectionState = TcpConnectionState.TcpConnectionStageConnected;
|
||||
channelToken = generateChannelToken();
|
||||
if (ConnectionsManager.DEBUG_VERSION) {
|
||||
Log.d("tmessages", String.format(this + " Connected (%s:%d)", hostAddress, hostPort));
|
||||
}
|
||||
if (delegate != null) {
|
||||
Utilities.stageQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
delegate.tcpConnectionConnected(TcpConnection.this);
|
||||
}
|
||||
});
|
||||
}
|
||||
while (packetsQueue.size() != 0) {
|
||||
byte[] packet = packetsQueue.poll();
|
||||
ByteBuffer sendBuffer = ByteBuffer.allocate((firstPacket ? 1 : 0) + packet.length);
|
||||
sendBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
if (firstPacket) {
|
||||
sendBuffer.put((byte)0xef);
|
||||
firstPacket = false;
|
||||
}
|
||||
sendBuffer.put(packet);
|
||||
sendBuffer.rewind();
|
||||
client.write(sendBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unconnectableClient(PyroClient client) {
|
||||
handleDisconnect(client, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void droppedClient(PyroClient client, IOException cause) {
|
||||
super.droppedClient(client, cause);
|
||||
handleDisconnect(client, cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnectedClient(PyroClient client) {
|
||||
handleDisconnect(client, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receivedData(PyroClient client, ByteBuffer data) {
|
||||
try {
|
||||
failedConnectionCount = 0;
|
||||
readData(data);
|
||||
} catch (Exception e) {
|
||||
if (ConnectionsManager.DEBUG_VERSION) {
|
||||
Log.d("tmessages", "read data error");
|
||||
}
|
||||
reconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sentData(PyroClient client, int bytes) {
|
||||
failedConnectionCount = 0;
|
||||
if (ConnectionsManager.DEBUG_VERSION) {
|
||||
Log.d("tmessages", this + " bytes sent " + bytes);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import org.telegram.TL.TLObject;
|
||||
import org.telegram.TL.TLRPC;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class UpdateDatacenterListAction extends Action {
|
||||
public int datacenterId;
|
||||
|
||||
public UpdateDatacenterListAction(int id) {
|
||||
datacenterId = id;
|
||||
}
|
||||
|
||||
public void execute(HashMap params) {
|
||||
TLRPC.TL_help_getConfig getConfig = new TLRPC.TL_help_getConfig();
|
||||
|
||||
ConnectionsManager.Instance.performRpc(getConfig, new RPCRequest.RPCRequestDelegate() {
|
||||
@Override
|
||||
public void run(TLObject response, TLRPC.TL_error error) {
|
||||
if (delegate == null) {
|
||||
return;
|
||||
}
|
||||
if (error == null) {
|
||||
TLRPC.TL_config config = (TLRPC.TL_config)response;
|
||||
ArrayList<Datacenter> datacenters = new ArrayList<Datacenter>();
|
||||
for (TLRPC.TL_dcOption datacenterDesc : config.dc_options) {
|
||||
Datacenter datacenter = new Datacenter();
|
||||
datacenter.datacenterId = datacenterDesc.id;
|
||||
|
||||
datacenter.authSessionId = (long)(MessagesController.random.nextDouble() * Long.MAX_VALUE);
|
||||
|
||||
datacenter.address = datacenterDesc.ip_address;
|
||||
datacenter.port = datacenterDesc.port;
|
||||
datacenters.add(datacenter);
|
||||
}
|
||||
HashMap<String, Object> result = new HashMap<String, Object>();
|
||||
result.put("datacenters", datacenters);
|
||||
delegate.ActionDidFinishExecution(UpdateDatacenterListAction.this, result);
|
||||
} else {
|
||||
delegate.ActionDidFailExecution(UpdateDatacenterListAction.this);
|
||||
}
|
||||
}
|
||||
}, null, true, RPCRequest.RPCRequestClassEnableUnauthorized | RPCRequest.RPCRequestClassGeneric);
|
||||
}
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import org.telegram.TL.TLClassStore;
|
||||
import org.telegram.TL.TLRPC;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
|
||||
public class UserConfig {
|
||||
public static TLRPC.User currentUser;
|
||||
public static int clientUserId = 0;
|
||||
public static boolean clientActivated = false;
|
||||
public static int lastDateValue = 0;
|
||||
public static int lastPtsValue = 0;
|
||||
public static int lastQtsValue = 0;
|
||||
public static int lastSeqValue = 0;
|
||||
public static boolean registeredForPush = false;
|
||||
public static String pushString = "";
|
||||
public static int lastSendMessageId = -1;
|
||||
public static int lastLocalId = -1;
|
||||
public static int lastSecretVersion = 0;
|
||||
public static byte[] secretPBytes = null;
|
||||
public static int secretG = 0;
|
||||
public static String contactsHash = "";
|
||||
public static String importHash = "";
|
||||
private final static Integer sync = 1;
|
||||
public static boolean saveIncomingPhotos = false;
|
||||
|
||||
public static int getNewMessageId() {
|
||||
int id;
|
||||
synchronized (sync) {
|
||||
id = lastSendMessageId;
|
||||
lastSendMessageId--;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public static void saveConfig() {
|
||||
synchronized (sync) {
|
||||
SerializedData data = new SerializedData();
|
||||
if (currentUser != null) {
|
||||
data.writeInt32(1);
|
||||
currentUser.serializeToStream(data);
|
||||
clientUserId = currentUser.id;
|
||||
clientActivated = true;
|
||||
data.writeInt32(lastDateValue);
|
||||
data.writeInt32(lastPtsValue);
|
||||
data.writeInt32(lastSeqValue);
|
||||
data.writeBool(registeredForPush);
|
||||
data.writeString(pushString);
|
||||
data.writeInt32(lastSendMessageId);
|
||||
data.writeInt32(lastLocalId);
|
||||
data.writeString(contactsHash);
|
||||
data.writeString(importHash);
|
||||
data.writeBool(saveIncomingPhotos);
|
||||
data.writeInt32(lastQtsValue);
|
||||
data.writeInt32(lastSecretVersion);
|
||||
if (secretPBytes != null) {
|
||||
data.writeInt32(1);
|
||||
data.writeByteArray(secretPBytes);
|
||||
} else {
|
||||
data.writeInt32(0);
|
||||
}
|
||||
data.writeInt32(secretG);
|
||||
} else {
|
||||
data.writeInt32(0);
|
||||
}
|
||||
try {
|
||||
File configFile = new File(Utilities.applicationContext.getFilesDir(), "user.dat");
|
||||
if (!configFile.exists()) {
|
||||
configFile.createNewFile();
|
||||
}
|
||||
FileOutputStream stream = new FileOutputStream(configFile);
|
||||
stream.write(data.toByteArray());
|
||||
stream.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadConfig() {
|
||||
synchronized (sync) {
|
||||
File configFile = new File(Utilities.applicationContext.getFilesDir(), "user.dat");
|
||||
if (configFile.exists()) {
|
||||
try {
|
||||
SerializedData data = new SerializedData(configFile);
|
||||
if (data.readInt32() != 0) {
|
||||
int constructor = data.readInt32();
|
||||
currentUser = (TLRPC.TL_userSelf)TLClassStore.Instance().TLdeserialize(data, constructor);
|
||||
clientUserId = currentUser.id;
|
||||
clientActivated = true;
|
||||
lastDateValue = data.readInt32();
|
||||
lastPtsValue = data.readInt32();
|
||||
lastSeqValue = data.readInt32();
|
||||
registeredForPush = data.readBool();
|
||||
pushString = data.readString();
|
||||
lastSendMessageId = data.readInt32();
|
||||
lastLocalId = data.readInt32();
|
||||
contactsHash = data.readString();
|
||||
importHash = data.readString();
|
||||
saveIncomingPhotos = data.readBool();
|
||||
if (currentUser.status != null) {
|
||||
if (currentUser.status.expires != 0) {
|
||||
currentUser.status.was_online = currentUser.status.expires;
|
||||
} else {
|
||||
currentUser.status.expires = currentUser.status.was_online;
|
||||
}
|
||||
}
|
||||
lastQtsValue = data.readInt32();
|
||||
lastSecretVersion = data.readInt32();
|
||||
int val = data.readInt32();
|
||||
if (val == 1) {
|
||||
secretPBytes = data.readByteArray();
|
||||
}
|
||||
secretG = data.readInt32();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void clearConfig() {
|
||||
clientUserId = 0;
|
||||
clientActivated = false;
|
||||
currentUser = null;
|
||||
lastDateValue = 0;
|
||||
lastSeqValue = 0;
|
||||
lastPtsValue = 0;
|
||||
registeredForPush = false;
|
||||
contactsHash = "";
|
||||
lastLocalId = -1;
|
||||
importHash = "";
|
||||
lastSendMessageId = -1;
|
||||
saveIncomingPhotos = false;
|
||||
saveConfig();
|
||||
}
|
||||
}
|
@ -0,0 +1,598 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Typeface;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.text.Html;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
import org.telegram.TL.TLClassStore;
|
||||
import org.telegram.TL.TLObject;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.PublicKey;
|
||||
import java.security.spec.RSAPublicKeySpec;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Locale;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
|
||||
public class Utilities {
|
||||
public static Context applicationContext;
|
||||
public static Handler applicationHandler;
|
||||
private final static Integer lock = 1;
|
||||
|
||||
public static class TPFactorizedValue {
|
||||
public long p, q;
|
||||
}
|
||||
|
||||
public static DispatchQueue stageQueue = new DispatchQueue("stageQueue");
|
||||
public static DispatchQueue globalQueue = new DispatchQueue("globalQueue");
|
||||
public static DispatchQueue cacheOutQueue = new DispatchQueue("cacheOutQueue");
|
||||
public static DispatchQueue imageLoadQueue = new DispatchQueue("imageLoadQueue");
|
||||
public static DispatchQueue fileUploadQueue = new DispatchQueue("imageLoadQueue");
|
||||
|
||||
public native static long doPQNative(long _what);
|
||||
public native static byte[] aesIgeEncryption(byte[] _what, byte[] _key, byte[] _iv, boolean encrypt, boolean changeIv);
|
||||
|
||||
static {
|
||||
System.loadLibrary("tmessages");
|
||||
}
|
||||
|
||||
static final Class<?>[] constructorSignature = new Class[] {Context.class, AttributeSet.class};
|
||||
|
||||
public static int externalCacheNotAvailableState = 0;
|
||||
public static File getCacheDir() {
|
||||
if (externalCacheNotAvailableState == 1 || externalCacheNotAvailableState == 0 && Environment.getExternalStorageState().startsWith(Environment.MEDIA_MOUNTED)) {
|
||||
externalCacheNotAvailableState = 1;
|
||||
return applicationContext.getExternalCacheDir();
|
||||
}
|
||||
externalCacheNotAvailableState = 2;
|
||||
return applicationContext.getCacheDir();
|
||||
}
|
||||
|
||||
public static TPFactorizedValue getFactorizedValue(long what) {
|
||||
long g = doPQNative(what);
|
||||
if (g > 1 && g < what) {
|
||||
long p1 = g;
|
||||
long p2 = what / g;
|
||||
if (p1 > p2) {
|
||||
long tmp = p1;
|
||||
p1 = p2;
|
||||
p2 = tmp;
|
||||
}
|
||||
|
||||
TPFactorizedValue result = new TPFactorizedValue();
|
||||
result.p = p1;
|
||||
result.q = p2;
|
||||
|
||||
return result;
|
||||
} else {
|
||||
Log.e("tmessages", String.format("**** Factorization failed for %d", what));
|
||||
TPFactorizedValue result = new TPFactorizedValue();
|
||||
result.p = 0;
|
||||
result.q = 0;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] computeSHA1(byte[] convertme) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-1");
|
||||
return md.digest(convertme);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static byte[] encryptWithRSA(BigInteger[] key, byte[] data) {
|
||||
try {
|
||||
KeyFactory fact = KeyFactory.getInstance("RSA");
|
||||
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(key[0], key[1]);
|
||||
PublicKey publicKey = fact.generatePublic(keySpec);
|
||||
final Cipher cipher = Cipher.getInstance("RSA");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||
return cipher.doFinal(data);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static byte[] longToBytes(long x) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(8);
|
||||
buffer.putLong(x);
|
||||
return buffer.array();
|
||||
}
|
||||
|
||||
public static long bytesToLong(byte[] bytes) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(8);
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.put(bytes);
|
||||
buffer.flip();
|
||||
return buffer.getLong();
|
||||
}
|
||||
|
||||
public static int bytesToInt(byte[] bytes) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(4);
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.put(bytes);
|
||||
buffer.flip();
|
||||
return buffer.getInt();
|
||||
}
|
||||
|
||||
public static MessageKeyData generateMessageKeyData(byte[] authKey, byte[] messageKey, boolean incoming) {
|
||||
MessageKeyData keyData = new MessageKeyData();
|
||||
if (authKey == null || authKey.length == 0) {
|
||||
keyData.aesIv = null;
|
||||
keyData.aesKey = null;
|
||||
return keyData;
|
||||
}
|
||||
|
||||
int x = incoming ? 8 : 0;
|
||||
|
||||
SerializedData data = new SerializedData();
|
||||
data.writeRaw(messageKey);
|
||||
data.writeRaw(authKey, x, 32);
|
||||
byte[] sha1_a = Utilities.computeSHA1(data.toByteArray());
|
||||
|
||||
data = new SerializedData();
|
||||
data.writeRaw(authKey, 32 + x, 16);
|
||||
data.writeRaw(messageKey);
|
||||
data.writeRaw(authKey, 48 + x, 16);
|
||||
byte[] sha1_b = Utilities.computeSHA1(data.toByteArray());
|
||||
|
||||
data = new SerializedData();
|
||||
data.writeRaw(authKey, 64 + x, 32);
|
||||
data.writeRaw(messageKey);
|
||||
byte[] sha1_c = Utilities.computeSHA1(data.toByteArray());
|
||||
|
||||
data = new SerializedData();
|
||||
data.writeRaw(messageKey);
|
||||
data.writeRaw(authKey, 96 + x, 32);
|
||||
byte[] sha1_d = Utilities.computeSHA1(data.toByteArray());
|
||||
|
||||
SerializedData aesKey = new SerializedData();
|
||||
aesKey.writeRaw(sha1_a, 0, 8);
|
||||
aesKey.writeRaw(sha1_b, 8, 12);
|
||||
aesKey.writeRaw(sha1_c, 4, 12);
|
||||
keyData.aesKey = aesKey.toByteArray();
|
||||
|
||||
SerializedData aesIv = new SerializedData();
|
||||
aesIv.writeRaw(sha1_a, 8, 12);
|
||||
aesIv.writeRaw(sha1_b, 0, 8);
|
||||
aesIv.writeRaw(sha1_c, 16, 4);
|
||||
aesIv.writeRaw(sha1_d, 0, 8);
|
||||
keyData.aesIv = aesIv.toByteArray();
|
||||
|
||||
return keyData;
|
||||
}
|
||||
|
||||
public static TLObject decompress(byte[] data, TLObject parentObject) {
|
||||
final int BUFFER_SIZE = 512;
|
||||
ByteArrayInputStream is = new ByteArrayInputStream(data);
|
||||
GZIPInputStream gis;
|
||||
try {
|
||||
gis = new GZIPInputStream(is, BUFFER_SIZE);
|
||||
ByteArrayOutputStream bytesOutput = new ByteArrayOutputStream();
|
||||
data = new byte[BUFFER_SIZE];
|
||||
int bytesRead;
|
||||
while ((bytesRead = gis.read(data)) != -1) {
|
||||
bytesOutput.write(data, 0, bytesRead);
|
||||
}
|
||||
gis.close();
|
||||
is.close();
|
||||
SerializedData stream = new SerializedData(bytesOutput.toByteArray());
|
||||
return TLClassStore.Instance().TLdeserialize(stream, stream.readInt32(), parentObject);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final String TAG = "Typefaces";
|
||||
private static final Hashtable<String, Typeface> cache = new Hashtable<String, Typeface>();
|
||||
|
||||
public static Typeface getTypeface(String assetPath) {
|
||||
synchronized (cache) {
|
||||
if (!cache.containsKey(assetPath)) {
|
||||
try {
|
||||
Typeface t = Typeface.createFromAsset(applicationContext.getAssets(),
|
||||
assetPath);
|
||||
cache.put(assetPath, t);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Could not get typeface '" + assetPath
|
||||
+ "' because " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return cache.get(assetPath);
|
||||
}
|
||||
}
|
||||
|
||||
public static void showKeyboard(View view) {
|
||||
if (view == null) {
|
||||
return;
|
||||
}
|
||||
InputMethodManager inputManager = (InputMethodManager)view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
inputManager.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
|
||||
|
||||
((InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE)).showSoftInput(view, 0);
|
||||
}
|
||||
|
||||
public static boolean isKeyboardShowed(View view) {
|
||||
if (view == null) {
|
||||
return false;
|
||||
}
|
||||
InputMethodManager inputManager = (InputMethodManager) view
|
||||
.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
return inputManager.isActive(view);
|
||||
}
|
||||
|
||||
public static void hideKeyboard(View view) {
|
||||
if (view == null) {
|
||||
return;
|
||||
}
|
||||
InputMethodManager imm = (InputMethodManager) view.getContext()
|
||||
.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
if (!imm.isActive())
|
||||
return;
|
||||
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
||||
}
|
||||
|
||||
public static ProgressDialog progressDialog;
|
||||
public static void ShowProgressDialog(final Activity activity, final String message) {
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
progressDialog = new ProgressDialog(activity);
|
||||
if (message != null) {
|
||||
progressDialog.setMessage(message);
|
||||
}
|
||||
progressDialog.setCanceledOnTouchOutside(false);
|
||||
progressDialog.setCancelable(false);
|
||||
progressDialog.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static FastDateFormat formatterDay;
|
||||
public static FastDateFormat formatterMonth;
|
||||
public static FastDateFormat formatterYear;
|
||||
public static FastDateFormat formatterYearMax;
|
||||
public static FastDateFormat chatDate;
|
||||
public static FastDateFormat chatFullDate;
|
||||
|
||||
static {
|
||||
Locale locale = Locale.getDefault();
|
||||
String lang = locale.getLanguage();
|
||||
formatterMonth = FastDateFormat.getInstance("dd MMM", locale);
|
||||
formatterYear = FastDateFormat.getInstance("dd.MM.yy", locale);
|
||||
formatterYearMax = FastDateFormat.getInstance("dd.MM.yyyy", locale);
|
||||
chatDate = FastDateFormat.getInstance("d MMMM", locale);
|
||||
chatFullDate = FastDateFormat.getInstance("d MMMM yyyy", locale);
|
||||
if (lang != null && lang.toLowerCase().equals("ar")) {
|
||||
formatterDay = FastDateFormat.getInstance("h:mm a", locale);
|
||||
} else {
|
||||
formatterDay = FastDateFormat.getInstance("h:mm a", Locale.US);}
|
||||
|
||||
}
|
||||
|
||||
public static String formatDateChat(long date) {
|
||||
Calendar rightNow = Calendar.getInstance();
|
||||
int year = rightNow.get(Calendar.YEAR);
|
||||
|
||||
rightNow.setTimeInMillis(date * 1000);
|
||||
int dateYear = rightNow.get(Calendar.YEAR);
|
||||
|
||||
if (year == dateYear) {
|
||||
return chatDate.format(date * 1000);
|
||||
}
|
||||
return chatFullDate.format(date * 1000);
|
||||
}
|
||||
|
||||
public static String formatDate(long date) {
|
||||
Calendar rightNow = Calendar.getInstance();
|
||||
int day = rightNow.get(Calendar.DAY_OF_YEAR);
|
||||
int year = rightNow.get(Calendar.YEAR);
|
||||
rightNow.setTimeInMillis(date * 1000);
|
||||
int dateDay = rightNow.get(Calendar.DAY_OF_YEAR);
|
||||
int dateYear = rightNow.get(Calendar.YEAR);
|
||||
|
||||
if (dateDay == day && year == dateYear) {
|
||||
return formatterDay.format(new Date(date * 1000));
|
||||
} else if (dateDay + 1 == day && year == dateYear) {
|
||||
return applicationContext.getResources().getString(R.string.Yesterday);
|
||||
} else if (year == dateYear) {
|
||||
return formatterMonth.format(new Date(date * 1000));
|
||||
} else {
|
||||
return formatterYear.format(new Date(date * 1000));
|
||||
}
|
||||
}
|
||||
|
||||
public static String formatDateOnline(long date) {
|
||||
Calendar rightNow = Calendar.getInstance();
|
||||
int day = rightNow.get(Calendar.DAY_OF_YEAR);
|
||||
int year = rightNow.get(Calendar.YEAR);
|
||||
rightNow.setTimeInMillis(date * 1000);
|
||||
int dateDay = rightNow.get(Calendar.DAY_OF_YEAR);
|
||||
int dateYear = rightNow.get(Calendar.YEAR);
|
||||
|
||||
if (dateDay == day && year == dateYear) {
|
||||
return String.format("%s %s", applicationContext.getResources().getString(R.string.TodayAt), formatterDay.format(new Date(date * 1000)));
|
||||
} else if (dateDay + 1 == day && year == dateYear) {
|
||||
return String.format("%s %s", applicationContext.getResources().getString(R.string.YesterdayAt), formatterDay.format(new Date(date * 1000)));
|
||||
} else if (year == dateYear) {
|
||||
return String.format("%s %s %s", formatterMonth.format(new Date(date * 1000)), applicationContext.getResources().getString(R.string.OtherAt), formatterDay.format(new Date(date * 1000)));
|
||||
} else {
|
||||
return String.format("%s %s %s", formatterYear.format(new Date(date * 1000)), applicationContext.getResources().getString(R.string.OtherAt), formatterDay.format(new Date(date * 1000)));
|
||||
}
|
||||
}
|
||||
|
||||
public static void HideProgressDialog(Activity activity) {
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (progressDialog != null) {
|
||||
progressDialog.dismiss();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static boolean copyFile(File sourceFile, File destFile) throws IOException {
|
||||
if(!destFile.exists()) {
|
||||
destFile.createNewFile();
|
||||
}
|
||||
FileChannel source = null;
|
||||
FileChannel destination = null;
|
||||
boolean result = true;
|
||||
try {
|
||||
source = new FileInputStream(sourceFile).getChannel();
|
||||
destination = new FileOutputStream(destFile).getChannel();
|
||||
destination.transferFrom(source, 0, source.size());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
result = false;
|
||||
} finally {
|
||||
if(source != null) {
|
||||
source.close();
|
||||
}
|
||||
if(destination != null) {
|
||||
destination.close();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void RunOnUIThread(Runnable runnable) {
|
||||
synchronized (lock) {
|
||||
if (applicationHandler == null) {
|
||||
applicationHandler = new Handler(applicationContext.getMainLooper());
|
||||
}
|
||||
applicationHandler.post(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
public static int[] arrColors = {0xffee4928, 0xff41a903, 0xffe09602, 0xff0f94ed, 0xff8f3bf7, 0xfffc4380, 0xff00a1c4, 0xffeb7002};
|
||||
public static int[] arrUsersAvatars = {
|
||||
R.drawable.user_placeholder_red,
|
||||
R.drawable.user_placeholder_green,
|
||||
R.drawable.user_placeholder_yellow,
|
||||
R.drawable.user_placeholder_blue,
|
||||
R.drawable.user_placeholder_purple,
|
||||
R.drawable.user_placeholder_pink,
|
||||
R.drawable.user_placeholder_cyan,
|
||||
R.drawable.user_placeholder_orange};
|
||||
|
||||
public static int[] arrGroupsAvatars = {
|
||||
R.drawable.group_placeholder_red,
|
||||
R.drawable.group_placeholder_green,
|
||||
R.drawable.group_placeholder_yellow,
|
||||
R.drawable.group_placeholder_blue,
|
||||
R.drawable.group_placeholder_purple,
|
||||
R.drawable.group_placeholder_pink,
|
||||
R.drawable.group_placeholder_cyan,
|
||||
R.drawable.group_placeholder_orange};
|
||||
|
||||
public static int getColorIndex(int id) {
|
||||
try {
|
||||
String str = String.format(Locale.US, "%d%d", id, UserConfig.clientUserId);
|
||||
if (str.length() > 15) {
|
||||
str = str.substring(0, 15);
|
||||
}
|
||||
java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
|
||||
byte[] digest = md.digest(str.getBytes());
|
||||
int b = digest[Math.abs(id % 16)];
|
||||
if (b < 0) {
|
||||
b += 256;
|
||||
}
|
||||
return Math.abs(b) % arrColors.length;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return id % arrColors.length;
|
||||
}
|
||||
|
||||
public static int getColorForId(int id) {
|
||||
if (id == 333000) {
|
||||
return 0xff0f94ed;
|
||||
}
|
||||
return arrColors[getColorIndex(id)];
|
||||
}
|
||||
|
||||
public static int getUserAvatarForId(int id) {
|
||||
if (id == 333000) {
|
||||
return R.drawable.telegram_avatar;
|
||||
}
|
||||
return arrUsersAvatars[getColorIndex(id)];
|
||||
}
|
||||
|
||||
public static int getGroupAvatarForId(int id) {
|
||||
return arrGroupsAvatars[getColorIndex(id)];
|
||||
}
|
||||
|
||||
public static String MD5(String md5) {
|
||||
try {
|
||||
java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
|
||||
byte[] array = md.digest(md5.getBytes());
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte anArray : array) {
|
||||
sb.append(Integer.toHexString((anArray & 0xFF) | 0x100).substring(1, 3));
|
||||
}
|
||||
return sb.toString();
|
||||
} catch (java.security.NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void addMediaToGallery(String fromPath) {
|
||||
if (fromPath == null) {
|
||||
return;
|
||||
}
|
||||
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
|
||||
File f = new File(fromPath);
|
||||
Uri contentUri = Uri.fromFile(f);
|
||||
mediaScanIntent.setData(contentUri);
|
||||
applicationContext.sendBroadcast(mediaScanIntent);
|
||||
}
|
||||
|
||||
public static void addMediaToGallery(Uri uri) {
|
||||
if (uri == null) {
|
||||
return;
|
||||
}
|
||||
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
|
||||
mediaScanIntent.setData(uri);
|
||||
applicationContext.sendBroadcast(mediaScanIntent);
|
||||
}
|
||||
|
||||
private static File getAlbumDir() {
|
||||
File storageDir = null;
|
||||
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
|
||||
storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), applicationContext.getResources().getString(R.string.AppName));
|
||||
if (storageDir != null) {
|
||||
if (! storageDir.mkdirs()) {
|
||||
if (! storageDir.exists()){
|
||||
Log.d("tmessages", "failed to create directory");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
Log.v("tmessages", "External storage is not mounted READ/WRITE.");
|
||||
}
|
||||
|
||||
return storageDir;
|
||||
}
|
||||
|
||||
public static File generatePicturePath() {
|
||||
try {
|
||||
File storageDir = getAlbumDir();
|
||||
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
||||
String imageFileName = "IMG_" + timeStamp + "_";
|
||||
return File.createTempFile(imageFileName, ".jpg", storageDir);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static CharSequence generateSearchName(String name, String name2, String q) {
|
||||
if (name == null && name2 == null) {
|
||||
return "";
|
||||
}
|
||||
int index;
|
||||
SpannableStringBuilder builder = new SpannableStringBuilder();
|
||||
String wholeString = name;
|
||||
if (wholeString == null || wholeString.length() == 0) {
|
||||
wholeString = name2;
|
||||
} else if (name2 != null && name2.length() != 0) {
|
||||
wholeString += " " + name2;
|
||||
}
|
||||
String[] args = wholeString.split(" ");
|
||||
|
||||
for (String arg : args) {
|
||||
String str = arg;
|
||||
if (str != null) {
|
||||
String lower = str.toLowerCase();
|
||||
if (lower.startsWith(q)) {
|
||||
if (builder.length() != 0) {
|
||||
builder.append(" ");
|
||||
}
|
||||
String query = str.substring(0, q.length());
|
||||
builder.append(Html.fromHtml("<font color=\"#1274c9\">" + query + "</font>"));
|
||||
str = str.substring(q.length());
|
||||
builder.append(str);
|
||||
} else {
|
||||
if (builder.length() != 0) {
|
||||
builder.append(" ");
|
||||
}
|
||||
builder.append(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static File generateVideoPath() {
|
||||
try {
|
||||
File storageDir = getAlbumDir();
|
||||
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
||||
String imageFileName = "VID_" + timeStamp + "_";
|
||||
return File.createTempFile(imageFileName, ".mp4", storageDir);
|
||||
/*
|
||||
|
||||
String fileName = "VID" + id + ".mp4";
|
||||
return new File(Utilities.applicationContext.getCacheDir(), fileName);
|
||||
*/
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String formatName(String firstName, String lastName) {
|
||||
String result = firstName;
|
||||
if (result == null || result.length() == 0) {
|
||||
result = lastName;
|
||||
} else if (result.length() != 0 && lastName.length() != 0) {
|
||||
result += " " + lastName;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.objects;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import org.telegram.TL.TLRPC;
|
||||
import org.telegram.messenger.Emoji;
|
||||
import org.telegram.messenger.MessagesController;
|
||||
import org.telegram.messenger.R;
|
||||
import org.telegram.messenger.UserConfig;
|
||||
import org.telegram.messenger.Utilities;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
public class MessageObject {
|
||||
public TLRPC.Message messageOwner;
|
||||
public CharSequence messageText;
|
||||
public int type;
|
||||
public ArrayList<PhotoObject> photoThumbs;
|
||||
public Bitmap imagePreview;
|
||||
public PhotoObject previewPhoto;
|
||||
public String dateKey;
|
||||
public boolean deleted = false;
|
||||
|
||||
public MessageObject(TLRPC.Message message, AbstractMap<Integer, TLRPC.User> users) {
|
||||
messageOwner = message;
|
||||
|
||||
if (message instanceof TLRPC.TL_messageService) {
|
||||
if (message.action != null) {
|
||||
TLRPC.User fromUser = users.get(message.from_id);
|
||||
if (fromUser == null) {
|
||||
fromUser = MessagesController.Instance.users.get(message.from_id);
|
||||
}
|
||||
if (message.action instanceof TLRPC.TL_messageActionChatCreate) {
|
||||
messageText = Utilities.applicationContext.getResources().getString(R.string.ActionCreateGroup).replace("un1", Utilities.formatName(fromUser.first_name, fromUser.last_name));
|
||||
} else if (message.action instanceof TLRPC.TL_messageActionChatDeleteUser) {
|
||||
if (message.action.user_id == message.from_id) {
|
||||
messageText = Utilities.applicationContext.getResources().getString(R.string.ActionLeftUser).replace("un1", Utilities.formatName(fromUser.first_name, fromUser.last_name));
|
||||
} else {
|
||||
TLRPC.User who = users.get(message.action.user_id);
|
||||
String str = Utilities.applicationContext.getResources().getString(R.string.ActionKickUser);
|
||||
messageText = str.replace("un2", Utilities.formatName(who.first_name, who.last_name)).replace("un1", Utilities.formatName(fromUser.first_name, fromUser.last_name));
|
||||
}
|
||||
} else if (message.action instanceof TLRPC.TL_messageActionChatAddUser) {
|
||||
TLRPC.User whoUser = users.get(message.action.user_id);
|
||||
String str = Utilities.applicationContext.getResources().getString(R.string.ActionAddUser);
|
||||
messageText = str.replace("un2", Utilities.formatName(whoUser.first_name, whoUser.last_name)).replace("un1", Utilities.formatName(fromUser.first_name, fromUser.last_name));
|
||||
} else if (message.action instanceof TLRPC.TL_messageActionChatEditPhoto) {
|
||||
photoThumbs = new ArrayList<PhotoObject>();
|
||||
for (TLRPC.PhotoSize size : message.action.photo.sizes) {
|
||||
photoThumbs.add(new PhotoObject(size));
|
||||
}
|
||||
messageText = Utilities.applicationContext.getResources().getString(R.string.ActionChangedPhoto).replace("un1", Utilities.formatName(fromUser.first_name, fromUser.last_name));
|
||||
} else if (message.action instanceof TLRPC.TL_messageActionChatEditTitle) {
|
||||
messageText = Utilities.applicationContext.getResources().getString(R.string.ActionChangedTitle).replace("un1", Utilities.formatName(fromUser.first_name, fromUser.last_name)).replace("un2", message.action.title);
|
||||
} else if (message.action instanceof TLRPC.TL_messageActionChatDeletePhoto) {
|
||||
messageText = Utilities.applicationContext.getResources().getString(R.string.ActionRemovedPhoto).replace("un1", Utilities.formatName(fromUser.first_name, fromUser.last_name));
|
||||
} else if (message.action instanceof TLRPC.TL_messageActionTTLChange) {
|
||||
if (message.action.ttl != 0) {
|
||||
String timeString;
|
||||
if (message.action.ttl == 2) {
|
||||
timeString = Utilities.applicationContext.getResources().getString(R.string.MessageLifetime2s);
|
||||
} else if (message.action.ttl == 5) {
|
||||
timeString = Utilities.applicationContext.getResources().getString(R.string.MessageLifetime5s);
|
||||
} else if (message.action.ttl == 60) {
|
||||
timeString = Utilities.applicationContext.getResources().getString(R.string.MessageLifetime1m);
|
||||
} else if (message.action.ttl == 60 * 60) {
|
||||
timeString = Utilities.applicationContext.getResources().getString(R.string.MessageLifetime1h);
|
||||
} else if (message.action.ttl == 60 * 60 * 24) {
|
||||
timeString = Utilities.applicationContext.getResources().getString(R.string.MessageLifetime1d);
|
||||
} else if (message.action.ttl == 60 * 60 * 24 * 7) {
|
||||
timeString = Utilities.applicationContext.getResources().getString(R.string.MessageLifetime1w);
|
||||
} else {
|
||||
timeString = String.format("%d", message.action.ttl);
|
||||
}
|
||||
if (message.from_id == UserConfig.clientUserId) {
|
||||
messageText = String.format(Utilities.applicationContext.getResources().getString(R.string.MessageLifetimeChangedOutgoing), timeString);
|
||||
} else {
|
||||
messageText = String.format(Utilities.applicationContext.getResources().getString(R.string.MessageLifetimeChanged), fromUser.first_name, timeString);
|
||||
}
|
||||
} else {
|
||||
if (message.from_id == UserConfig.clientUserId) {
|
||||
messageText = String.format(Utilities.applicationContext.getResources().getString(R.string.MessageLifetimeRemoved), Utilities.applicationContext.getResources().getString(R.string.FromYou));
|
||||
} else {
|
||||
messageText = String.format(Utilities.applicationContext.getResources().getString(R.string.MessageLifetimeRemoved), fromUser.first_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (message.media != null && !(message.media instanceof TLRPC.TL_messageMediaEmpty)) {
|
||||
if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
|
||||
photoThumbs = new ArrayList<PhotoObject>();
|
||||
for (TLRPC.PhotoSize size : message.media.photo.sizes) {
|
||||
PhotoObject obj = new PhotoObject(size);
|
||||
photoThumbs.add(obj);
|
||||
if (imagePreview == null && obj.image != null) {
|
||||
imagePreview = obj.image;
|
||||
}
|
||||
}
|
||||
messageText = Utilities.applicationContext.getResources().getString(R.string.AttachPhoto);
|
||||
} else if (message.media instanceof TLRPC.TL_messageMediaVideo) {
|
||||
photoThumbs = new ArrayList<PhotoObject>();
|
||||
PhotoObject obj = new PhotoObject(message.media.video.thumb);
|
||||
photoThumbs.add(obj);
|
||||
if (imagePreview == null && obj.image != null) {
|
||||
imagePreview = obj.image;
|
||||
}
|
||||
messageText = Utilities.applicationContext.getResources().getString(R.string.AttachVideo);
|
||||
} else if (message.media instanceof TLRPC.TL_messageMediaGeo) {
|
||||
messageText = Utilities.applicationContext.getResources().getString(R.string.AttachLocation);
|
||||
} else if (message.media instanceof TLRPC.TL_messageMediaContact) {
|
||||
messageText = Utilities.applicationContext.getResources().getString(R.string.AttachContact);
|
||||
}
|
||||
} else {
|
||||
messageText = message.message;
|
||||
}
|
||||
messageText = Emoji.replaceEmoji(messageText);
|
||||
|
||||
|
||||
if (message instanceof TLRPC.TL_message || (message instanceof TLRPC.TL_messageForwarded && (message.media == null || !(message.media instanceof TLRPC.TL_messageMediaEmpty)))) {
|
||||
if (message.media == null || message.media instanceof TLRPC.TL_messageMediaEmpty) {
|
||||
if (message.from_id == UserConfig.clientUserId) {
|
||||
type = 0;
|
||||
} else {
|
||||
type = 1;
|
||||
}
|
||||
} else if (message.media != null && message.media instanceof TLRPC.TL_messageMediaPhoto) {
|
||||
if (message.from_id == UserConfig.clientUserId) {
|
||||
type = 2;
|
||||
} else {
|
||||
type = 3;
|
||||
}
|
||||
} else if (message.media != null && message.media instanceof TLRPC.TL_messageMediaGeo) {
|
||||
if (message.from_id == UserConfig.clientUserId) {
|
||||
type = 4;
|
||||
} else {
|
||||
type = 5;
|
||||
}
|
||||
} else if (message.media != null && message.media instanceof TLRPC.TL_messageMediaVideo) {
|
||||
if (message.from_id == UserConfig.clientUserId) {
|
||||
type = 6;
|
||||
} else {
|
||||
type = 7;
|
||||
}
|
||||
} else if (message.media != null && message.media instanceof TLRPC.TL_messageMediaContact) {
|
||||
if (message.from_id == UserConfig.clientUserId) {
|
||||
type = 12;
|
||||
} else {
|
||||
type = 13;
|
||||
}
|
||||
}
|
||||
} else if (message instanceof TLRPC.TL_messageService) {
|
||||
if (message.action instanceof TLRPC.TL_messageActionChatEditPhoto) {
|
||||
type = 11;
|
||||
} else {
|
||||
type = 10;
|
||||
}
|
||||
} else if (message instanceof TLRPC.TL_messageForwarded) {
|
||||
if (message.from_id == UserConfig.clientUserId) {
|
||||
type = 8;
|
||||
} else {
|
||||
type = 9;
|
||||
}
|
||||
}
|
||||
|
||||
Calendar rightNow = new GregorianCalendar();
|
||||
rightNow.setTimeInMillis((long)(messageOwner.date) * 1000);
|
||||
int dateDay = rightNow.get(Calendar.DAY_OF_YEAR);
|
||||
int dateYear = rightNow.get(Calendar.YEAR);
|
||||
int dateMonth = rightNow.get(Calendar.MONTH);
|
||||
dateKey = String.format("%d_%02d_%02d", dateYear, dateMonth, dateDay);
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.objects;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
|
||||
import org.telegram.TL.TLRPC;
|
||||
import org.telegram.messenger.FileLoader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class PhotoObject {
|
||||
public TLRPC.PhotoSize photoOwner;
|
||||
public Bitmap image;
|
||||
|
||||
public PhotoObject(TLRPC.PhotoSize photo) {
|
||||
photoOwner = photo;
|
||||
|
||||
if (photo instanceof TLRPC.TL_photoCachedSize) {
|
||||
BitmapFactory.Options opts = new BitmapFactory.Options();
|
||||
opts.inPreferredConfig = Bitmap.Config.RGB_565;
|
||||
opts.inDither = false;
|
||||
opts.outWidth = photo.w;
|
||||
opts.outHeight = photo.h;
|
||||
image = BitmapFactory.decodeByteArray(photoOwner.bytes, 0, photoOwner.bytes.length, opts);
|
||||
if (FileLoader.Instance.runtimeHack != null) {
|
||||
FileLoader.Instance.runtimeHack.trackFree(image.getRowBytes() * image.getHeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static PhotoObject getClosestImageWithSize(ArrayList<PhotoObject> arr, int width, int height) {
|
||||
int closestWidth = 9999;
|
||||
int closestHeight = 9999;
|
||||
PhotoObject closestObject = null;
|
||||
for (PhotoObject obj : arr) {
|
||||
int diffW = Math.abs(obj.photoOwner.w - width);
|
||||
int diffH = Math.abs(obj.photoOwner.h - height);
|
||||
if (closestObject == null || closestWidth > diffW && closestHeight > diffH || closestObject.photoOwner instanceof TLRPC.TL_photoCachedSize) {
|
||||
closestObject = obj;
|
||||
closestWidth = diffW;
|
||||
closestHeight = diffH;
|
||||
}
|
||||
}
|
||||
return closestObject;
|
||||
}
|
||||
|
||||
public static TLRPC.PhotoSize getClosestPhotoSizeWithSize(ArrayList<TLRPC.PhotoSize> sizes, int width, int height) {
|
||||
int closestWidth = 9999;
|
||||
int closestHeight = 9999;
|
||||
TLRPC.PhotoSize closestObject = null;
|
||||
for (TLRPC.PhotoSize obj : sizes) {
|
||||
int diffW = Math.abs(obj.w - width);
|
||||
int diffH = Math.abs(obj.h - height);
|
||||
if (closestObject == null || closestWidth > diffW && closestHeight > diffH) {
|
||||
closestObject = obj;
|
||||
closestWidth = diffW;
|
||||
closestHeight = diffH;
|
||||
}
|
||||
}
|
||||
return closestObject;
|
||||
}
|
||||
}
|
@ -0,0 +1,647 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.ui;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.text.Html;
|
||||
import android.view.Display;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.actionbarsherlock.app.ActionBar;
|
||||
import com.actionbarsherlock.app.SherlockFragmentActivity;
|
||||
import com.actionbarsherlock.internal.app.ActionBarImpl;
|
||||
|
||||
import org.telegram.messenger.ConnectionsManager;
|
||||
import org.telegram.messenger.MessagesController;
|
||||
import org.telegram.messenger.NotificationCenter;
|
||||
import org.telegram.messenger.R;
|
||||
import org.telegram.messenger.UserConfig;
|
||||
import org.telegram.messenger.Utilities;
|
||||
import org.telegram.objects.MessageObject;
|
||||
import org.telegram.ui.Views.BaseFragment;
|
||||
import org.telegram.ui.Views.NotificationView;
|
||||
|
||||
import net.hockeyapp.android.CrashManager;
|
||||
import net.hockeyapp.android.UpdateManager;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class ApplicationActivity extends SherlockFragmentActivity implements NotificationCenter.NotificationCenterDelegate, MessagesActivity.MessagesActivityDelegate {
|
||||
private View shadowView;
|
||||
private boolean finished = false;
|
||||
private NotificationView notificationView;
|
||||
String photoPath = null;
|
||||
String videoPath = null;
|
||||
String sendingText = null;
|
||||
private int currentConnectionState;
|
||||
private View statusView;
|
||||
private View backStatusButton;
|
||||
private View statusBackground;
|
||||
private TextView statusText;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
NotificationCenter.Instance.postNotificationName(702, this);
|
||||
currentConnectionState = ConnectionsManager.Instance.connectionState;
|
||||
for (BaseFragment fragment : ApplicationLoader.fragmentsStack) {
|
||||
if (fragment.fragmentView != null) {
|
||||
ViewGroup parent = (ViewGroup)fragment.fragmentView.getParent();
|
||||
if (parent != null) {
|
||||
parent.removeView(fragment.fragmentView);
|
||||
}
|
||||
fragment.parentActivity = null;
|
||||
fragment.fragmentView = null;
|
||||
}
|
||||
}
|
||||
setContentView(R.layout.application_layout);
|
||||
notificationView = (NotificationView) getLayoutInflater().inflate(R.layout.notification_layout, null);
|
||||
shadowView = findViewById(R.id.shadow);
|
||||
NotificationCenter.Instance.addObserver(this, 1234);
|
||||
NotificationCenter.Instance.addObserver(this, 658);
|
||||
NotificationCenter.Instance.addObserver(this, 701);
|
||||
NotificationCenter.Instance.addObserver(this, 702);
|
||||
NotificationCenter.Instance.addObserver(this, 703);
|
||||
NotificationCenter.Instance.addObserver(this, GalleryImageViewer.needShowAllMedia);
|
||||
getSupportActionBar().setLogo(R.drawable.ab_icon_fixed2);
|
||||
|
||||
statusView = getLayoutInflater().inflate(R.layout.updating_state_layout, null);
|
||||
statusBackground = statusView.findViewById(R.id.back_button_background);
|
||||
backStatusButton = statusView.findViewById(R.id.back_button);
|
||||
statusText = (TextView)statusView.findViewById(R.id.status_text);
|
||||
statusBackground.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (ApplicationLoader.fragmentsStack.size() > 1) {
|
||||
onBackPressed();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (ApplicationLoader.fragmentsStack.isEmpty()) {
|
||||
MessagesActivity fragment = new MessagesActivity();
|
||||
fragment.onFragmentCreate();
|
||||
ApplicationLoader.fragmentsStack.add(fragment);
|
||||
}
|
||||
|
||||
boolean pushOpened = false;
|
||||
|
||||
Integer push_user_id = (Integer)NotificationCenter.Instance.getFromMemCache("push_user_id", 0);
|
||||
Integer push_chat_id = (Integer)NotificationCenter.Instance.getFromMemCache("push_chat_id", 0);
|
||||
Integer push_enc_id = (Integer)NotificationCenter.Instance.getFromMemCache("push_enc_id", 0);
|
||||
Integer open_settings = (Integer)NotificationCenter.Instance.getFromMemCache("open_settings", 0);
|
||||
photoPath = (String)NotificationCenter.Instance.getFromMemCache(533);
|
||||
videoPath = (String)NotificationCenter.Instance.getFromMemCache(534);
|
||||
sendingText = (String)NotificationCenter.Instance.getFromMemCache(535);
|
||||
|
||||
if (push_user_id != 0) {
|
||||
if (push_user_id == UserConfig.clientUserId) {
|
||||
open_settings = 1;
|
||||
} else {
|
||||
ChatActivity fragment = new ChatActivity();
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt("user_id", push_user_id);
|
||||
fragment.setArguments(bundle);
|
||||
if (fragment.onFragmentCreate()) {
|
||||
pushOpened = true;
|
||||
ApplicationLoader.fragmentsStack.add(fragment);
|
||||
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment, "chat_user_" + push_user_id).commitAllowingStateLoss();
|
||||
}
|
||||
}
|
||||
} else if (push_chat_id != 0) {
|
||||
ChatActivity fragment = new ChatActivity();
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt("chat_id", push_chat_id);
|
||||
fragment.setArguments(bundle);
|
||||
if (fragment.onFragmentCreate()) {
|
||||
pushOpened = true;
|
||||
ApplicationLoader.fragmentsStack.add(fragment);
|
||||
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment, "chat_group_" + push_chat_id).commitAllowingStateLoss();
|
||||
}
|
||||
} else if (push_enc_id != 0) {
|
||||
ChatActivity fragment = new ChatActivity();
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt("enc_id", push_enc_id);
|
||||
fragment.setArguments(bundle);
|
||||
if (fragment.onFragmentCreate()) {
|
||||
pushOpened = true;
|
||||
ApplicationLoader.fragmentsStack.add(fragment);
|
||||
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment, "chat_enc_" + push_enc_id).commitAllowingStateLoss();
|
||||
}
|
||||
}
|
||||
if (videoPath != null || photoPath != null || sendingText != null) {
|
||||
MessagesActivity fragment = new MessagesActivity();
|
||||
fragment.selectAlertString = R.string.ForwardMessagesTo;
|
||||
fragment.animationType = 1;
|
||||
Bundle args = new Bundle();
|
||||
args.putBoolean("onlySelect", true);
|
||||
fragment.setArguments(args);
|
||||
fragment.delegate = this;
|
||||
ApplicationLoader.fragmentsStack.add(fragment);
|
||||
fragment.onFragmentCreate();
|
||||
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment, fragment.getTag()).commitAllowingStateLoss();
|
||||
pushOpened = true;
|
||||
}
|
||||
if (open_settings != 0) {
|
||||
SettingsActivity fragment = new SettingsActivity();
|
||||
ApplicationLoader.fragmentsStack.add(fragment);
|
||||
fragment.onFragmentCreate();
|
||||
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment, "settings").commitAllowingStateLoss();
|
||||
pushOpened = true;
|
||||
}
|
||||
if (!pushOpened) {
|
||||
BaseFragment fragment = ApplicationLoader.fragmentsStack.get(ApplicationLoader.fragmentsStack.size() - 1);
|
||||
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment, fragment.getTag()).commitAllowingStateLoss();
|
||||
}
|
||||
|
||||
getWindow().setBackgroundDrawableResource(R.drawable.transparent);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void prepareForHideShowActionBar() {
|
||||
try {
|
||||
Class aClass = getSupportActionBar().getClass();
|
||||
if (aClass == ActionBarImpl.class) {
|
||||
Method method = aClass.getDeclaredMethod("setShowHideAnimationEnabled", boolean.class);
|
||||
method.invoke(getSupportActionBar(), false);
|
||||
} else {
|
||||
Field field = aClass.getDeclaredField("mActionBar");
|
||||
field.setAccessible(true);
|
||||
Method method = field.get(getSupportActionBar()).getClass().getDeclaredMethod("setShowHideAnimationEnabled", boolean.class);
|
||||
method.invoke(field.get(getSupportActionBar()), false);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void showActionBar() {
|
||||
prepareForHideShowActionBar();
|
||||
shadowView.setVisibility(View.VISIBLE);
|
||||
getSupportActionBar().show();
|
||||
}
|
||||
|
||||
public void hideActionBar() {
|
||||
prepareForHideShowActionBar();
|
||||
shadowView.setVisibility(View.INVISIBLE);
|
||||
getSupportActionBar().hide();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
photoPath = (String)NotificationCenter.Instance.getFromMemCache(533);
|
||||
videoPath = (String)NotificationCenter.Instance.getFromMemCache(534);
|
||||
sendingText = (String)NotificationCenter.Instance.getFromMemCache(535);
|
||||
if (videoPath != null || photoPath != null || sendingText != null) {
|
||||
MessagesActivity fragment = new MessagesActivity();
|
||||
fragment.selectAlertString = R.string.ForwardMessagesTo;
|
||||
fragment.animationType = 1;
|
||||
Bundle args = new Bundle();
|
||||
args.putBoolean("onlySelect", true);
|
||||
fragment.setArguments(args);
|
||||
fragment.delegate = this;
|
||||
ApplicationLoader.fragmentsStack.add(fragment);
|
||||
fragment.onFragmentCreate();
|
||||
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment, fragment.getTag()).commitAllowingStateLoss();
|
||||
}
|
||||
|
||||
Integer push_user_id = (Integer)NotificationCenter.Instance.getFromMemCache("push_user_id", 0);
|
||||
Integer push_chat_id = (Integer)NotificationCenter.Instance.getFromMemCache("push_chat_id", 0);
|
||||
Integer push_enc_id = (Integer)NotificationCenter.Instance.getFromMemCache("push_enc_id", 0);
|
||||
Integer open_settings = (Integer)NotificationCenter.Instance.getFromMemCache("open_settings", 0);
|
||||
|
||||
if (push_user_id != 0) {
|
||||
if (push_user_id == UserConfig.clientUserId) {
|
||||
open_settings = 1;
|
||||
} else {
|
||||
ChatActivity fragment = new ChatActivity();
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt("user_id", push_user_id);
|
||||
fragment.setArguments(bundle);
|
||||
if (fragment.onFragmentCreate()) {
|
||||
ApplicationLoader.fragmentsStack.add(fragment);
|
||||
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment, "chat_user_" + push_user_id).commitAllowingStateLoss();
|
||||
}
|
||||
}
|
||||
} else if (push_chat_id != 0) {
|
||||
ChatActivity fragment = new ChatActivity();
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt("chat_id", push_chat_id);
|
||||
fragment.setArguments(bundle);
|
||||
if (fragment.onFragmentCreate()) {
|
||||
ApplicationLoader.fragmentsStack.add(fragment);
|
||||
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment, "chat_group_" + push_chat_id).commitAllowingStateLoss();
|
||||
}
|
||||
} else if (push_enc_id != 0) {
|
||||
ChatActivity fragment = new ChatActivity();
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt("enc_id", push_enc_id);
|
||||
fragment.setArguments(bundle);
|
||||
if (fragment.onFragmentCreate()) {
|
||||
ApplicationLoader.fragmentsStack.add(fragment);
|
||||
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment, "chat_enc_" + push_enc_id).commitAllowingStateLoss();
|
||||
}
|
||||
}
|
||||
if (open_settings != 0) {
|
||||
SettingsActivity fragment = new SettingsActivity();
|
||||
ApplicationLoader.fragmentsStack.add(fragment);
|
||||
fragment.onFragmentCreate();
|
||||
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment, "settings").commitAllowingStateLoss();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didSelectDialog(MessagesActivity messageFragment, long dialog_id) {
|
||||
if (dialog_id != 0) {
|
||||
int lower_part = (int)dialog_id;
|
||||
|
||||
ChatActivity fragment = new ChatActivity();
|
||||
Bundle bundle = new Bundle();
|
||||
if (lower_part != 0) {
|
||||
if (lower_part > 0) {
|
||||
NotificationCenter.Instance.postNotificationName(MessagesController.closeChats);
|
||||
bundle.putInt("user_id", lower_part);
|
||||
fragment.setArguments(bundle);
|
||||
fragment.scrollToTopOnResume = true;
|
||||
presentFragment(fragment, "chat_user_" + lower_part, true, false);
|
||||
} else if (lower_part < 0) {
|
||||
NotificationCenter.Instance.postNotificationName(MessagesController.closeChats);
|
||||
bundle.putInt("chat_id", -lower_part);
|
||||
fragment.setArguments(bundle);
|
||||
fragment.scrollToTopOnResume = true;
|
||||
presentFragment(fragment, "chat_group_" + -lower_part, true, false);
|
||||
}
|
||||
} else {
|
||||
NotificationCenter.Instance.postNotificationName(MessagesController.closeChats);
|
||||
int chat_id = (int)(dialog_id >> 32);
|
||||
bundle.putInt("enc_id", chat_id);
|
||||
fragment.setArguments(bundle);
|
||||
fragment.scrollToTopOnResume = true;
|
||||
presentFragment(fragment, "chat_enc_" + chat_id, true, false);
|
||||
}
|
||||
if (photoPath != null) {
|
||||
fragment.processSendingPhoto(photoPath);
|
||||
} else if (videoPath != null) {
|
||||
fragment.processSendingVideo(videoPath);
|
||||
} else if (sendingText != null) {
|
||||
fragment.processSendingText(sendingText);
|
||||
}
|
||||
photoPath = null;
|
||||
videoPath = null;
|
||||
sendingText = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkForCrashes() {
|
||||
CrashManager.register(this, "your-hockeyapp-api-key-here");
|
||||
}
|
||||
|
||||
private void checkForUpdates() {
|
||||
if (ConnectionsManager.DEBUG_VERSION) {
|
||||
UpdateManager.register(this, "your-hockeyapp-api-key-here");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
ApplicationLoader.lastPauseTime = System.currentTimeMillis();
|
||||
if (notificationView != null) {
|
||||
notificationView.hide(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
processOnFinish();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
fixLayout();
|
||||
checkForCrashes();
|
||||
checkForUpdates();
|
||||
ApplicationLoader.lastPauseTime = 0;
|
||||
invalidateOptionsMenu();
|
||||
updateActionBar();
|
||||
try {
|
||||
NotificationManager mNotificationManager = (NotificationManager)this.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
mNotificationManager.cancel(1);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void processOnFinish() {
|
||||
if (finished) {
|
||||
return;
|
||||
}
|
||||
finished = true;
|
||||
NotificationCenter.Instance.removeObserver(this, 1234);
|
||||
NotificationCenter.Instance.removeObserver(this, 658);
|
||||
NotificationCenter.Instance.removeObserver(this, 701);
|
||||
NotificationCenter.Instance.removeObserver(this, 702);
|
||||
NotificationCenter.Instance.removeObserver(this, 703);
|
||||
NotificationCenter.Instance.removeObserver(this, GalleryImageViewer.needShowAllMedia);
|
||||
if (notificationView != null) {
|
||||
notificationView.hide(false);
|
||||
notificationView.destroy();
|
||||
notificationView = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(android.content.res.Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
fixLayout();
|
||||
}
|
||||
|
||||
private void fixLayout() {
|
||||
if (shadowView != null) {
|
||||
ViewTreeObserver obs = shadowView.getViewTreeObserver();
|
||||
obs.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
WindowManager manager = (WindowManager) getSystemService(WINDOW_SERVICE);
|
||||
Display display = manager.getDefaultDisplay();
|
||||
int rotation = display.getRotation();
|
||||
float density = Utilities.applicationContext.getResources().getDisplayMetrics().density;
|
||||
|
||||
int height;
|
||||
int currentActionBarHeight = getSupportActionBar().getHeight();
|
||||
if (currentActionBarHeight != 48 * density && currentActionBarHeight != 40 * density) {
|
||||
height = currentActionBarHeight;
|
||||
} else {
|
||||
height = (int) (48.0f * density);
|
||||
if (rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90) {
|
||||
height = (int) (40.0f * density);
|
||||
}
|
||||
}
|
||||
|
||||
if (notificationView != null) {
|
||||
notificationView.applyOrientationPaddings(rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90, density, height);
|
||||
}
|
||||
|
||||
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) shadowView.getLayoutParams();
|
||||
params.setMargins(0, height, 0, 0);
|
||||
shadowView.setLayoutParams(params);
|
||||
if (Build.VERSION.SDK_INT < 16) {
|
||||
shadowView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
|
||||
} else {
|
||||
shadowView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void didReceivedNotification(int id, Object... args) {
|
||||
if (id == 1234) {
|
||||
for (BaseFragment fragment : ApplicationLoader.fragmentsStack) {
|
||||
fragment.onFragmentDestroy();
|
||||
}
|
||||
ApplicationLoader.fragmentsStack.clear();
|
||||
Intent intent2 = new Intent(this, LaunchActivity.class);
|
||||
startActivity(intent2);
|
||||
processOnFinish();
|
||||
finish();
|
||||
} else if (id == GalleryImageViewer.needShowAllMedia) {
|
||||
long dialog_id = (Long)args[0];
|
||||
MediaActivity fragment = new MediaActivity();
|
||||
Bundle bundle = new Bundle();
|
||||
if (dialog_id != 0) {
|
||||
bundle.putLong("dialog_id", dialog_id);
|
||||
fragment.setArguments(bundle);
|
||||
presentFragment(fragment, "media_" + dialog_id, false);
|
||||
}
|
||||
} else if (id == 658) {
|
||||
Integer push_user_id = (Integer)NotificationCenter.Instance.getFromMemCache("push_user_id", 0);
|
||||
Integer push_chat_id = (Integer)NotificationCenter.Instance.getFromMemCache("push_chat_id", 0);
|
||||
Integer push_enc_id = (Integer)NotificationCenter.Instance.getFromMemCache("push_enc_id", 0);
|
||||
|
||||
if (push_user_id != 0) {
|
||||
NotificationCenter.Instance.postNotificationName(MessagesController.closeChats);
|
||||
ChatActivity fragment = new ChatActivity();
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt("user_id", push_user_id);
|
||||
fragment.setArguments(bundle);
|
||||
if (fragment.onFragmentCreate()) {
|
||||
if (ApplicationLoader.fragmentsStack.size() > 0) {
|
||||
BaseFragment lastFragment = ApplicationLoader.fragmentsStack.get(ApplicationLoader.fragmentsStack.size() - 1);
|
||||
lastFragment.willBeHidden();
|
||||
}
|
||||
ApplicationLoader.fragmentsStack.add(fragment);
|
||||
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment, "chat_user_" + push_user_id).commitAllowingStateLoss();
|
||||
}
|
||||
} else if (push_chat_id != 0) {
|
||||
NotificationCenter.Instance.postNotificationName(MessagesController.closeChats);
|
||||
ChatActivity fragment = new ChatActivity();
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt("chat_id", push_chat_id);
|
||||
fragment.setArguments(bundle);
|
||||
if (fragment.onFragmentCreate()) {
|
||||
if (ApplicationLoader.fragmentsStack.size() > 0) {
|
||||
BaseFragment lastFragment = ApplicationLoader.fragmentsStack.get(ApplicationLoader.fragmentsStack.size() - 1);
|
||||
lastFragment.willBeHidden();
|
||||
}
|
||||
ApplicationLoader.fragmentsStack.add(fragment);
|
||||
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment, "chat_group_" + push_chat_id).commitAllowingStateLoss();
|
||||
}
|
||||
} else if (push_enc_id != 0) {
|
||||
NotificationCenter.Instance.postNotificationName(MessagesController.closeChats);
|
||||
ChatActivity fragment = new ChatActivity();
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt("enc_id", push_enc_id);
|
||||
fragment.setArguments(bundle);
|
||||
if (fragment.onFragmentCreate()) {
|
||||
if (ApplicationLoader.fragmentsStack.size() > 0) {
|
||||
BaseFragment lastFragment = ApplicationLoader.fragmentsStack.get(ApplicationLoader.fragmentsStack.size() - 1);
|
||||
lastFragment.willBeHidden();
|
||||
}
|
||||
ApplicationLoader.fragmentsStack.add(fragment);
|
||||
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment, "chat_enc_" + push_enc_id).commitAllowingStateLoss();
|
||||
}
|
||||
}
|
||||
} else if (id == 701) {
|
||||
if (notificationView != null) {
|
||||
MessageObject message = (MessageObject)args[0];
|
||||
notificationView.show(message);
|
||||
}
|
||||
} else if (id == 702) {
|
||||
if (args[0] != this) {
|
||||
processOnFinish();
|
||||
}
|
||||
} else if (id == 703) {
|
||||
int state = (Integer)args[0];
|
||||
if (currentConnectionState != state) {
|
||||
currentConnectionState = state;
|
||||
updateActionBar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateActionBar() {
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if (actionBar == null) {
|
||||
return;
|
||||
}
|
||||
BaseFragment currentFragment = null;
|
||||
if (!ApplicationLoader.fragmentsStack.isEmpty()) {
|
||||
currentFragment = ApplicationLoader.fragmentsStack.get(ApplicationLoader.fragmentsStack.size() - 1);
|
||||
}
|
||||
boolean canApplyLoading = true;
|
||||
if (currentFragment != null && (currentConnectionState == 0 || !currentFragment.canApplyUpdateStatus() || statusView == null)) {
|
||||
currentFragment.applySelfActionBar();
|
||||
canApplyLoading = false;
|
||||
}
|
||||
if (canApplyLoading) {
|
||||
if (statusView != null) {
|
||||
actionBar.setDisplayShowTitleEnabled(false);
|
||||
actionBar.setDisplayShowHomeEnabled(false);
|
||||
actionBar.setDisplayHomeAsUpEnabled(false);
|
||||
actionBar.setDisplayUseLogoEnabled(false);
|
||||
actionBar.setDisplayShowCustomEnabled(true);
|
||||
actionBar.setSubtitle(null);
|
||||
|
||||
if (ApplicationLoader.fragmentsStack.size() > 1) {
|
||||
backStatusButton.setVisibility(View.VISIBLE);
|
||||
statusBackground.setEnabled(true);
|
||||
} else {
|
||||
backStatusButton.setVisibility(View.GONE);
|
||||
statusBackground.setEnabled(false);
|
||||
}
|
||||
|
||||
if (currentConnectionState == 1) {
|
||||
statusText.setText(Html.fromHtml("<font color='#006fc8'>" + getString(R.string.WaitingForNetwork) + "</font>"));
|
||||
} else if (currentConnectionState == 2) {
|
||||
statusText.setText(Html.fromHtml("<font color='#006fc8'>" + getString(R.string.Connecting) + "</font>"));
|
||||
} else if (currentConnectionState == 3) {
|
||||
statusText.setText(Html.fromHtml("<font color='#006fc8'>" + getString(R.string.Updating) + "</font>"));
|
||||
}
|
||||
if (actionBar.getCustomView() != statusView) {
|
||||
actionBar.setCustomView(statusView);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void presentFragment(BaseFragment fragment, String tag, boolean bySwipe) {
|
||||
presentFragment(fragment, tag, false, bySwipe);
|
||||
}
|
||||
|
||||
public void presentFragment(BaseFragment fragment, String tag, boolean removeLast, boolean bySwipe) {
|
||||
if (getCurrentFocus() != null) {
|
||||
Utilities.hideKeyboard(getCurrentFocus());
|
||||
}
|
||||
if (!fragment.onFragmentCreate()) {
|
||||
return;
|
||||
}
|
||||
BaseFragment current = null;
|
||||
if (!ApplicationLoader.fragmentsStack.isEmpty()) {
|
||||
current = ApplicationLoader.fragmentsStack.get(ApplicationLoader.fragmentsStack.size() - 1);
|
||||
}
|
||||
if (current != null) {
|
||||
current.willBeHidden();
|
||||
}
|
||||
FragmentManager fm = getSupportFragmentManager();
|
||||
FragmentTransaction fTrans = fm.beginTransaction();
|
||||
if (removeLast && current != null) {
|
||||
ApplicationLoader.fragmentsStack.remove(ApplicationLoader.fragmentsStack.size() - 1);
|
||||
current.onFragmentDestroy();
|
||||
}
|
||||
SharedPreferences preferences = Utilities.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE);
|
||||
boolean animations = preferences.getBoolean("view_animations", true);
|
||||
if (animations) {
|
||||
if (bySwipe) {
|
||||
fTrans.setCustomAnimations(R.anim.slide_left, R.anim.no_anim);
|
||||
} else {
|
||||
fTrans.setCustomAnimations(R.anim.scale_in, R.anim.no_anim);
|
||||
}
|
||||
}
|
||||
fTrans.replace(R.id.container, fragment, tag);
|
||||
fTrans.commitAllowingStateLoss();
|
||||
ApplicationLoader.fragmentsStack.add(fragment);
|
||||
}
|
||||
|
||||
public void removeFromStack(BaseFragment fragment) {
|
||||
ApplicationLoader.fragmentsStack.remove(fragment);
|
||||
fragment.onFragmentDestroy();
|
||||
}
|
||||
|
||||
public void finishFragment(boolean bySwipe) {
|
||||
if (getCurrentFocus() != null) {
|
||||
Utilities.hideKeyboard(getCurrentFocus());
|
||||
}
|
||||
if (ApplicationLoader.fragmentsStack.size() < 2) {
|
||||
for (BaseFragment fragment : ApplicationLoader.fragmentsStack) {
|
||||
fragment.onFragmentDestroy();
|
||||
}
|
||||
ApplicationLoader.fragmentsStack.clear();
|
||||
MessagesActivity fragment = new MessagesActivity();
|
||||
fragment.onFragmentCreate();
|
||||
ApplicationLoader.fragmentsStack.add(fragment);
|
||||
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment, "chats").commitAllowingStateLoss();
|
||||
return;
|
||||
}
|
||||
BaseFragment fragment = ApplicationLoader.fragmentsStack.get(ApplicationLoader.fragmentsStack.size() - 1);
|
||||
fragment.onFragmentDestroy();
|
||||
BaseFragment prev = ApplicationLoader.fragmentsStack.get(ApplicationLoader.fragmentsStack.size() - 2);
|
||||
FragmentManager fm = getSupportFragmentManager();
|
||||
FragmentTransaction fTrans = fm.beginTransaction();
|
||||
SharedPreferences preferences = Utilities.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE);
|
||||
boolean animations = preferences.getBoolean("view_animations", true);
|
||||
if (animations) {
|
||||
if (bySwipe) {
|
||||
fTrans.setCustomAnimations(R.anim.no_anim_show, R.anim.slide_right_away);
|
||||
} else {
|
||||
fTrans.setCustomAnimations(R.anim.no_anim_show, R.anim.scale_out);
|
||||
}
|
||||
}
|
||||
fTrans.replace(R.id.container, prev, prev.getTag());
|
||||
fTrans.commitAllowingStateLoss();
|
||||
ApplicationLoader.fragmentsStack.remove(ApplicationLoader.fragmentsStack.size() - 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (ApplicationLoader.fragmentsStack.size() == 1) {
|
||||
ApplicationLoader.fragmentsStack.get(0).onFragmentDestroy();
|
||||
ApplicationLoader.fragmentsStack.clear();
|
||||
processOnFinish();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
if (!ApplicationLoader.fragmentsStack.isEmpty()) {
|
||||
BaseFragment lastFragment = ApplicationLoader.fragmentsStack.get(ApplicationLoader.fragmentsStack.size() - 1);
|
||||
if (lastFragment.onBackPressed()) {
|
||||
finishFragment(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,209 @@
|
||||
/*
|
||||
* This is the source code of Telegram for Android v. 1.2.3.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013.
|
||||
*/
|
||||
|
||||
package org.telegram.ui;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.GooglePlayServicesUtil;
|
||||
import com.google.android.gms.gcm.GoogleCloudMessaging;
|
||||
|
||||
import org.telegram.PhoneFormat.PhoneFormat;
|
||||
import org.telegram.TL.TLRPC;
|
||||
import org.telegram.messenger.ConnectionsManager;
|
||||
import org.telegram.messenger.MessagesController;
|
||||
import org.telegram.messenger.MessagesStorage;
|
||||
import org.telegram.messenger.UserConfig;
|
||||
import org.telegram.messenger.Utilities;
|
||||
import org.telegram.ui.Views.BaseFragment;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class ApplicationLoader extends Application {
|
||||
private GoogleCloudMessaging gcm;
|
||||
private AtomicInteger msgId = new AtomicInteger();
|
||||
private String regid;
|
||||
private String SENDER_ID = "760348033672";
|
||||
public static final String EXTRA_MESSAGE = "message";
|
||||
public static final String PROPERTY_REG_ID = "registration_id";
|
||||
private static final String PROPERTY_APP_VERSION = "appVersion";
|
||||
private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
|
||||
public static long lastPauseTime;
|
||||
public static Bitmap cachedWallpaper = null;
|
||||
|
||||
public static ApplicationLoader Instance = null;
|
||||
|
||||
public static ArrayList<BaseFragment> fragmentsStack = new ArrayList<BaseFragment>();
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
Instance = this;
|
||||
|
||||
java.lang.System.setProperty("java.net.preferIPv4Stack", "true");
|
||||
java.lang.System.setProperty("java.net.preferIPv6Addresses", "false");
|
||||
|
||||
Utilities.applicationContext = getApplicationContext();
|
||||
UserConfig.loadConfig();
|
||||
SharedPreferences preferences = getSharedPreferences("Notifications", MODE_PRIVATE);
|
||||
if (UserConfig.currentUser != null) {
|
||||
int value = preferences.getInt("version", 0);
|
||||
if (value != 15) {
|
||||
UserConfig.contactsHash = "";
|
||||
UserConfig.lastDateValue = 0;
|
||||
UserConfig.lastPtsValue = 0;
|
||||
UserConfig.lastSeqValue = 0;
|
||||
UserConfig.lastQtsValue = 0;
|
||||
UserConfig.saveConfig();
|
||||
MessagesStorage.Instance.cleanUp();
|
||||
ArrayList<TLRPC.User> users = new ArrayList<TLRPC.User>();
|
||||
users.add(UserConfig.currentUser);
|
||||
MessagesStorage.Instance.putUsersAndChats(users, null, true, true);
|
||||
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putInt("version", 15);
|
||||
editor.commit();
|
||||
}
|
||||
MessagesController.Instance.users.put(UserConfig.clientUserId, UserConfig.currentUser);
|
||||
} else {
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putInt("version", 15);
|
||||
editor.commit();
|
||||
}
|
||||
MessagesController.Instance.checkAppAccount();
|
||||
|
||||
try {
|
||||
ViewConfiguration config = ViewConfiguration.get(this);
|
||||
Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
|
||||
if(menuKeyField != null) {
|
||||
menuKeyField.setAccessible(true);
|
||||
menuKeyField.setBoolean(config, false);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (checkPlayServices()) {
|
||||
gcm = GoogleCloudMessaging.getInstance(this);
|
||||
regid = getRegistrationId(Utilities.applicationContext);
|
||||
|
||||
if (regid.length() == 0) {
|
||||
registerInBackground();
|
||||
} else {
|
||||
sendRegistrationIdToBackend(false);
|
||||
}
|
||||
} else {
|
||||
Log.i("tmessages", "No valid Google Play Services APK found.");
|
||||
}
|
||||
|
||||
PhoneFormat format = PhoneFormat.Instance;
|
||||
|
||||
lastPauseTime = System.currentTimeMillis() - 5000;
|
||||
if (ConnectionsManager.DEBUG_VERSION) {
|
||||
Log.e("tmessages", "start application with time " + lastPauseTime);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkPlayServices() {
|
||||
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
|
||||
return resultCode == ConnectionResult.SUCCESS;
|
||||
/*if (resultCode != ConnectionResult.SUCCESS) {
|
||||
if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
|
||||
GooglePlayServicesUtil.getErrorDialog(resultCode, this, PLAY_SERVICES_RESOLUTION_REQUEST).show();
|
||||
} else {
|
||||
Log.i("tmessages", "This device is not supported.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;*/
|
||||
}
|
||||
|
||||
private String getRegistrationId(Context context) {
|
||||
final SharedPreferences prefs = getGCMPreferences(context);
|
||||
String registrationId = prefs.getString(PROPERTY_REG_ID, "");
|
||||
if (registrationId.length() == 0) {
|
||||
Log.i("tmessages", "Registration not found.");
|
||||
return "";
|
||||
}
|
||||
int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
|
||||
int currentVersion = getAppVersion(context);
|
||||
if (registeredVersion != currentVersion) {
|
||||
Log.i("tmessages", "App version changed.");
|
||||
return "";
|
||||
}
|
||||
return registrationId;
|
||||
}
|
||||
|
||||
private SharedPreferences getGCMPreferences(Context context) {
|
||||
return getSharedPreferences(ApplicationLoader.class.getSimpleName(), Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
private static int getAppVersion(Context context) {
|
||||
try {
|
||||
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
|
||||
return packageInfo.versionCode;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
throw new RuntimeException("Could not get package name: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerInBackground() {
|
||||
AsyncTask<String, String, Boolean> task = new AsyncTask<String, String, Boolean>() {
|
||||
@Override
|
||||
protected Boolean doInBackground(String... objects) {
|
||||
String msg;
|
||||
try {
|
||||
if (gcm == null) {
|
||||
gcm = GoogleCloudMessaging.getInstance(Utilities.applicationContext);
|
||||
}
|
||||
regid = gcm.register(SENDER_ID);
|
||||
sendRegistrationIdToBackend(true);
|
||||
storeRegistrationId(Utilities.applicationContext, regid);
|
||||
return true;
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}.execute(null, null, null);
|
||||
}
|
||||
|
||||
private void sendRegistrationIdToBackend(final boolean isNew) {
|
||||
Utilities.stageQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
UserConfig.pushString = regid;
|
||||
UserConfig.registeredForPush = !isNew;
|
||||
UserConfig.saveConfig();
|
||||
MessagesController.Instance.registerForPush(regid);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void storeRegistrationId(Context context, String regId) {
|
||||
final SharedPreferences prefs = getGCMPreferences(context);
|
||||
int appVersion = getAppVersion(context);
|
||||
Log.i("tmessages", "Saving regId on app version " + appVersion);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putString(PROPERTY_REG_ID, regId);
|
||||
editor.putInt(PROPERTY_APP_VERSION, appVersion);
|
||||
editor.commit();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user