Rewritten to use libtgl

This commit is contained in:
Vysheng 2014-11-11 20:29:09 +03:00
parent 1b6fdf44e8
commit f46c685bbd
44 changed files with 1506 additions and 14814 deletions

21
.gitignore vendored
View file

@ -1,21 +0,0 @@
telegram
*.o
*.so
*.a
telegram-adium/libcrypto.a
config.h
config.log
config.status
.idea/
nbproject/
tags
.DS_Store
.ycm_extra_conf.py
*.pyc
app-hash.png
.gdbinit
core
core*
telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcuserdata/matj.xcuserdatad/UserInterfaceState.xcuserstate
telegram-adium/telegram-adium.xcodeproj/xcuserdata/matj.xcuserdatad
telegram-adium/telegram-adium.xcodeproj/project.xcworkspace/xcuserdata/*

View file

@ -1,12 +0,0 @@
language: c
compiler:
- gcc
- clang
install:
- sudo apt-get install libssl-dev libglib2.0-dev libpurple-dev
script:
- ./configure
- make

339
LICENSE
View file

@ -1,339 +0,0 @@
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.

339
LICENSE.h
View file

@ -1,339 +0,0 @@
" GNU GENERAL PUBLIC LICENSE\n"
" Version 2, June 1991\n"
"\n"
" Copyright (C) 1989, 1991 Free Software Foundation, Inc.,\n"
" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
" Everyone is permitted to copy and distribute verbatim copies\n"
" of this license document, but changing it is not allowed.\n"
"\n"
" Preamble\n"
"\n"
" The licenses for most software are designed to take away your\n"
"freedom to share and change it. By contrast, the GNU General Public\n"
"License is intended to guarantee your freedom to share and change free\n"
"software--to make sure the software is free for all its users. This\n"
"General Public License applies to most of the Free Software\n"
"Foundation's software and to any other program whose authors commit to\n"
"using it. (Some other Free Software Foundation software is covered by\n"
"the GNU Lesser General Public License instead.) You can apply it to\n"
"your programs, too.\n"
"\n"
" When we speak of free software, we are referring to freedom, not\n"
"price. Our General Public Licenses are designed to make sure that you\n"
"have the freedom to distribute copies of free software (and charge for\n"
"this service if you wish), that you receive source code or can get it\n"
"if you want it, that you can change the software or use pieces of it\n"
"in new free programs; and that you know you can do these things.\n"
"\n"
" To protect your rights, we need to make restrictions that forbid\n"
"anyone to deny you these rights or to ask you to surrender the rights.\n"
"These restrictions translate to certain responsibilities for you if you\n"
"distribute copies of the software, or if you modify it.\n"
"\n"
" For example, if you distribute copies of such a program, whether\n"
"gratis or for a fee, you must give the recipients all the rights that\n"
"you have. You must make sure that they, too, receive or can get the\n"
"source code. And you must show them these terms so they know their\n"
"rights.\n"
"\n"
" We protect your rights with two steps: (1) copyright the software, and\n"
"(2) offer you this license which gives you legal permission to copy,\n"
"distribute and/or modify the software.\n"
"\n"
" Also, for each author's protection and ours, we want to make certain\n"
"that everyone understands that there is no warranty for this free\n"
"software. If the software is modified by someone else and passed on, we\n"
"want its recipients to know that what they have is not the original, so\n"
"that any problems introduced by others will not reflect on the original\n"
"authors' reputations.\n"
"\n"
" Finally, any free program is threatened constantly by software\n"
"patents. We wish to avoid the danger that redistributors of a free\n"
"program will individually obtain patent licenses, in effect making the\n"
"program proprietary. To prevent this, we have made it clear that any\n"
"patent must be licensed for everyone's free use or not licensed at all.\n"
"\n"
" The precise terms and conditions for copying, distribution and\n"
"modification follow.\n"
"\n"
" GNU GENERAL PUBLIC LICENSE\n"
" TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n"
"\n"
" 0. This License applies to any program or other work which contains\n"
"a notice placed by the copyright holder saying it may be distributed\n"
"under the terms of this General Public License. The \"Program\", below,\n"
"refers to any such program or work, and a \"work based on the Program\"\n"
"means either the Program or any derivative work under copyright law:\n"
"that is to say, a work containing the Program or a portion of it,\n"
"either verbatim or with modifications and/or translated into another\n"
"language. (Hereinafter, translation is included without limitation in\n"
"the term \"modification\".) Each licensee is addressed as \"you\".\n"
"\n"
"Activities other than copying, distribution and modification are not\n"
"covered by this License; they are outside its scope. The act of\n"
"running the Program is not restricted, and the output from the Program\n"
"is covered only if its contents constitute a work based on the\n"
"Program (independent of having been made by running the Program).\n"
"Whether that is true depends on what the Program does.\n"
"\n"
" 1. You may copy and distribute verbatim copies of the Program's\n"
"source code as you receive it, in any medium, provided that you\n"
"conspicuously and appropriately publish on each copy an appropriate\n"
"copyright notice and disclaimer of warranty; keep intact all the\n"
"notices that refer to this License and to the absence of any warranty;\n"
"and give any other recipients of the Program a copy of this License\n"
"along with the Program.\n"
"\n"
"You may charge a fee for the physical act of transferring a copy, and\n"
"you may at your option offer warranty protection in exchange for a fee.\n"
"\n"
" 2. You may modify your copy or copies of the Program or any portion\n"
"of it, thus forming a work based on the Program, and copy and\n"
"distribute such modifications or work under the terms of Section 1\n"
"above, provided that you also meet all of these conditions:\n"
"\n"
" a) You must cause the modified files to carry prominent notices\n"
" stating that you changed the files and the date of any change.\n"
"\n"
" b) You must cause any work that you distribute or publish, that in\n"
" whole or in part contains or is derived from the Program or any\n"
" part thereof, to be licensed as a whole at no charge to all third\n"
" parties under the terms of this License.\n"
"\n"
" c) If the modified program normally reads commands interactively\n"
" when run, you must cause it, when started running for such\n"
" interactive use in the most ordinary way, to print or display an\n"
" announcement including an appropriate copyright notice and a\n"
" notice that there is no warranty (or else, saying that you provide\n"
" a warranty) and that users may redistribute the program under\n"
" these conditions, and telling the user how to view a copy of this\n"
" License. (Exception: if the Program itself is interactive but\n"
" does not normally print such an announcement, your work based on\n"
" the Program is not required to print an announcement.)\n"
"\n"
"These requirements apply to the modified work as a whole. If\n"
"identifiable sections of that work are not derived from the Program,\n"
"and can be reasonably considered independent and separate works in\n"
"themselves, then this License, and its terms, do not apply to those\n"
"sections when you distribute them as separate works. But when you\n"
"distribute the same sections as part of a whole which is a work based\n"
"on the Program, the distribution of the whole must be on the terms of\n"
"this License, whose permissions for other licensees extend to the\n"
"entire whole, and thus to each and every part regardless of who wrote it.\n"
"\n"
"Thus, it is not the intent of this section to claim rights or contest\n"
"your rights to work written entirely by you; rather, the intent is to\n"
"exercise the right to control the distribution of derivative or\n"
"collective works based on the Program.\n"
"\n"
"In addition, mere aggregation of another work not based on the Program\n"
"with the Program (or with a work based on the Program) on a volume of\n"
"a storage or distribution medium does not bring the other work under\n"
"the scope of this License.\n"
"\n"
" 3. You may copy and distribute the Program (or a work based on it,\n"
"under Section 2) in object code or executable form under the terms of\n"
"Sections 1 and 2 above provided that you also do one of the following:\n"
"\n"
" a) Accompany it with the complete corresponding machine-readable\n"
" source code, which must be distributed under the terms of Sections\n"
" 1 and 2 above on a medium customarily used for software interchange; or,\n"
"\n"
" b) Accompany it with a written offer, valid for at least three\n"
" years, to give any third party, for a charge no more than your\n"
" cost of physically performing source distribution, a complete\n"
" machine-readable copy of the corresponding source code, to be\n"
" distributed under the terms of Sections 1 and 2 above on a medium\n"
" customarily used for software interchange; or,\n"
"\n"
" c) Accompany it with the information you received as to the offer\n"
" to distribute corresponding source code. (This alternative is\n"
" allowed only for noncommercial distribution and only if you\n"
" received the program in object code or executable form with such\n"
" an offer, in accord with Subsection b above.)\n"
"\n"
"The source code for a work means the preferred form of the work for\n"
"making modifications to it. For an executable work, complete source\n"
"code means all the source code for all modules it contains, plus any\n"
"associated interface definition files, plus the scripts used to\n"
"control compilation and installation of the executable. However, as a\n"
"special exception, the source code distributed need not include\n"
"anything that is normally distributed (in either source or binary\n"
"form) with the major components (compiler, kernel, and so on) of the\n"
"operating system on which the executable runs, unless that component\n"
"itself accompanies the executable.\n"
"\n"
"If distribution of executable or object code is made by offering\n"
"access to copy from a designated place, then offering equivalent\n"
"access to copy the source code from the same place counts as\n"
"distribution of the source code, even though third parties are not\n"
"compelled to copy the source along with the object code.\n"
"\n"
" 4. You may not copy, modify, sublicense, or distribute the Program\n"
"except as expressly provided under this License. Any attempt\n"
"otherwise to copy, modify, sublicense or distribute the Program is\n"
"void, and will automatically terminate your rights under this License.\n"
"However, parties who have received copies, or rights, from you under\n"
"this License will not have their licenses terminated so long as such\n"
"parties remain in full compliance.\n"
"\n"
" 5. You are not required to accept this License, since you have not\n"
"signed it. However, nothing else grants you permission to modify or\n"
"distribute the Program or its derivative works. These actions are\n"
"prohibited by law if you do not accept this License. Therefore, by\n"
"modifying or distributing the Program (or any work based on the\n"
"Program), you indicate your acceptance of this License to do so, and\n"
"all its terms and conditions for copying, distributing or modifying\n"
"the Program or works based on it.\n"
"\n"
" 6. Each time you redistribute the Program (or any work based on the\n"
"Program), the recipient automatically receives a license from the\n"
"original licensor to copy, distribute or modify the Program subject to\n"
"these terms and conditions. You may not impose any further\n"
"restrictions on the recipients' exercise of the rights granted herein.\n"
"You are not responsible for enforcing compliance by third parties to\n"
"this License.\n"
"\n"
" 7. If, as a consequence of a court judgment or allegation of patent\n"
"infringement or for any other reason (not limited to patent issues),\n"
"conditions are imposed on you (whether by court order, agreement or\n"
"otherwise) that contradict the conditions of this License, they do not\n"
"excuse you from the conditions of this License. If you cannot\n"
"distribute so as to satisfy simultaneously your obligations under this\n"
"License and any other pertinent obligations, then as a consequence you\n"
"may not distribute the Program at all. For example, if a patent\n"
"license would not permit royalty-free redistribution of the Program by\n"
"all those who receive copies directly or indirectly through you, then\n"
"the only way you could satisfy both it and this License would be to\n"
"refrain entirely from distribution of the Program.\n"
"\n"
"If any portion of this section is held invalid or unenforceable under\n"
"any particular circumstance, the balance of the section is intended to\n"
"apply and the section as a whole is intended to apply in other\n"
"circumstances.\n"
"\n"
"It is not the purpose of this section to induce you to infringe any\n"
"patents or other property right claims or to contest validity of any\n"
"such claims; this section has the sole purpose of protecting the\n"
"integrity of the free software distribution system, which is\n"
"implemented by public license practices. Many people have made\n"
"generous contributions to the wide range of software distributed\n"
"through that system in reliance on consistent application of that\n"
"system; it is up to the author/donor to decide if he or she is willing\n"
"to distribute software through any other system and a licensee cannot\n"
"impose that choice.\n"
"\n"
"This section is intended to make thoroughly clear what is believed to\n"
"be a consequence of the rest of this License.\n"
"\n"
" 8. If the distribution and/or use of the Program is restricted in\n"
"certain countries either by patents or by copyrighted interfaces, the\n"
"original copyright holder who places the Program under this License\n"
"may add an explicit geographical distribution limitation excluding\n"
"those countries, so that distribution is permitted only in or among\n"
"countries not thus excluded. In such case, this License incorporates\n"
"the limitation as if written in the body of this License.\n"
"\n"
" 9. The Free Software Foundation may publish revised and/or new versions\n"
"of the General Public License from time to time. Such new versions will\n"
"be similar in spirit to the present version, but may differ in detail to\n"
"address new problems or concerns.\n"
"\n"
"Each version is given a distinguishing version number. If the Program\n"
"specifies a version number of this License which applies to it and \"any\n"
"later version\", you have the option of following the terms and conditions\n"
"either of that version or of any later version published by the Free\n"
"Software Foundation. If the Program does not specify a version number of\n"
"this License, you may choose any version ever published by the Free Software\n"
"Foundation.\n"
"\n"
" 10. If you wish to incorporate parts of the Program into other free\n"
"programs whose distribution conditions are different, write to the author\n"
"to ask for permission. For software which is copyrighted by the Free\n"
"Software Foundation, write to the Free Software Foundation; we sometimes\n"
"make exceptions for this. Our decision will be guided by the two goals\n"
"of preserving the free status of all derivatives of our free software and\n"
"of promoting the sharing and reuse of software generally.\n"
"\n"
" NO WARRANTY\n"
"\n"
" 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
"FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"
"OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
"PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
"OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
"MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"
"TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"
"PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
"REPAIR OR CORRECTION.\n"
"\n"
" 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
"WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
"REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
"INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
"OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
"TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
"YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
"PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
"POSSIBILITY OF SUCH DAMAGES.\n"
"\n"
" END OF TERMS AND CONDITIONS\n"
"\n"
" How to Apply These Terms to Your New Programs\n"
"\n"
" If you develop a new program, and you want it to be of the greatest\n"
"possible use to the public, the best way to achieve this is to make it\n"
"free software which everyone can redistribute and change under these terms.\n"
"\n"
" To do so, attach the following notices to the program. It is safest\n"
"to attach them to the start of each source file to most effectively\n"
"convey the exclusion of warranty; and each file should have at least\n"
"the \"copyright\" line and a pointer to where the full notice is found.\n"
"\n"
" <one line to give the program's name and a brief idea of what it does.>\n"
" Copyright (C) <year> <name of author>\n"
"\n"
" This program is free software; you can redistribute it and/or modify\n"
" it under the terms of the GNU General Public License as published by\n"
" the Free Software Foundation; either version 2 of the License, or\n"
" (at your option) any later version.\n"
"\n"
" This program is distributed in the hope that it will be useful,\n"
" but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
" GNU General Public License for more details.\n"
"\n"
" You should have received a copy of the GNU General Public License along\n"
" with this program; if not, write to the Free Software Foundation, Inc.,\n"
" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n"
"\n"
"Also add information on how to contact you by electronic and paper mail.\n"
"\n"
"If the program is interactive, make it output a short notice like this\n"
"when it starts in an interactive mode:\n"
"\n"
" Gnomovision version 69, Copyright (C) year name of author\n"
" Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n"
" This is free software, and you are welcome to redistribute it\n"
" under certain conditions; type `show c' for details.\n"
"\n"
"The hypothetical commands `show w' and `show c' should show the appropriate\n"
"parts of the General Public License. Of course, the commands you use may\n"
"be called something other than `show w' and `show c'; they could even be\n"
"mouse-clicks or menu items--whatever suits your program.\n"
"\n"
"You should also get your employer (if you work as a programmer) or your\n"
"school, if any, to sign a \"copyright disclaimer\" for the program, if\n"
"necessary. Here is a sample; alter the names:\n"
"\n"
" Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n"
" `Gnomovision' (which makes passes at compilers) written by James Hacker.\n"
"\n"
" <signature of Ty Coon>, 1 April 1989\n"
" Ty Coon, President of Vice\n"
"\n"
"This General Public License does not permit incorporating your program into\n"
"proprietary programs. If your program is a subroutine library, you may\n"
"consider it more useful to permit linking proprietary applications with the\n"
"library. If this is what you want to do, use the GNU Lesser General\n"
"Public License instead of this License.\n"

View file

@ -3,16 +3,19 @@
#
srcdir=.
CFLAGS=-g -I/usr/local/include
LDFLAGS=-L/usr/local/lib
COMPILE_FLAGS=${CFLAGS} -Wall -Wextra -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb
CFLAGS=-g -Wall -Wextra -Werror -Wno-unused-parameter
LDFLAGS=-L/usr/local/lib
CPPFLAGS=-I/usr/local/include -Itg
DEFS=
COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb
EXTRA_LIBS=-lcrypto -lz -lm
HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/net.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/no-preview.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/binlog.h ${srcdir}/tools.h ${srcdir}/msglog.h
LOCAL_LDFLAGS=-rdynamic -ggdb ${EXTRA_LIBS}
LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS}
INCLUDE=-I. -I${srcdir}
CC=cc
OBJECTS=loop.o net.o mtproto-common.o mtproto-client.o queries.o structures.o binlog.o tools.o msglog.o telegram.o
OBJECTS=tgp-net.o tgp-timers.o msglog.o telegram-base.o
.SUFFIXES:
.SUFFIXES: .c .h .o
@ -37,7 +40,7 @@ else
endif
LD = $(CC)
PRPL_C_SRCS = purple-plugin/telegram-purple.c
PRPL_C_SRCS = telegram-purple.c
PRPL_C_OBJS = $(PRPL_C_SRCS:.c=.o)
PRPL_LIBNAME = telegram-purple.so
PRPL_INCLUDE = -I. -I./purple-plugin
@ -46,8 +49,8 @@ STRIP = strip
PRPL_CFLAGS = \
$(ARCHFLAGS) \
-fPIC \
-DPIC \
-DPURPLE_PLUGINS \
-DPIC \
-DDEBUG \
-g \
$(CFLAGS_PURPLE)
@ -59,30 +62,38 @@ PRPL_CFLAGS = \
.c.o :
${CC} -fPIC -DPIC ${CFLAGS_PURPLE} ${COMPILE_FLAGS} ${INCLUDE} -c $< -o $@
${OBJECTS}: ${HEADERS}
# ${OBJECTS}: ${HEADERS}
#telegram: ${OBJECTS}
# ${CC} ${OBJECTS} ${LINK_FLAGS} -o $@
#
# Plugin Objects
#
$(PRPL_C_OBJS): $(PRPL_C_SRCS)
$(CC) -c $(PRPL_INCLUDE) $(PRPL_CFLAGS) $(CFLAGS) $(CPPFLAGS) -o $@ $<
$(CC) -c $(PRPL_INCLUDE) $(PRPL_CFLAGS) $(CFLAGS) $(CPPFLAGS) -ggdb -o $@ $<
$(PRPL_LIBNAME): $(OBJECTS) $(PRPL_C_OBJS)
$(LD) $(PRPL_LDFLAGS) $(LDFLAGS) $(PRPL_INCLUDE) -o $@ $(PRPL_C_OBJS) $(OBJECTS) $(LIBS_PURPLE) $(EXTRA_LIBS)
$(PRPL_LIBNAME): $(OBJECTS) $(PRPL_C_OBJS) tg/libs/libtgl.a
$(LD) $(PRPL_LDFLAGS) $(LDFLAGS) $(PRPL_INCLUDE) $(LIBS_PURPLE) $(EXTRA_LIBS) -o $@ $^
.PHONY: all
all: ${PRPL_LIBNAME}
plugin: $(PRPL_LIBNAME)
all: $(PRPL_LIBNAME)
.PHONY: strip
strip: $(PRPL_LIBNAME)
$(STRIP) --strip-unneeded $(PRPL_LIBNAME)
# TODO: Find a better place for server.pub
install: $(PRPL_LIBNAME)
install -D $(PRPL_LIBNAME) $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(PRPL_LIBNAME)
install -D tg-server.pub /etc/telegram-purple/server.pub
install -D purple-plugin/telegram16.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png
install -D purple-plugin/telegram22.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22/telegram.png
install -D purple-plugin/telegram48.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png
install -D imgs/telegram16.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png
install -D imgs/telegram22.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22/telegram.png
install -D imgs/telegram48.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png
.PHONY: uninstall
uninstall:

View file

@ -11,6 +11,10 @@ Warning, this version is mainly for development and testing and NOT for producti
When encountering a crash or some other bugs, please report it to us, preferably together with a backtrace of the crashed application [https://developer.pidgin.im/wiki/GetABacktrace]
## Version 0.4
- Use latest version of libtgl
## Version 0.3.3
- multiple bugfixes
@ -70,8 +74,14 @@ Unfortunately there are no packages right now, so you need to compile it yoursel
git clone https://github.com/majn/telegram-purple
## 2. Get libtgl to tg subfolder
cd telegram-purple
git clone https://github.com/vysheng/tg
## 2. Fetch all needed dependencies
## 3. Fetch all needed dependencies
This plugin depends on a working libpurple client (like Pidgin or Finch) and the following packages:
@ -143,8 +153,7 @@ This bundle was tested to work under OSX 10.9 and 10.8. If it doesn't work on yo
please send your Adium crash log (which you can find in ~/Library/Logs/Adium 2/).
[Version 0.3.2](http://lauschgift.org/telegram-purple/telegram-adium-0.3.2.zip)
[Version 0.3.3](http://lauschgift.org/telegram-purple/telegram-adium-0.3.3.zip)
[Version 0.3.2](http://lauschgift.org/telegram-purple/telegram-adium-0.3.3.zip)
## Build with XCode

1686
binlog.c

File diff suppressed because it is too large Load diff

150
binlog.h
View file

@ -1,150 +0,0 @@
/*
This file is part of telegram-client.
Telegram-client 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.
Telegram-client 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 telegram-client. If not, see <http://www.gnu.org/licenses/>.
Copyright Vitaly Valtman 2013
*/
#ifndef __BINLOG_H__
#define __BINLOG_H__
#include "structures.h"
#include "telegram.h"
#define LOG_START 0x8948329a
#define LOG_AUTH_KEY 0x984932aa
#define LOG_DEFAULT_DC 0x95382908
#define LOG_OUR_ID 0x8943211a
#define LOG_DC_SIGNED 0x234f9893
#define LOG_DC_SALT 0x92192ffa
#define LOG_DH_CONFIG 0x8983402b
#define LOG_ENCR_CHAT_KEY 0x894320aa
#define LOG_ENCR_CHAT_SEND_ACCEPT 0x12ab01c4
#define LOG_ENCR_CHAT_SEND_CREATE 0xab091e24
#define LOG_ENCR_CHAT_DELETED 0x99481230
#define LOG_ENCR_CHAT_WAITING 0x7102100a
#define LOG_ENCR_CHAT_REQUESTED 0x9011011a
#define LOG_ENCR_CHAT_OK 0x7612ce13
#define CODE_binlog_new_user 0xe04f30de
#define CODE_binlog_user_delete 0xf7a27c79
#define CODE_binlog_set_user_access_token 0x1349f615
#define CODE_binlog_set_user_phone 0x5d3afde2
#define CODE_binlog_set_user_friend 0x75a7ec5a
#define CODE_binlog_dc_option 0x08c0ef19
#define CODE_binlog_user_full_photo 0xfaa35824
#define CODE_binlog_user_blocked 0xb2dea7cd
#define CODE_binlog_set_user_full_name 0x4ceb4cf0
#define CODE_binlog_encr_chat_delete 0xb9d33f87
#define CODE_binlog_encr_chat_requested 0xf57d1ea2
#define CODE_binlog_set_encr_chat_access_hash 0xe5612bb3
#define CODE_binlog_set_encr_chat_date 0x54f16911
#define CODE_binlog_set_encr_chat_state 0x76a6e45b
#define CODE_binlog_encr_chat_accepted 0x4627e926
#define CODE_binlog_set_encr_chat_key 0x179df2d4
#define CODE_binlog_set_dh_params 0x20ba46bc
#define CODE_binlog_encr_chat_init 0x939cd1c7
#define CODE_binlog_set_pts 0x844e4c1c
#define CODE_binlog_set_qts 0x3cf22b79
#define CODE_binlog_set_date 0x33dfe392
#define CODE_binlog_set_seq 0xb9294837
#define CODE_binlog_chat_create 0xbaa75791
#define CODE_binlog_chat_change_flags 0x1e494031
#define CODE_binlog_set_chat_title 0x7dd9bea8
#define CODE_binlog_set_chat_photo 0xb4ea1fd2
#define CODE_binlog_set_chat_date 0x78d1114e
#define CODE_binlog_set_chat_version 0xa5d3504f
#define CODE_binlog_set_chat_admin 0x1e7cea04
#define CODE_binlog_set_chat_participants 0x3a29d335
#define CODE_binlog_chat_full_photo 0x6cca6629
#define CODE_binlog_add_chat_participant 0x63345108
#define CODE_binlog_del_chat_participant 0x82d1f0ee
#define CODE_binlog_create_message_text 0x269acd5b
#define CODE_binlog_create_message_text_fwd 0xa3d864cd
#define CODE_binlog_create_message_service 0xbbe5e94b
#define CODE_binlog_create_message_service_fwd 0xea9c57ae
#define CODE_binlog_create_message_media 0x62a92d19
#define CODE_binlog_create_message_media_fwd 0xbefdc462
#define CODE_binlog_send_message_text 0x31cfd652
#define CODE_binlog_set_unread 0x21d4c909
#define CODE_binlog_set_message_sent 0xc335282b
#define CODE_binlog_set_msg_id 0xf3285b6a
#define CODE_binlog_create_message_media_encr 0x19cd7c9d
#define CODE_binlog_create_message_service_encr 0x8b4b9395
#define CODE_binlog_delete_msg 0xa1d6ab6d
void *alloc_log_event (struct binlog *bl, int l);
void add_log_event (struct binlog *bl, struct mtproto_connection *self, const int *data, int l);
void write_binlog (struct binlog *bl);
void bl_do_set_auth_key_id (struct telegram *instance, int num, unsigned char *buf);
void bl_do_dc_option (struct binlog *bl, struct mtproto_connection *self, int id, int l1, const char *name, int l2, const char *ip, int port, struct telegram *instance);
void bl_do_set_our_id (struct binlog *bl, struct mtproto_connection *self, int id);
void bl_do_new_user (struct binlog *bl, struct mtproto_connection *self, int id, const char *f, int fl, const char *l, int ll, long long access_token, const char *p, int pl, int contact);
void bl_do_user_delete (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U);
void bl_do_set_user_profile_photo (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, long long photo_id, struct file_location *big, struct file_location *small);
void bl_do_set_user_name (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, const char *f, int fl, const char *l, int ll);
void bl_do_set_user_access_token (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, long long access_token);
void bl_do_set_user_phone (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, const char *p, int pl);
void bl_do_set_user_friend (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, int friend);
void bl_do_set_user_full_photo (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, const int *start, int len);
void bl_do_set_user_blocked (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, int blocked);
void bl_do_set_user_real_name (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, const char *f, int fl, const char *l, int ll);
void bl_do_encr_chat_delete (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U);
void bl_do_encr_chat_requested (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, long long access_hash, int date, int admin_id, int user_id, unsigned char g_key[], unsigned char nonce[]);
void bl_do_set_encr_chat_access_hash (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, long long access_hash);
void bl_do_set_encr_chat_date (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, int date);
void bl_do_set_encr_chat_state (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, enum secret_chat_state state);
void bl_do_encr_chat_accepted (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, const unsigned char g_key[], const unsigned char nonce[], long long key_fingerprint);
void bl_do_set_encr_chat_key (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *E, unsigned char key[], long long key_fingerprint);
void bl_do_encr_chat_init (struct binlog *bl, struct mtproto_connection *self, int id, int user_id, unsigned char random[], unsigned char g_a[]);
void bl_do_dc_signed (struct binlog *bl, struct mtproto_connection *self, int id);
void bl_do_set_working_dc (struct binlog *bl, struct mtproto_connection *self, int num);
void bl_do_set_dh_params (struct binlog *bl, struct mtproto_connection *self, int root, unsigned char prime[], int version);
void bl_do_set_pts (struct binlog *bl, struct mtproto_connection *self, int pts);
void bl_do_set_qts (struct binlog *bl, struct mtproto_connection *self, int qts);
void bl_do_set_seq (struct binlog *bl, struct mtproto_connection *self, int seq);
void bl_do_set_date (struct binlog *bl, struct mtproto_connection *self, int date);
void bl_do_create_chat (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int y, const char *s, int l, int users_num, int date, int version, struct file_location *big, struct file_location *small);
void bl_do_chat_forbid (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int on);
void bl_do_set_chat_title (struct binlog *bl, struct mtproto_connection *self, struct chat *C, const char *s, int l);
void bl_do_set_chat_photo (struct binlog *bl, struct mtproto_connection *self, struct chat *C, struct file_location *big, struct file_location *small);
void bl_do_set_chat_date (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int date);
void bl_do_set_chat_set_in_chat (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int on);
void bl_do_set_chat_version (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int version, int user_num);
void bl_do_set_chat_admin (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int admin);
void bl_do_set_chat_participants (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int version, int user_num, struct chat_user *users);
void bl_do_set_chat_full_photo (struct binlog *bl, struct mtproto_connection *self, struct chat *U, const int *start, int len);
void bl_do_chat_add_user (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int version, int user, int inviter, int date);
void bl_do_chat_del_user (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int version, int user);
void bl_do_create_message_text (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s);
void bl_do_create_message_text_fwd (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s);
void bl_do_create_message_service (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len);
void bl_do_create_message_service_fwd (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, const int *data, int len);
void bl_do_create_message_media (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len);
void bl_do_create_message_media_fwd (struct binlog *bl, struct mtproto_connection *self, int msg_id, int from_id, int to_type, int to_id, int date, int fwd, int fwd_date, int l, const char *s, const int *data, int len);
void bl_do_create_message_media_encr (struct binlog *bl, struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s, const int *data, int len, const int *data2, int len2);
void bl_do_create_message_service_encr (struct binlog *bl, struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, const int *data, int len);
void bl_do_send_message_text (struct binlog *bl, struct mtproto_connection *self, long long msg_id, int from_id, int to_type, int to_id, int date, int l, const char *s);
void bl_do_set_unread (struct binlog *bl, struct mtproto_connection *self, struct message *M, int unread);
void bl_do_set_message_sent (struct binlog *bl, struct mtproto_connection *self, struct message *M);
void bl_do_set_msg_id (struct binlog *bl, struct mtproto_connection *self, struct message *M, int id);
void bl_do_delete_msg (struct binlog *bl, struct mtproto_connection *self, struct message *M);
#endif

View file

@ -1,10 +0,0 @@
log.peer peer_type:int peer_id:int = log.Peer;
log.dc num:int hostname:string ip:string port:int = log.Event;
log.dcRenum old_num:int new_num:int = log.Event;
log.authKey dc:int key:bytes key_id:long = log.Event;
log.signIn dc:int id:int = log.Event;
log.user id:int flags:int access_hash:long first_name:string last_name:string real_first_name:string real_last_name:string phone:string photo:log.Photo photo_id:long photo_big:log.FileLocation photo_small:long.FileLocation = log.Event;

View file

@ -1,383 +0,0 @@
/*
This file is part of telegram-client.
Telegram-client 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.
Telegram-client 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 telegram-client. If not, see <http://www.gnu.org/licenses/>.
Copyright Vitaly Valtman 2013
*/
#ifndef CONSTANTS_H
#define CONSTANTS_H
#define CODE_bool_false 0xbc799737
#define CODE_bool_true 0x997275b5
#define CODE_vector 0x1cb5c415
#define CODE_error 0xc4b9f9bb
#define CODE_null 0x56730bcc
#define CODE_input_peer_empty 0x7f3b18ea
#define CODE_input_peer_self 0x7da07ec9
#define CODE_input_peer_contact 0x1023dbe8
#define CODE_input_peer_foreign 0x9b447325
#define CODE_input_peer_chat 0x179be863
#define CODE_input_user_empty 0xb98886cf
#define CODE_input_user_self 0xf7c1b13f
#define CODE_input_user_contact 0x86e94f65
#define CODE_input_user_foreign 0x655e74ff
#define CODE_input_phone_contact 0xf392b7f4
#define CODE_input_file 0xf52ff27f
#define CODE_input_media_empty 0x9664f57f
#define CODE_input_media_uploaded_photo 0x2dc53a7d
#define CODE_input_media_photo 0x8f2ab2ec
#define CODE_input_media_geo_point 0xf9c44144
#define CODE_input_media_contact 0xa6e45987
#define CODE_input_media_uploaded_video 0x4847d92a
#define CODE_input_media_uploaded_thumb_video 0xe628a145
#define CODE_input_media_video 0x7f023ae6
#define CODE_input_chat_photo_empty 0x1ca48f57
#define CODE_input_chat_uploaded_photo 0x94254732
#define CODE_input_chat_photo 0xb2e1bf08
#define CODE_input_geo_point_empty 0xe4c123d6
#define CODE_input_geo_point 0xf3b7acc9
#define CODE_input_photo_empty 0x1cd7bf0d
#define CODE_input_photo 0xfb95c6c4
#define CODE_input_video_empty 0x5508ec75
#define CODE_input_video 0xee579652
#define CODE_input_file_location 0x14637196
#define CODE_input_video_file_location 0x3d0364ec
#define CODE_input_photo_crop_auto 0xade6b004
#define CODE_input_photo_crop 0xd9915325
#define CODE_input_app_event 0x770656a8
#define CODE_peer_user 0x9db1bc6d
#define CODE_peer_chat 0xbad0e5bb
#define CODE_storage_file_unknown 0xaa963b05
#define CODE_storage_file_jpeg 0x7efe0e
#define CODE_storage_file_gif 0xcae1aadf
#define CODE_storage_file_png 0xa4f63c0
#define CODE_storage_file_mp3 0x528a0677
#define CODE_storage_file_mov 0x4b09ebbc
#define CODE_storage_file_partial 0x40bc6f52
#define CODE_storage_file_mp4 0xb3cea0e4
#define CODE_storage_file_webp 0x1081464c
#define CODE_file_location_unavailable 0x7c596b46
#define CODE_file_location 0x53d69076
#define CODE_user_empty 0x200250ba
#define CODE_user_self 0x720535ec
#define CODE_user_contact 0xf2fb8319
#define CODE_user_request 0x22e8ceb0
#define CODE_user_foreign 0x5214c89d
#define CODE_user_deleted 0xb29ad7cc
#define CODE_user_profile_photo_empty 0x4f11bae1
#define CODE_user_profile_photo 0xd559d8c8
#define CODE_user_status_empty 0x9d05049
#define CODE_user_status_online 0xedb93949
#define CODE_user_status_offline 0x8c703f
#define CODE_chat_empty 0x9ba2d800
#define CODE_chat 0x6e9c9bc7
#define CODE_chat_forbidden 0xfb0ccc41
#define CODE_chat_full 0x630e61be
#define CODE_chat_participant 0xc8d7493e
#define CODE_chat_participants_forbidden 0xfd2bb8a
#define CODE_chat_participants 0x7841b415
#define CODE_chat_photo_empty 0x37c1011c
#define CODE_chat_photo 0x6153276a
#define CODE_message_empty 0x83e5de54
#define CODE_message 0x22eb6aba
#define CODE_message_forwarded 0x5f46804
#define CODE_message_service 0x9f8d60bb
#define CODE_message_media_empty 0x3ded6320
#define CODE_message_media_photo 0xc8c45a2a
#define CODE_message_media_video 0xa2d24290
#define CODE_message_media_geo 0x56e0d474
#define CODE_message_media_contact 0x5e7d2f39
#define CODE_message_media_unsupported 0x29632a36
#define CODE_message_action_empty 0xb6aef7b0
#define CODE_message_action_chat_create 0xa6638b9a
#define CODE_message_action_chat_edit_title 0xb5a1ce5a
#define CODE_message_action_chat_edit_photo 0x7fcb13a8
#define CODE_message_action_chat_delete_photo 0x95e3fbef
#define CODE_message_action_chat_add_user 0x5e3cfc4b
#define CODE_message_action_chat_delete_user 0xb2ae9b0c
#define CODE_dialog 0x214a8cdf
#define CODE_photo_empty 0x2331b22d
#define CODE_photo 0x22b56751
#define CODE_photo_size_empty 0xe17e23c
#define CODE_photo_size 0x77bfb61b
#define CODE_photo_cached_size 0xe9a734fa
#define CODE_video_empty 0xc10658a8
#define CODE_video 0x5a04a49f
#define CODE_geo_point_empty 0x1117dd5f
#define CODE_geo_point 0x2049d70c
#define CODE_auth_checked_phone 0xe300cc3b
#define CODE_auth_sent_code 0xefed51d9
#define CODE_auth_authorization 0xf6b673a4
#define CODE_auth_exported_authorization 0xdf969c2d
#define CODE_input_notify_peer 0xb8bc5b0c
#define CODE_input_notify_users 0x193b4417
#define CODE_input_notify_chats 0x4a95e84e
#define CODE_input_notify_all 0xa429b886
#define CODE_input_peer_notify_events_empty 0xf03064d8
#define CODE_input_peer_notify_events_all 0xe86a2c74
#define CODE_input_peer_notify_settings 0x46a2ce98
#define CODE_peer_notify_events_empty 0xadd53cb3
#define CODE_peer_notify_events_all 0x6d1ded88
#define CODE_peer_notify_settings_empty 0x70a68512
#define CODE_peer_notify_settings 0x8d5e11ee
#define CODE_wall_paper 0xccb03657
#define CODE_user_full 0x771095da
#define CODE_contact 0xf911c994
#define CODE_imported_contact 0xd0028438
#define CODE_contact_blocked 0x561bc879
#define CODE_contact_found 0xea879f95
#define CODE_contact_suggested 0x3de191a1
#define CODE_contact_status 0xaa77b873
#define CODE_chat_located 0x3631cf4c
#define CODE_contacts_foreign_link_unknown 0x133421f8
#define CODE_contacts_foreign_link_requested 0xa7801f47
#define CODE_contacts_foreign_link_mutual 0x1bea8ce1
#define CODE_contacts_my_link_empty 0xd22a1c60
#define CODE_contacts_my_link_requested 0x6c69efee
#define CODE_contacts_my_link_contact 0xc240ebd9
#define CODE_contacts_link 0xeccea3f5
#define CODE_contacts_contacts 0x6f8b8cb2
#define CODE_contacts_contacts_not_modified 0xb74ba9d2
#define CODE_contacts_imported_contacts 0xd1cd0a4c
#define CODE_contacts_blocked 0x1c138d15
#define CODE_contacts_blocked_slice 0x900802a1
#define CODE_contacts_found 0x566000e
#define CODE_contacts_suggested 0x5649dcc5
#define CODE_messages_dialogs 0x15ba6c40
#define CODE_messages_dialogs_slice 0x71e094f3
#define CODE_messages_messages 0x8c718e87
#define CODE_messages_messages_slice 0xb446ae3
#define CODE_messages_message_empty 0x3f4e0648
#define CODE_messages_message 0xff90c417
#define CODE_messages_stated_messages 0x969478bb
#define CODE_messages_stated_message 0xd07ae726
#define CODE_messages_sent_message 0xd1f4d35c
#define CODE_messages_chat 0x40e9002a
#define CODE_messages_chats 0x8150cbd8
#define CODE_messages_chat_full 0xe5d7d19c
#define CODE_messages_affected_history 0xb7de36f2
#define CODE_input_messages_filter_empty 0x57e2f66c
#define CODE_input_messages_filter_photos 0x9609a51c
#define CODE_input_messages_filter_video 0x9fc00e65
#define CODE_input_messages_filter_photo_video 0x56e9f0e4
#define CODE_update_new_message 0x13abdb3
#define CODE_update_message_i_d 0x4e90bfd6
#define CODE_update_read_messages 0xc6649e31
#define CODE_update_delete_messages 0xa92bfe26
#define CODE_update_restore_messages 0xd15de04d
#define CODE_update_user_typing 0x6baa8508
#define CODE_update_chat_user_typing 0x3c46cfe6
#define CODE_update_chat_participants 0x7761198
#define CODE_update_user_status 0x1bfbd823
#define CODE_update_user_name 0xda22d9ad
#define CODE_update_user_photo 0x95313b0c
#define CODE_update_contact_registered 0x2575bbb9
#define CODE_update_contact_link 0x51a48a9a
#define CODE_update_activation 0x6f690963
#define CODE_update_new_authorization 0x8f06529a
#define CODE_updates_state 0xa56c2a3e
#define CODE_updates_difference_empty 0x5d75a138
#define CODE_updates_difference 0xf49ca0
#define CODE_updates_difference_slice 0xa8fb1981
#define CODE_updates_too_long 0xe317af7e
#define CODE_update_short_message 0xd3f45784
#define CODE_update_short_chat_message 0x2b2fbd4e
#define CODE_update_short 0x78d4dec1
#define CODE_updates_combined 0x725b04c3
#define CODE_updates 0x74ae4240
#define CODE_photos_photos 0x8dca6aa5
#define CODE_photos_photos_slice 0x15051f54
#define CODE_photos_photo 0x20212ca8
#define CODE_upload_file 0x96a18d5
#define CODE_dc_option 0x2ec2a43c
#define CODE_config 0x2e54dd74
#define CODE_nearest_dc 0x8e1a1775
#define CODE_help_app_update 0x8987f311
#define CODE_help_no_app_update 0xc45a6536
#define CODE_help_invite_text 0x18cb9f78
#define CODE_messages_stated_messages_links 0x3e74f5c6
#define CODE_messages_stated_message_link 0xa9af2881
#define CODE_messages_sent_message_link 0xe9db4a3f
#define CODE_input_geo_chat 0x74d456fa
#define CODE_input_notify_geo_chat_peer 0x4d8ddec8
#define CODE_geo_chat 0x75eaea5a
#define CODE_geo_chat_message_empty 0x60311a9b
#define CODE_geo_chat_message 0x4505f8e1
#define CODE_geo_chat_message_service 0xd34fa24e
#define CODE_geochats_stated_message 0x17b1578b
#define CODE_geochats_located 0x48feb267
#define CODE_geochats_messages 0xd1526db1
#define CODE_geochats_messages_slice 0xbc5863e8
#define CODE_message_action_geo_chat_create 0x6f038ebc
#define CODE_message_action_geo_chat_checkin 0xc7d53de
#define CODE_update_new_geo_chat_message 0x5a68e3f7
#define CODE_wall_paper_solid 0x63117f24
#define CODE_update_new_encrypted_message 0x12bcbd9a
#define CODE_update_encrypted_chat_typing 0x1710f156
#define CODE_update_encryption 0xb4a2e88d
#define CODE_update_encrypted_messages_read 0x38fe25b7
#define CODE_encrypted_chat_empty 0xab7ec0a0
#define CODE_encrypted_chat_waiting 0x3bf703dc
#define CODE_encrypted_chat_requested 0xc878527e
#define CODE_encrypted_chat 0xfa56ce36
#define CODE_encrypted_chat_discarded 0x13d6dd27
#define CODE_input_encrypted_chat 0xf141b5e1
#define CODE_encrypted_file_empty 0xc21f497e
#define CODE_encrypted_file 0x4a70994c
#define CODE_input_encrypted_file_empty 0x1837c364
#define CODE_input_encrypted_file_uploaded 0x64bd0306
#define CODE_input_encrypted_file 0x5a17b5e5
#define CODE_input_encrypted_file_location 0xf5235d55
#define CODE_encrypted_message 0xed18c118
#define CODE_encrypted_message_service 0x23734b06
#define CODE_decrypted_message_layer 0x99a438cf
#define CODE_decrypted_message 0x1f814f1f
#define CODE_decrypted_message_service 0xaa48327d
#define CODE_decrypted_message_media_empty 0x89f5c4a
#define CODE_decrypted_message_media_photo 0x32798a8c
#define CODE_decrypted_message_media_video 0x4cee6ef3
#define CODE_decrypted_message_media_geo_point 0x35480a59
#define CODE_decrypted_message_media_contact 0x588a0a97
#define CODE_decrypted_message_action_set_message_t_t_l 0xa1733aec
#define CODE_messages_dh_config_not_modified 0xc0e24635
#define CODE_messages_dh_config 0x2c221edd
#define CODE_messages_sent_encrypted_message 0x560f8935
#define CODE_messages_sent_encrypted_file 0x9493ff32
#define CODE_input_file_big 0xfa4f0bb5
#define CODE_input_encrypted_file_big_uploaded 0x2dc173c8
#define CODE_update_chat_participant_add 0x3a0eeb22
#define CODE_update_chat_participant_delete 0x6e5f8c22
#define CODE_update_dc_options 0x8e5e9873
#define CODE_input_media_uploaded_audio 0x61a6d436
#define CODE_input_media_audio 0x89938781
#define CODE_input_media_uploaded_document 0x34e794bd
#define CODE_input_media_uploaded_thumb_document 0x3e46de5d
#define CODE_input_media_document 0xd184e841
#define CODE_message_media_document 0x2fda2204
#define CODE_message_media_audio 0xc6b68300
#define CODE_input_audio_empty 0xd95adc84
#define CODE_input_audio 0x77d440ff
#define CODE_input_document_empty 0x72f0eaae
#define CODE_input_document 0x18798952
#define CODE_input_audio_file_location 0x74dc404d
#define CODE_input_document_file_location 0x4e45abe9
#define CODE_decrypted_message_media_document 0xb095434b
#define CODE_decrypted_message_media_audio 0x6080758f
#define CODE_audio_empty 0x586988d8
#define CODE_audio 0x427425e7
#define CODE_document_empty 0x36f8c871
#define CODE_document 0x9efc6326
#define CODE_invoke_after_msg 0xcb9f372d
#define CODE_invoke_after_msgs 0x3dc4b4f0
#define CODE_invoke_with_layer1 0x53835315
#define CODE_auth_check_phone 0x6fe51dfb
#define CODE_auth_send_code 0x768d5f4d
#define CODE_auth_send_call 0x3c51564
#define CODE_auth_sign_up 0x1b067634
#define CODE_auth_sign_in 0xbcd51581
#define CODE_auth_log_out 0x5717da40
#define CODE_auth_reset_authorizations 0x9fab0d1a
#define CODE_auth_send_invites 0x771c1d97
#define CODE_auth_export_authorization 0xe5bfffcd
#define CODE_auth_import_authorization 0xe3ef9613
#define CODE_account_register_device 0x446c712c
#define CODE_account_unregister_device 0x65c55b40
#define CODE_account_update_notify_settings 0x84be5b93
#define CODE_account_get_notify_settings 0x12b3ad31
#define CODE_account_reset_notify_settings 0xdb7e1747
#define CODE_account_update_profile 0xf0888d68
#define CODE_account_update_status 0x6628562c
#define CODE_account_get_wall_papers 0xc04cfac2
#define CODE_users_get_users 0xd91a548
#define CODE_users_get_full_user 0xca30a5b1
#define CODE_contacts_get_statuses 0xc4a353ee
#define CODE_contacts_get_contacts 0x22c6aa08
#define CODE_contacts_import_contacts 0xda30b32d
#define CODE_contacts_search 0x11f812d8
#define CODE_contacts_get_suggested 0xcd773428
#define CODE_contacts_delete_contact 0x8e953744
#define CODE_contacts_delete_contacts 0x59ab389e
#define CODE_contacts_block 0x332b49fc
#define CODE_contacts_unblock 0xe54100bd
#define CODE_contacts_get_blocked 0xf57c350f
#define CODE_messages_get_messages 0x4222fa74
#define CODE_messages_get_dialogs 0xeccf1df6
#define CODE_messages_get_history 0x92a1df2f
#define CODE_messages_search 0x7e9f2ab
#define CODE_messages_read_history 0xb04f2510
#define CODE_messages_delete_history 0xf4f8fb61
#define CODE_messages_delete_messages 0x14f2dd0a
#define CODE_messages_restore_messages 0x395f9d7e
#define CODE_messages_received_messages 0x28abcb68
#define CODE_messages_set_typing 0x719839e9
#define CODE_messages_send_message 0x4cde0aab
#define CODE_messages_send_media 0xa3c85d76
#define CODE_messages_forward_messages 0x514cd10f
#define CODE_messages_get_chats 0x3c6aa187
#define CODE_messages_get_full_chat 0x3b831c66
#define CODE_messages_edit_chat_title 0xb4bc68b5
#define CODE_messages_edit_chat_photo 0xd881821d
#define CODE_messages_add_chat_user 0x2ee9ee9e
#define CODE_messages_delete_chat_user 0xc3c5cd23
#define CODE_messages_create_chat 0x419d9aee
#define CODE_updates_get_state 0xedd4882a
#define CODE_updates_get_difference 0xa041495
#define CODE_photos_update_profile_photo 0xeef579a0
#define CODE_photos_upload_profile_photo 0xd50f9c88
#define CODE_upload_save_file_part 0xb304a621
#define CODE_upload_get_file 0xe3a6cfb5
#define CODE_help_get_config 0xc4f9186b
#define CODE_help_get_nearest_dc 0x1fb33026
#define CODE_help_get_app_update 0xc812ac7e
#define CODE_help_save_app_log 0x6f02f748
#define CODE_help_get_invite_text 0xa4a95186
#define CODE_photos_get_user_photos 0xb7ee553c
#define CODE_invoke_with_layer2 0x289dd1f6
#define CODE_messages_forward_message 0x3f3f4f2
#define CODE_messages_send_broadcast 0x41bb0972
#define CODE_invoke_with_layer3 0xb7475268
#define CODE_geochats_get_located 0x7f192d8f
#define CODE_geochats_get_recents 0xe1427e6f
#define CODE_geochats_checkin 0x55b3e8fb
#define CODE_geochats_get_full_chat 0x6722dd6f
#define CODE_geochats_edit_chat_title 0x4c8e2273
#define CODE_geochats_edit_chat_photo 0x35d81a95
#define CODE_geochats_search 0xcfcdc44d
#define CODE_geochats_get_history 0xb53f7a68
#define CODE_geochats_set_typing 0x8b8a729
#define CODE_geochats_send_message 0x61b0044
#define CODE_geochats_send_media 0xb8f0deff
#define CODE_geochats_create_geo_chat 0xe092e16
#define CODE_invoke_with_layer4 0xdea0d430
#define CODE_invoke_with_layer5 0x417a57ae
#define CODE_invoke_with_layer6 0x3a64d54d
#define CODE_invoke_with_layer7 0xa5be56d3
#define CODE_messages_get_dh_config 0x26cf8950
#define CODE_messages_request_encryption 0xf64daf43
#define CODE_messages_accept_encryption 0x3dbc0415
#define CODE_messages_discard_encryption 0xedd923c5
#define CODE_messages_set_encrypted_typing 0x791451ed
#define CODE_messages_read_encrypted_history 0x7f4b690a
#define CODE_messages_send_encrypted 0xa9776773
#define CODE_messages_send_encrypted_file 0x9a901b66
#define CODE_messages_send_encrypted_service 0x32d439a4
#define CODE_messages_received_queue 0x55a5bb66
#define CODE_invoke_with_layer8 0xe9abd9fd
#define CODE_upload_save_big_file_part 0xde7b673d
#define CODE_init_connection 0x69796de9
#define CODE_invoke_with_layer9 0x76715a63
#define CODE_invoke_with_layer10 0x39620c41
#define CODE_invoke_with_layer11 0xa6b88fdf
#define CODE_invoke_with_layer12 0xdda60d3c
#endif

View file

@ -1,37 +0,0 @@
BEGIN {
print "/*";
print " This file is part of telegram-client.";
print "";
print " Telegram-client is free software: you can redistribute it and/or modify";
print " it under the terms of the GNU General Public License as published by";
print " the Free Software Foundation, either version 2 of the License, or";
print " (at your option) any later version.";
print "";
print " Telegram-client is distributed in the hope that it will be useful,";
print " but WITHOUT ANY WARRANTY; without even the implied warranty of";
print " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the";
print " GNU General Public License for more details.";
print "";
print " You should have received a copy of the GNU General Public License";
print " along with this telegram-client. If not, see <http://www.gnu.org/licenses/>.";
print "";
print " Copyright Vitaly Valtman 2013";
print "*/";
print "#ifndef CONSTANTS_H";
print "#define CONSTANTS_H";
}
// {
if (split ($1, a, "#") == 2) {
gsub (/[A-Z]/, "_&", a[1]);
gsub (/[.]/, "_", a[1]);
if (a[2] in h) {
print "ERROR: Duplicate magic " a[2] " for define " a[1] " and " h[a[2]] >"/dev/stderr/"
exit 1;
}
h[a[2]] = a[1];
print "#define", "CODE_" tolower(a[1]), "0x" a[2];
}
}
END {
print "#endif";
}

View file

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

Before

Width:  |  Height:  |  Size: 671 B

After

Width:  |  Height:  |  Size: 671 B

View file

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 1 KiB

View file

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -1,24 +0,0 @@
/*
This file is part of telegram-client.
Telegram-client 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.
Telegram-client 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 telegram-client. If not, see <http://www.gnu.org/licenses/>.
Copyright Vitaly Valtman 2013
*/
#ifndef __INCLUDE_H__
#define __INCLUDE_H__
#define UU __attribute__ ((unused))
#endif

350
loop.c
View file

@ -1,350 +0,0 @@
/*
This file is part of telegram-client.
Telegram-client 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.
Telegram-client 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 telegram-client. If not, see <http://www.gnu.org/licenses/>.
Copyright Vitaly Valtman 2013
*/
#define _GNU_SOURCE
#define READLINE_CALLBACKS
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <poll.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "net.h"
#include "mtproto-client.h"
#include "queries.h"
#include "telegram.h"
#include "loop.h"
#include "binlog.h"
//
#include "purple-plugin/telegram-purple.h"
//
char *get_auth_key_filename (void);
char *get_state_filename (void);
int zero[512];
void write_dc (int auth_file_fd, struct dc *DC) {
debug("writing to auth_file: auth_file_fd: %d, port: %d, ip: %s\n", auth_file_fd, DC->port, DC->ip);
assert (write (auth_file_fd, &DC->port, 4) == 4);
int l = strlen (DC->ip);
assert (write (auth_file_fd, &l, 4) == 4);
assert (write (auth_file_fd, DC->ip, l) == l);
if (DC->flags & 1) {
assert (write (auth_file_fd, &DC->auth_key_id, 8) == 8);
assert (write (auth_file_fd, DC->auth_key, 256) == 256);
} else {
assert (write (auth_file_fd, zero, 256 + 8) == 256 + 8);
}
assert (write (auth_file_fd, &DC->server_salt, 8) == 8);
assert (write (auth_file_fd, &DC->has_auth, 4) == 4);
}
void write_auth_file (struct authorization_state *state, const char *filename) {
debug("Writing to auth_file: %s\n", filename);
int auth_file_fd = open (filename, O_CREAT | O_RDWR, 0600);
assert (auth_file_fd >= 0);
int x = DC_SERIALIZED_MAGIC_V2;
assert (write (auth_file_fd, &x, 4) == 4);
x = MAX_DC_ID;
assert (write (auth_file_fd, &x, 4) == 4);
assert (write (auth_file_fd, &state->dc_working_num, 4) == 4);
assert (write (auth_file_fd, &state->auth_state, 4) == 4);
int i;
for (i = 0; i <= MAX_DC_ID; i++) {
if (state->DC_list[i]) {
x = 1;
assert (write (auth_file_fd, &x, 4) == 4);
write_dc (auth_file_fd, state->DC_list[i]);
} else {
x = 0;
assert (write (auth_file_fd, &x, 4) == 4);
}
}
assert (write (auth_file_fd, &state->our_id, 4) == 4);
close (auth_file_fd);
}
void read_dc (int auth_file_fd, int id, unsigned ver, struct dc *DC_list[]) {
int port = 0;
assert (read (auth_file_fd, &port, 4) == 4);
int l = 0;
assert (read (auth_file_fd, &l, 4) == 4);
assert (l >= 0);
char *ip = talloc (l + 1);
assert (read (auth_file_fd, ip, l) == l);
ip[l] = 0;
struct dc *DC = alloc_dc (DC_list, id, ip, port);
assert (read (auth_file_fd, &DC->auth_key_id, 8) == 8);
assert (read (auth_file_fd, &DC->auth_key, 256) == 256);
assert (read (auth_file_fd, &DC->server_salt, 8) == 8);
if (DC->auth_key_id) {
DC->flags |= 1;
}
if (ver != DC_SERIALIZED_MAGIC) {
assert (read (auth_file_fd, &DC->has_auth, 4) == 4);
} else {
DC->has_auth = 0;
}
}
void empty_auth_file (const char *filename) {
struct authorization_state state;
memset(state.DC_list, 0, 11 * sizeof(void *));
debug("empty_auth_file()\n");
alloc_dc (state.DC_list, TG_DC_NUM, tstrdup (TG_SERVER), TG_PORT);
state.dc_working_num = TG_DC_NUM;
state.auth_state = 0;
write_auth_file (&state, filename);
}
/**
* Read the auth-file and return the read authorization state
*
* When the given file doesn't exist, create a new empty
* file containing the default authorization state at this
* path
*/
struct authorization_state read_auth_file (const char *filename) {
debug("read_auth_file()\n");
struct authorization_state state;
memset(state.DC_list, 0, 11 * sizeof(void *));
int auth_file_fd = open (filename, O_RDWR, 0600);
debug("fd: %d\n", auth_file_fd);
if (auth_file_fd < 0) {
debug("auth_file does not exist, creating empty...\n");
empty_auth_file (filename);
}
auth_file_fd = open (filename, O_RDWR, 0600);
assert (auth_file_fd >= 0);
// amount of data centers
unsigned x;
// magic number of file
unsigned m;
if (read (auth_file_fd, &m, 4) < 4 || (m != DC_SERIALIZED_MAGIC && m != DC_SERIALIZED_MAGIC_V2)) {
debug("Invalid File content, wrong Magic numebr\n");
close (auth_file_fd);
empty_auth_file (filename);
return state;
}
assert (read (auth_file_fd, &x, 4) == 4);
assert (x <= MAX_DC_ID);
assert (read (auth_file_fd, &state.dc_working_num, 4) == 4);
assert (read (auth_file_fd, &state.auth_state, 4) == 4);
debug ("dc_working_num=%d, auth_state=%d \n", state.dc_working_num, state.auth_state);
if (m == DC_SERIALIZED_MAGIC) {
state.auth_state = 700;
}
int i;
for (i = 0; i <= (int)x; i++) {
int y;
assert (read (auth_file_fd, &y, 4) == 4);
if (y) {
read_dc (auth_file_fd, i, m, state.DC_list);
debug("loaded dc[%d] - port: %d, ip: %s, auth_key_id: %lli, server_salt: %lli, has_auth: %d\n",
i, state.DC_list[i]->port, state.DC_list[i]->ip, state.DC_list[i]->auth_key_id,
state.DC_list[i]->server_salt, state.DC_list[i]->has_auth);
} else {
debug("loaded dc[%d] - NULL\n", i);
}
}
int l = read (auth_file_fd, &state.our_id, 4);
if (l < 4) {
assert (!l);
}
close (auth_file_fd);
struct dc *DC_working = state.DC_list[state.dc_working_num];
if (m == DC_SERIALIZED_MAGIC) {
DC_working->has_auth = 1;
}
debug("loaded authorization state - our_id: %d, auth_state: %d, dc_working_num: %d \n", state.our_id, state.auth_state, state.dc_working_num);
return state;
}
struct protocol_state read_state_file (const char *filename) {
debug("read_state_file()\n");
struct protocol_state state = {0, 0, 0, 0};
int state_file_fd = open (filename, O_CREAT | O_RDWR, 0600);
if (state_file_fd < 0) {
return state;
}
int version, magic;
if (read (state_file_fd, &magic, 4) < 4) { close (state_file_fd); return state; }
if (magic != (int)STATE_FILE_MAGIC) { close (state_file_fd); return state; }
if (read (state_file_fd, &version, 4) < 4) { close (state_file_fd); return state; }
assert (version >= 0);
int x[4];
if (read (state_file_fd, x, 16) < 16) {
close (state_file_fd);
return state;
}
state.pts = x[0];
state.qts = x[1];
state.seq = x[2];
state.last_date = x[3];
close (state_file_fd);
debug("loaded session state - pts: %d, qts: %d, seq: %d, last_date: %d.\n", state.pts,
state.qts, state.seq, state.last_date);
return state;
}
void write_state_file (struct protocol_state *state, const char* filename) {
int state_file_fd = open (filename, O_CREAT | O_RDWR, 0600);
if (state_file_fd < 0) {
return;
}
int x[6];
x[0] = STATE_FILE_MAGIC;
x[1] = 0;
x[2] = state->pts;
x[3] = state->qts;
x[4] = state->seq;
x[5] = state->last_date;
assert (write (state_file_fd, x, 24) == 24);
close (state_file_fd);
}
void read_secret_chat_file (struct telegram *instance, const char *file) {
struct binlog *bl = instance->bl;
int fd = open (file, O_CREAT | O_RDWR, 0600);
if (fd < 0) {
return;
}
int x[2];
if (read (fd, x, 8) < 8) {
close (fd); return;
}
if (x[0] != (int)SECRET_CHAT_FILE_MAGIC) { close (fd); return; }
int version = x[1];
assert (version >= 0);
int cc;
assert (read (fd, &cc, 4) == 4);
int i;
for (i = 0; i < cc; i++) {
peer_t *P = talloc0 (sizeof (*P));
struct secret_chat *E = &P->encr_chat;
int t;
assert (read (fd, &t, 4) == 4);
P->id = MK_ENCR_CHAT (t);
assert (read (fd, &P->flags, 4) == 4);
assert (read (fd, &t, 4) == 4);
assert (t > 0);
P->print_name = talloc (t + 1);
assert (read (fd, P->print_name, t) == t);
P->print_name[t] = 0;
peer_insert_name (bl, P);
assert (read (fd, &E->state, 4) == 4);
assert (read (fd, &E->user_id, 4) == 4);
assert (read (fd, &E->admin_id, 4) == 4);
assert (read (fd, &E->ttl, 4) == 4);
assert (read (fd, &E->access_hash, 8) == 8);
if (E->state != sc_waiting) {
E->g_key = talloc (256);
assert (read (fd, E->g_key, 256) == 256);
E->nonce = talloc (256);
assert (read (fd, E->nonce, 256) == 256);
}
assert (read (fd, E->key, 256) == 256);
assert (read (fd, &E->key_fingerprint, 8) == 8);
insert_encrypted_chat (bl, P);
}
if (version >= 1) {
assert (read (fd, &instance->encr_root, 4) == 4);
if (instance->encr_root) {
assert (read (fd, &instance->encr_param_version, 4) == 4);
instance->encr_prime = talloc (256);
assert (read (fd, instance->encr_prime, 256) == 256);
}
}
close (fd);
}
// TODO: Refactor
void write_secret_chat_file (struct telegram *instance, const char *filename) {
struct binlog *bl = instance->bl;
int fd = open (filename, O_CREAT | O_RDWR, 0600);
if (fd < 0) {
return;
}
int x[2];
x[0] = SECRET_CHAT_FILE_MAGIC;
x[1] = 1;
assert (write (fd, x, 8) == 8);
int i;
int cc = 0;
for (i = 0; i < bl->peer_num; i++) if (get_peer_type (bl->Peers[i]->id) == PEER_ENCR_CHAT) {
if (bl->Peers[i]->encr_chat.state != sc_none && bl->Peers[i]->encr_chat.state != sc_deleted) {
cc ++;
}
}
assert (write (fd, &cc, 4) == 4);
for (i = 0; i < bl->peer_num; i++) if (get_peer_type (bl->Peers[i]->id) == PEER_ENCR_CHAT) {
if (bl->Peers[i]->encr_chat.state != sc_none && bl->Peers[i]->encr_chat.state != sc_deleted) {
int t = get_peer_id (bl->Peers[i]->id);
assert (write (fd, &t, 4) == 4);
t = bl->Peers[i]->flags;
assert (write (fd, &t, 4) == 4);
t = strlen (bl->Peers[i]->print_name);
assert (write (fd, &t, 4) == 4);
assert (write (fd, bl->Peers[i]->print_name, t) == t);
assert (write (fd, &bl->Peers[i]->encr_chat.state, 4) == 4);
assert (write (fd, &bl->Peers[i]->encr_chat.user_id, 4) == 4);
assert (write (fd, &bl->Peers[i]->encr_chat.admin_id, 4) == 4);
assert (write (fd, &bl->Peers[i]->encr_chat.ttl, 4) == 4);
assert (write (fd, &bl->Peers[i]->encr_chat.access_hash, 8) == 8);
if (bl->Peers[i]->encr_chat.state != sc_waiting) {
assert (write (fd, bl->Peers[i]->encr_chat.g_key, 256) == 256);
}
if (bl->Peers[i]->encr_chat.state != sc_waiting) {
assert (write (fd, bl->Peers[i]->encr_chat.nonce, 256) == 256);
}
assert (write (fd, bl->Peers[i]->encr_chat.key, 256) == 256);
assert (write (fd, &bl->Peers[i]->encr_chat.key_fingerprint, 8) == 8);
}
}
assert (write (fd, &instance->encr_root, 4) == 4);
if (instance->encr_root) {
assert (write (fd, &instance->encr_param_version, 4) == 4);
assert (write (fd, instance->encr_prime, 256) == 256);
}
close (fd);
}

79
loop.h
View file

@ -1,79 +0,0 @@
/*
This file is part of telegram-client.
Telegram-client 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.
Telegram-client 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 telegram-client. If not, see <http://www.gnu.org/licenses/>.
Copyright Vitaly Valtman 2013
*/
#include "telegram.h"
#ifndef __LOOP_H__
#define __LOOP_H__
// forward declarations
struct dc;
struct telegram;
/**
* The authorization state, storing all known data centers of the telegram
* network and associated shared keys for transport encryption
*/
struct authorization_state {
int dc_working_num;
int auth_state;
struct dc* DC_list[11];
int our_id;
};
/**
* Stores the current update state of a client
*/
struct protocol_state {
/**
* Number of events occured in a text box
*/
int pts;
/**
* Position within a siccession of unconfirmed updates, used for encrypted
* messages
*/
int qts;
/**
* Number of sent updates
*/
int seq;
/**
* Last update
*/
int last_date;
};
void write_secret_chat_file (struct telegram *instance, const char *filename);
void write_auth_file (struct authorization_state *state, const char *filename);
struct authorization_state read_auth_file (const char *filename);
void write_state_file (struct protocol_state *state, const char *filename);
struct protocol_state read_state_file (const char *filename);
void write_secret_chat_file (struct telegram *instance, const char *filename);
void read_secret_chat_file (struct telegram *instance, const char *filename);
#endif

View file

@ -1,7 +1,7 @@
#include <stdio.h>
#include <stdarg.h>
#include "debug.h"
#include "purple-plugin/telegram-purple.h"
#include <debug.h>
#include "telegram-purple.h"
#ifdef DEBUG
#define COLOR_GREY "\033[37;1m"

File diff suppressed because it is too large Load diff

View file

@ -1,514 +0,0 @@
/*
This file is part of telegram-client.
Telegram-client 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.
Telegram-client 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 telegram-client. If not, see <http://www.gnu.org/licenses/>.
Copyright Nikolay Durov, Andrey Lopatin 2012-2013
Copyright Vitaly Valtman 2013
*/
#ifndef __MTPROTO_CLIENT_H__
#define __MTPROTO_CLIENT_H__
/*
* COMMON
*/
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <openssl/rsa.h>
#include <openssl/bn.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
#include <openssl/pem.h>
#include <openssl/sha.h>
#include <stdio.h>
#include <sys/types.h>
#include <netdb.h>
#include "include.h"
#include "tools.h"
#include "constants.h"
#include "msglog.h"
#include "net.h"
#ifdef __MACH__
#include <mach/clock.h>
#include <mach/mach.h>
#endif
/* DH key exchange protocol data structures */
#define CODE_req_pq 0x60469778
#define CODE_resPQ 0x05162463
#define CODE_req_DH_params 0xd712e4be
#define CODE_p_q_inner_data 0x83c95aec
#define CODE_server_DH_inner_data 0xb5890dba
#define CODE_server_DH_params_fail 0x79cb045d
#define CODE_server_DH_params_ok 0xd0e8075c
#define CODE_set_client_DH_params 0xf5045f1f
#define CODE_client_DH_inner_data 0x6643b654
#define CODE_dh_gen_ok 0x3bcbf734
#define CODE_dh_gen_retry 0x46dc1fb9
#define CODE_dh_gen_fail 0xa69dae02
/* service messages */
#define CODE_rpc_result 0xf35c6d01
#define CODE_rpc_error 0x2144ca19
#define CODE_msg_container 0x73f1f8dc
#define CODE_msg_copy 0xe06046b2
#define CODE_msgs_ack 0x62d6b459
#define CODE_bad_msg_notification 0xa7eff811
#define CODE_bad_server_salt 0xedab447b
#define CODE_msgs_state_req 0xda69fb52
#define CODE_msgs_state_info 0x04deb57d
#define CODE_msgs_all_info 0x8cc0d131
#define CODE_new_session_created 0x9ec20908
#define CODE_msg_resend_req 0x7d861a08
#define CODE_ping 0x7abe77ec
#define CODE_pong 0x347773c5
#define CODE_destroy_session 0xe7512126
#define CODE_destroy_session_ok 0xe22045fc
#define CODE_destroy_session_none 0x62d350c9
#define CODE_destroy_sessions 0x9a6face8
#define CODE_destroy_sessions_res 0xa8164668
#define CODE_get_future_salts 0xb921bd04
#define CODE_future_salt 0x0949d9dc
#define CODE_future_salts 0xae500895
#define CODE_rpc_drop_answer 0x58e4a740
#define CODE_rpc_answer_unknown 0x5e2ad36e
#define CODE_rpc_answer_dropped_running 0xcd78e586
#define CODE_rpc_answer_dropped 0xa43ad8b7
#define CODE_msg_detailed_info 0x276d3ec6
#define CODE_msg_new_detailed_info 0x809db6df
#define CODE_ping_delay_disconnect 0xf3427b8c
#define CODE_gzip_packed 0x3072cfa1
#define CODE_input_peer_notify_settings_old 0x3cf4b1be
#define CODE_peer_notify_settings_old 0xddbcd4a5
#define CODE_user_profile_photo_old 0x990d1493
#define CODE_config_old 0x232d5905
#define CODE_msg_new_detailed_info 0x809db6df
#define CODE_msg_detailed_info 0x276d3ec6
/* not really a limit, for struct encrypted_message only */
// #define MAX_MESSAGE_INTS 16384
#define MAX_MESSAGE_INTS 1048576
#define MAX_PROTO_MESSAGE_INTS 1048576
#define _FILE_OFFSET_BITS 64
char *rsa_public_key_name;
#pragma pack(push,4)
struct encrypted_message {
// unencrypted header
long long auth_key_id;
char msg_key[16];
// encrypted part, starts with encrypted header
long long server_salt;
long long session_id;
// long long auth_key_id2; // removed
// first message follows
long long msg_id;
int seq_no;
int msg_len; // divisible by 4
int message[MAX_MESSAGE_INTS];
};
#pragma pack(pop)
/*
* CONNECTION STATES
*/
enum dc_state {
st_init,
st_reqpq_sent,
st_reqdh_sent,
st_client_dh_sent,
st_authorized,
st_error
};
/*
* CLIENT
*/
// forward-declarations
struct timespec;
struct telegram;
struct mtproto_connection;
void mtproto_destroy (struct mtproto_connection *self);
#define DECRYPT_BUFFER_INTS 16384
#define ENCRYPT_BUFFER_INTS 16384
#define PACKET_BUFFER_SIZE (16384 * 100 + 16) // temp fix
struct mtproto_connection {
struct connection *connection;
int auth_success;
enum dc_state c_state;
char nonce[256];
char new_nonce[256];
char server_nonce[256];
int total_packets_sent;
long long total_data_sent;
unsigned long long what;
unsigned p1, p2;
int *in_ptr, *in_end;
// common
int __packet_buffer[PACKET_BUFFER_SIZE], *packet_ptr;
int *packet_buffer;
long long rsa_encrypted_chunks, rsa_decrypted_chunks;
BN_CTX *BN_ctx;
// DH
int encrypt_buffer[ENCRYPT_BUFFER_INTS];
int decrypt_buffer[ENCRYPT_BUFFER_INTS];
char s_power [256];
BIGNUM dh_prime, dh_g, g_a, dh_power, auth_key_num;
struct {
long long auth_key_id;
long long out_msg_id;
int msg_len;
} unenc_msg_header;
// AES IGE
unsigned char aes_key_raw[32], aes_iv[32];
AES_KEY aes_key;
// authorized
struct encrypted_message enc_msg;
long long client_last_msg_id;
long long server_last_msg_id;
int longpoll_count, good_messages;
// TODO: decide whether this should be in struct telegram
// or in struct mtproto_client
int unread_messages;
int our_id;
int pts;
int qts;
int last_date;
int seq;
// extra (queries.c)
int *encr_extra;
int *encr_ptr;
int *encr_end;
// callbacks
void (*on_ready)(struct mtproto_connection *self, void* data);
void *on_ready_data;
void (*on_error)(struct mtproto_connection *self, void *data);
// the amount of currently outgoing messages that
// have not yet received a response
int queries_num;
// binlog that consumes all updates and events of this connection
struct binlog *bl;
// marks this connection for destruction, so it
// will be freed once all queries received a response or timed out
int destroy;
//
// the corresponding telegram instance
//
struct telegram *instance;
void *handle;
};
void mtproto_connection_init (struct mtproto_connection *c);
struct mtproto_connection *mtproto_new(struct dc *DC, int fd, struct telegram *tg);
void mtproto_close(struct mtproto_connection *c);
void mtproto_connect(struct mtproto_connection *c);
void on_start (struct mtproto_connection *self);
long long encrypt_send_message (struct mtproto_connection *self, int *msg, int msg_ints, int useful);
void work_update (struct mtproto_connection *self, long long msg_id);
void work_update_binlog (struct mtproto_connection *self);
int check_g (unsigned char p[256], BIGNUM *g);
int check_g_bn (BIGNUM *p, BIGNUM *g);
int check_DH_params (struct mtproto_connection *self, BIGNUM *p, int g);
void secure_random (void *s, int l);
/*
* Common 2
*/
void prng_seed (struct mtproto_connection *self, const char *password_filename, int password_length);
int serialize_bignum (BIGNUM *b, char *buffer, int maxlen);
long long compute_rsa_key_fingerprint (RSA *key);
static inline void out_ints (struct mtproto_connection *self, const int *what, int len) {
assert (self->packet_ptr + len <= self->packet_buffer + PACKET_BUFFER_SIZE);
memcpy (self->packet_ptr, what, len * 4);
self->packet_ptr += len;
}
static inline void out_int (struct mtproto_connection *self, int x) {
assert (self->packet_ptr + 1 <= self->packet_buffer + PACKET_BUFFER_SIZE);
*self->packet_ptr++ = x;
}
static inline void out_long (struct mtproto_connection *self, long long x) {
assert (self->packet_ptr + 2 <= self->packet_buffer + PACKET_BUFFER_SIZE);
*(long long *)self->packet_ptr = x;
self->packet_ptr += 2;
}
static inline void clear_packet (struct mtproto_connection *self) {
self->packet_ptr = self->packet_buffer;
}
void out_cstring (struct mtproto_connection *self, const char *str, long len);
void out_cstring_careful (struct mtproto_connection *self, const char *str, long len);
void out_data (struct mtproto_connection *self, const void *data, long len);
static inline void out_string (struct mtproto_connection *self, const char *str) {
out_cstring (self, str, strlen (str));
}
static inline void out_bignum (struct mtproto_connection *self, BIGNUM *n) {
int l = serialize_bignum (n, (char *)self->packet_ptr, (PACKET_BUFFER_SIZE - (self->packet_ptr - self->packet_buffer)) * 4);
assert (l > 0);
self->packet_ptr += l >> 2;
}
void fetch_pts (struct mtproto_connection *self);
void fetch_qts (struct mtproto_connection *self);
void fetch_date (struct mtproto_connection *self);
void fetch_seq (struct mtproto_connection *self);
static inline int prefetch_strlen (struct mtproto_connection *self) {
if (self->in_ptr >= self->in_end) {
return -1;
}
unsigned l = *self->in_ptr;
if ((l & 0xff) < 0xfe) {
l &= 0xff;
return (self->in_end >= self->in_ptr + (l >> 2) + 1) ? (int)l : -1;
} else if ((l & 0xff) == 0xfe) {
l >>= 8;
return (l >= 254 && self->in_end >= self->in_ptr + ((l + 7) >> 2)) ? (int)l : -1;
} else {
return -1;
}
}
extern int verbosity;
static inline char *fetch_str (struct mtproto_connection *self, int len) {
assert (len >= 0);
if (verbosity > 6) {
debug ("fetch_string: len = %d\n", len);
}
if (len < 254) {
char *str = (char *) self->in_ptr + 1;
self->in_ptr += 1 + (len >> 2);
return str;
} else {
char *str = (char *) self->in_ptr + 4;
self->in_ptr += (len + 7) >> 2;
return str;
}
}
static inline char *fetch_str_dup (struct mtproto_connection *self) {
int l = prefetch_strlen (self);
assert (l >= 0);
int i;
char *s = fetch_str (self, l);
for (i = 0; i < l; i++) {
if (!s[i]) { break; }
}
char *r = talloc (i + 1);
memcpy (r, s, i);
r[i] = 0;
return r;
}
static inline int fetch_update_str (struct mtproto_connection *self, char **s) {
if (!*s) {
*s = fetch_str_dup (self);
return 1;
}
int l = prefetch_strlen (self);
char *r = fetch_str (self, l);
if (memcmp (*s, r, l) || (*s)[l]) {
tfree_str (*s);
*s = talloc (l + 1);
memcpy (*s, r, l);
(*s)[l] = 0;
return 1;
}
return 0;
}
static inline int fetch_update_int (struct mtproto_connection *self, int *value) {
if (*value == *self->in_ptr) {
self->in_ptr ++;
return 0;
} else {
*value = *(self->in_ptr ++);
return 1;
}
}
static inline int fetch_update_long (struct mtproto_connection *self, long long *value) {
if (*value == *(long long *)self->in_ptr) {
self->in_ptr += 2;
return 0;
} else {
*value = *(long long *)(self->in_ptr);
self->in_ptr += 2;
return 1;
}
}
static inline int set_update_int (int *value, int new_value) {
if (*value == new_value) {
return 0;
} else {
*value = new_value;
return 1;
}
}
static inline void fetch_skip (struct mtproto_connection *self, int n) {
self->in_ptr += n;
assert (self->in_ptr <= self->in_end);
}
static inline void fetch_skip_str (struct mtproto_connection *self) {
int l = prefetch_strlen (self);
assert (l >= 0);
fetch_str (self, l);
}
static inline long have_prefetch_ints (struct mtproto_connection *self) {
return self->in_end - self->in_ptr;
}
int fetch_bignum (struct mtproto_connection *self, BIGNUM *x);
static inline int fetch_int (struct mtproto_connection *self) {
assert (self->in_ptr + 1 <= self->in_end);
if (verbosity > 6) {
debug ("fetch_int: 0x%08x (%d)\n", *self->in_ptr, *self->in_ptr);
}
return *(self->in_ptr ++);
}
static inline int fetch_bool (struct mtproto_connection *self) {
if (verbosity > 6) {
debug ("fetch_bool: 0x%08x (%d)\n", *self->in_ptr, *self->in_ptr);
}
assert (self->in_ptr + 1 <= self->in_end);
assert (*(self->in_ptr) == (int)CODE_bool_true || *(self->in_ptr) == (int)CODE_bool_false);
return *(self->in_ptr ++) == (int)CODE_bool_true;
}
static inline int prefetch_int (struct mtproto_connection *self) {
assert (self->in_ptr < self->in_end);
return *(self->in_ptr);
}
static inline void prefetch_data (struct mtproto_connection *self, void *data, int size) {
assert (self->in_ptr + (size >> 2) <= self->in_end);
memcpy (data, self->in_ptr, size);
}
static inline void fetch_data (struct mtproto_connection *self, void *data, int size) {
assert (self->in_ptr + (size >> 2) <= self->in_end);
memcpy (data, self->in_ptr, size);
assert (!(size & 3));
self->in_ptr += (size >> 2);
}
static inline long long fetch_long (struct mtproto_connection *self) {
assert (self->in_ptr + 2 <= self->in_end);
long long r = *(long long *)self->in_ptr;
self->in_ptr += 2;
return r;
}
static inline double fetch_double (struct mtproto_connection *self) {
assert (self->in_ptr + 2 <= self->in_end);
double r = *(double *)self->in_ptr;
self->in_ptr += 2;
return r;
}
static inline void fetch_ints (struct mtproto_connection *self, void *data, int count) {
assert (self->in_ptr + count <= self->in_end);
memcpy (data, self->in_ptr, 4 * count);
self->in_ptr += count;
}
int get_random_bytes (unsigned char *buf, int n);
int pad_rsa_encrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *E);
int pad_rsa_decrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *D);
void init_aes_unauth (struct mtproto_connection *self, const char server_nonce[16], const char hidden_client_nonce[32], int encrypt);
void init_aes_auth (struct mtproto_connection *self, char auth_key[192], char msg_key[16], int encrypt);
int pad_aes_encrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size);
int pad_aes_decrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size);
static inline void hexdump_in (struct mtproto_connection *self) {
hexdump (self->in_ptr, self->in_end);
}
static inline void hexdump_out (struct mtproto_connection *self) {
hexdump (self->packet_buffer, self->packet_ptr);
}
#ifdef __MACH__
#define CLOCK_REALTIME 0
#define CLOCK_MONOTONIC 1
#endif
void my_clock_gettime (int clock_id, struct timespec *T);
void mtproto_close_foreign (struct telegram *instance);
void mtproto_free_closed (struct telegram *tg, int force);
#endif

View file

@ -1,357 +0,0 @@
#include "mtproto-client.h"
/*
* struct mtproto_connection-Common.c
*/
int verbosity;
#ifndef __MTPROTO_COMMON_C__
#define __MTPROTO_COMMON_C__
int get_random_bytes (unsigned char *buf, int n) {
int r = 0, h = open ("/dev/random", O_RDONLY | O_NONBLOCK);
if (h >= 0) {
r = read (h, buf, n);
if (r > 0) {
if (verbosity >= 3) {
debug ( "added %d bytes of real entropy to secure random numbers seed\n", r);
}
} else {
r = 0;
}
close (h);
}
if (r < n) {
h = open ("/dev/urandom", O_RDONLY);
if (h < 0) {
return r;
}
int s = read (h, buf + r, n - r);
close (h);
if (s > 0) {
r += s;
}
}
if (r >= (int) sizeof (long)) {
*(long *)buf ^= lrand48 ();
srand48 (*(long *)buf);
}
return r;
}
void my_clock_gettime (int clock_id UU, struct timespec *T) {
#ifdef __MACH__
// We are ignoring MONOTONIC and hope time doesn't go back to often
clock_serv_t cclock;
mach_timespec_t mts;
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock);
T->tv_sec = mts.tv_sec;
T->tv_nsec = mts.tv_nsec;
#else
assert (clock_gettime(clock_id, T) >= 0);
#endif
}
/* RDTSC */
#if defined(__i386__)
#define HAVE_RDTSC
static __inline__ unsigned long long rdtsc (void) {
unsigned long long int x;
__asm__ volatile ("rdtsc" : "=A" (x));
return x;
}
#elif defined(__x86_64__)
#define HAVE_RDTSC
static __inline__ unsigned long long rdtsc (void) {
unsigned hi, lo;
__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
return ((unsigned long long) lo) | (((unsigned long long) hi) << 32);
}
#endif
void prng_seed (struct mtproto_connection *self, const char *password_filename, int password_length) {
struct timespec T;
my_clock_gettime (CLOCK_REALTIME, &T);
RAND_add (&T, sizeof (T), 4.0);
#ifdef HAVE_RDTSC
unsigned long long r = rdtsc ();
RAND_add (&r, 8, 4.0);
#endif
unsigned short p = getpid ();
RAND_add (&p, sizeof (p), 0.0);
p = getppid ();
RAND_add (&p, sizeof (p), 0.0);
unsigned char rb[32];
int s = get_random_bytes (rb, 32);
if (s > 0) {
RAND_add (rb, s, s);
}
memset (rb, 0, sizeof (rb));
if (password_filename && password_length > 0) {
int fd = open (password_filename, O_RDONLY);
if (fd < 0) {
debug ( "Warning: fail to open password file - \"%s\", %m.\n", password_filename);
} else {
unsigned char *a = talloc0 (password_length);
int l = read (fd, a, password_length);
if (l < 0) {
debug ( "Warning: fail to read password file - \"%s\", %m.\n", password_filename);
} else {
debug ( "read %d bytes from password file.\n", l);
RAND_add (a, l, l);
}
close (fd);
tfree_secure (a, password_length);
}
}
self->BN_ctx = BN_CTX_new ();
ensure_ptr (self->BN_ctx);
}
int serialize_bignum (BIGNUM *b, char *buffer, int maxlen) {
int itslen = BN_num_bytes (b);
int reqlen;
if (itslen < 254) {
reqlen = itslen + 1;
} else {
reqlen = itslen + 4;
}
int newlen = (reqlen + 3) & -4;
int pad = newlen - reqlen;
reqlen = newlen;
if (reqlen > maxlen) {
return -reqlen;
}
if (itslen < 254) {
*buffer++ = itslen;
} else {
*(int *)buffer = (itslen << 8) + 0xfe;
buffer += 4;
}
int l = BN_bn2bin (b, (unsigned char *)buffer);
assert (l == itslen);
buffer += l;
while (pad --> 0) {
*buffer++ = 0;
}
return reqlen;
}
long long compute_rsa_key_fingerprint (RSA *key) {
static char tempbuff[4096];
static unsigned char sha[20];
assert (key->n && key->e);
int l1 = serialize_bignum (key->n, tempbuff, 4096);
assert (l1 > 0);
int l2 = serialize_bignum (key->e, tempbuff + l1, 4096 - l1);
assert (l2 > 0 && l1 + l2 <= 4096);
SHA1 ((unsigned char *)tempbuff, l1 + l2, sha);
return *(long long *)(sha + 12);
}
void out_cstring (struct mtproto_connection *self, const char *str, long len) {
assert (len >= 0 && len < (1 << 24));
assert ((char *) self->packet_ptr + len + 8 < (char *) (self->packet_buffer + PACKET_BUFFER_SIZE));
char *dest = (char *) self->packet_ptr;
if (len < 254) {
*dest++ = len;
} else {
*self->packet_ptr = (len << 8) + 0xfe;
dest += 4;
}
memcpy (dest, str, len);
dest += len;
while ((long) dest & 3) {
*dest++ = 0;
}
self->packet_ptr = (int *) dest;
}
void out_cstring_careful (struct mtproto_connection *self, const char *str, long len) {
assert (len >= 0 && len < (1 << 24));
assert ((char *) self->packet_ptr + len + 8 < (char *) (self->packet_buffer + PACKET_BUFFER_SIZE));
char *dest = (char *) self->packet_ptr;
if (len < 254) {
dest++;
if (dest != str) {
memmove (dest, str, len);
}
dest[-1] = len;
} else {
dest += 4;
if (dest != str) {
memmove (dest, str, len);
}
*self->packet_ptr = (len << 8) + 0xfe;
}
dest += len;
while ((long) dest & 3) {
*dest++ = 0;
}
self->packet_ptr = (int *) dest;
}
void out_data (struct mtproto_connection *self, const void *data, long len) {
assert (len >= 0 && len < (1 << 24) && !(len & 3));
assert ((char *) self->packet_ptr + len + 8 < (char *) (self->packet_buffer + PACKET_BUFFER_SIZE));
memcpy (self->packet_ptr, data, len);
self->packet_ptr += len >> 2;
}
int fetch_bignum (struct mtproto_connection *self, BIGNUM *x) {
int l = prefetch_strlen (self);
if (l < 0) {
return l;
}
char *str = fetch_str (self, l);
assert (BN_bin2bn ((unsigned char *) str, l, x) == x);
return l;
}
int pad_rsa_encrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *E) {
int pad = (255000 - from_len - 32) % 255 + 32;
int chunks = (from_len + pad) / 255;
int bits = BN_num_bits (N);
assert (bits >= 2041 && bits <= 2048);
assert (from_len > 0 && from_len <= 2550);
assert (size >= chunks * 256);
assert (RAND_pseudo_bytes ((unsigned char *) from + from_len, pad) >= 0);
int i;
BIGNUM x, y;
BN_init (&x);
BN_init (&y);
self->rsa_encrypted_chunks += chunks;
for (i = 0; i < chunks; i++) {
BN_bin2bn ((unsigned char *) from, 255, &x);
assert (BN_mod_exp (&y, &x, E, N, self->BN_ctx) == 1);
unsigned l = 256 - BN_num_bytes (&y);
assert (l <= 256);
memset (to, 0, l);
BN_bn2bin (&y, (unsigned char *) to + l);
to += 256;
}
BN_free (&x);
BN_free (&y);
return chunks * 256;
}
int pad_rsa_decrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *D) {
if (from_len < 0 || from_len > 0x1000 || (from_len & 0xff)) {
return -1;
}
int chunks = (from_len >> 8);
int bits = BN_num_bits (N);
assert (bits >= 2041 && bits <= 2048);
assert (size >= chunks * 255);
int i;
BIGNUM x, y;
BN_init (&x);
BN_init (&y);
for (i = 0; i < chunks; i++) {
++self->rsa_decrypted_chunks;
BN_bin2bn ((unsigned char *) from, 256, &x);
assert (BN_mod_exp (&y, &x, D, N, self->BN_ctx) == 1);
int l = BN_num_bytes (&y);
if (l > 255) {
BN_free (&x);
BN_free (&y);
return -1;
}
assert (l >= 0 && l <= 255);
memset (to, 0, 255 - l);
BN_bn2bin (&y, (unsigned char *) to + 255 - l);
to += 255;
}
BN_free (&x);
BN_free (&y);
return chunks * 255;
}
void init_aes_unauth (struct mtproto_connection *self, const char server_nonce[16], const char hidden_client_nonce[32], int encrypt) {
static unsigned char buffer[64], hash[20];
memcpy (buffer, hidden_client_nonce, 32);
memcpy (buffer + 32, server_nonce, 16);
SHA1 (buffer, 48, self->aes_key_raw);
memcpy (buffer + 32, hidden_client_nonce, 32);
SHA1 (buffer, 64, self->aes_iv + 8);
memcpy (buffer, server_nonce, 16);
memcpy (buffer + 16, hidden_client_nonce, 32);
SHA1 (buffer, 48, hash);
memcpy (self->aes_key_raw + 20, hash, 12);
memcpy (self->aes_iv, hash + 12, 8);
memcpy (self->aes_iv + 28, hidden_client_nonce, 4);
if (encrypt == AES_ENCRYPT) {
AES_set_encrypt_key (self->aes_key_raw, 32*8, &self->aes_key);
} else {
AES_set_decrypt_key (self->aes_key_raw, 32*8, &self->aes_key);
}
memset (self->aes_key_raw, 0, sizeof (self->aes_key_raw));
}
void init_aes_auth (struct mtproto_connection *self, char auth_key[192], char msg_key[16], int encrypt) {
static unsigned char buffer[48], hash[20];
// sha1_a = SHA1 (msg_key + substr (auth_key, 0, 32));
// sha1_b = SHA1 (substr (auth_key, 32, 16) + msg_key + substr (auth_key, 48, 16));
// sha1_с = SHA1 (substr (auth_key, 64, 32) + msg_key);
// sha1_d = SHA1 (msg_key + substr (auth_key, 96, 32));
// aes_key = substr (sha1_a, 0, 8) + substr (sha1_b, 8, 12) + substr (sha1_c, 4, 12);
// aes_iv = substr (sha1_a, 8, 12) + substr (sha1_b, 0, 8) + substr (sha1_c, 16, 4) + substr (sha1_d, 0, 8);
memcpy (buffer, msg_key, 16);
memcpy (buffer + 16, auth_key, 32);
SHA1 (buffer, 48, hash);
memcpy (self->aes_key_raw, hash, 8);
memcpy (self->aes_iv, hash + 8, 12);
memcpy (buffer, auth_key + 32, 16);
memcpy (buffer + 16, msg_key, 16);
memcpy (buffer + 32, auth_key + 48, 16);
SHA1 (buffer, 48, hash);
memcpy (self->aes_key_raw + 8, hash + 8, 12);
memcpy (self->aes_iv + 12, hash, 8);
memcpy (buffer, auth_key + 64, 32);
memcpy (buffer + 32, msg_key, 16);
SHA1 (buffer, 48, hash);
memcpy (self->aes_key_raw + 20, hash + 4, 12);
memcpy (self->aes_iv + 20, hash + 16, 4);
memcpy (buffer, msg_key, 16);
memcpy (buffer + 16, auth_key + 96, 32);
SHA1 (buffer, 48, hash);
memcpy (self->aes_iv + 24, hash, 8);
if (encrypt == AES_ENCRYPT) {
AES_set_encrypt_key (self->aes_key_raw, 32*8, &self->aes_key);
} else {
AES_set_decrypt_key (self->aes_key_raw, 32*8, &self->aes_key);
}
memset (self->aes_key_raw, 0, sizeof (self->aes_key_raw));
}
int pad_aes_encrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size) {
int padded_size = (from_len + 15) & -16;
assert (from_len > 0 && padded_size <= size);
if (from_len < padded_size) {
assert (RAND_pseudo_bytes ((unsigned char *) from + from_len, padded_size - from_len) >= 0);
}
AES_ige_encrypt ((unsigned char *) from, (unsigned char *) to, padded_size, &self->aes_key, self->aes_iv, AES_ENCRYPT);
return padded_size;
}
int pad_aes_decrypt (struct mtproto_connection *self, char *from, int from_len, char *to, int size) {
if (from_len <= 0 || from_len > size || (from_len & 15)) {
return -1;
}
AES_ige_encrypt ((unsigned char *) from, (unsigned char *) to, from_len, &self->aes_key, self->aes_iv, AES_DECRYPT);
return from_len;
}
#endif

549
net.c
View file

@ -1,549 +0,0 @@
/*
This file is part of telegram-client.
Telegram-client 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.
Telegram-client 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 telegram-client. If not, see <http://www.gnu.org/licenses/>.
Copyright Vitaly Valtman 2013
*/
#define _GNU_SOURCE
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <poll.h>
#include <openssl/rand.h>
#include <arpa/inet.h>
#include "net.h"
#include "include.h"
#include "mtproto-client.h"
#include "tree.h"
#ifndef POLLRDHUP
#define POLLRDHUP 0
#endif
#define long_cmp(a,b) ((a) > (b) ? 1 : (a) == (b) ? 0 : -1)
DEFINE_TREE(long,long long,long_cmp,0)
double get_utime (int clock_id);
int verbosity;
extern struct connection_methods auth_methods;
//extern FILE *log_net_f;
FILE *log_net_f = 0;
void fail_connection (struct connection *c);
/*
*
*/
#define PING_TIMEOUT 10
void start_ping_timer (struct connection *c);
int ping_alarm (struct connection *c) {
assert (c->state == conn_ready || c->state == conn_connecting);
if (get_double_time () - c->last_receive_time > 20 * PING_TIMEOUT) {
warning ( "fail connection: reason: ping timeout\n");
c->state = conn_failed;
fail_connection (c);
} else if (get_double_time () - c->last_receive_time > 5 * PING_TIMEOUT && c->state == conn_ready) {
debug ("sending PING...\n");
int x[3];
x[0] = CODE_ping;
*(long long *)(x + 1) = lrand48 () * (1ll << 32) + lrand48 ();
encrypt_send_message (c->mtconnection, x, 3, 0);
start_ping_timer (c);
} else {
start_ping_timer (c);
}
return 0;
}
void stop_ping_timer (struct connection *c) {
if (c->ev.self) {
remove_event_timer (c->instance, &c->ev);
} else {
warning ("trying to stop non-existing ping timer fd: #%d\n", c->fd);
}
}
void start_ping_timer (struct connection *c) {
c->ev.timeout = get_double_time () + PING_TIMEOUT;
c->ev.alarm = (void *)ping_alarm;
c->ev.self = c;
insert_event_timer (c->instance, &c->ev);
}
void restart_connection (struct connection *c);
int fail_alarm (void *ev) {
((struct connection *)ev)->in_fail_timer = 0;
restart_connection (ev);
return 0;
}
void start_fail_timer (struct connection *c) {
if (c->in_fail_timer) { return; }
c->in_fail_timer = 1;
c->ev.timeout = get_double_time () + 10;
c->ev.alarm = (void *)fail_alarm;
c->ev.self = c;
insert_event_timer (c->instance, &c->ev);
}
struct connection_buffer *new_connection_buffer (int size) {
struct connection_buffer *b = talloc0 (sizeof (*b));
b->start = talloc (size);
b->end = b->start + size;
b->rptr = b->wptr = b->start;
return b;
}
void delete_connection_buffer (struct connection_buffer *b) {
tfree (b->start, b->end - b->start);
tfree (b, sizeof (*b));
}
int write_out (struct connection *c, const void *_data, int len) {
const unsigned char *data = _data;
if (!len) { return 0; }
assert (len > 0);
int x = 0;
if (!c->out_head) {
struct connection_buffer *b = new_connection_buffer (1 << 20);
c->out_head = c->out_tail = b;
}
while (len) {
if (c->out_tail->end - c->out_tail->wptr >= len) {
memcpy (c->out_tail->wptr, data, len);
c->out_tail->wptr += len;
c->out_bytes += len;
return x + len;
} else {
int y = c->out_tail->end - c->out_tail->wptr;
assert (y < len);
memcpy (c->out_tail->wptr, data, y);
x += y;
len -= y;
data += y;
struct connection_buffer *b = new_connection_buffer (1 << 20);
c->out_tail->next = b;
b->next = 0;
c->out_tail = b;
c->out_bytes += y;
}
}
return x;
}
int read_in (struct connection *c, void *_data, int len) {
unsigned char *data = _data;
if (!len) { return 0; }
assert (len > 0);
if (len > c->in_bytes) {
len = c->in_bytes;
}
int x = 0;
while (len) {
int y = c->in_head->wptr - c->in_head->rptr;
if (y > len) {
memcpy (data, c->in_head->rptr, len);
c->in_head->rptr += len;
c->in_bytes -= len;
return x + len;
} else {
memcpy (data, c->in_head->rptr, y);
c->in_bytes -= y;
x += y;
data += y;
len -= y;
void *old = c->in_head;
c->in_head = c->in_head->next;
if (!c->in_head) {
c->in_tail = 0;
}
delete_connection_buffer (old);
}
}
return x;
}
int read_in_lookup (struct connection *c, void *_data, int len) {
unsigned char *data = _data;
if (!len || !c->in_bytes) { return 0; }
assert (len > 0);
if (len > c->in_bytes) {
len = c->in_bytes;
}
int x = 0;
struct connection_buffer *b = c->in_head;
while (len) {
int y = b->wptr - b->rptr;
if (y >= len) {
memcpy (data, b->rptr, len);
return x + len;
} else {
memcpy (data, b->rptr, y);
x += y;
data += y;
len -= y;
b = b->next;
}
}
return x;
}
void flush_out (struct connection *c UU) {
}
#define MAX_CONNECTIONS 100
struct connection *Connections[MAX_CONNECTIONS];
int max_connection_fd;
void rotate_port (struct connection *c) {
switch (c->port) {
case 443:
c->port = 80;
break;
case 80:
c->port = 25;
break;
case 25:
c->port = 443;
break;
}
}
void restart_connection (struct connection *c) {
if (c->last_connect_time == time (0)) {
start_fail_timer (c);
return;
}
c->last_connect_time = time (0);
int fd = socket (AF_INET, SOCK_STREAM, 0);
if (fd == -1) {
debug ("Can not create socket: %m\n");
exit (1);
}
assert (fd >= 0 && fd < MAX_CONNECTIONS);
if (fd > max_connection_fd) {
max_connection_fd = fd;
}
int flags = -1;
setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof (flags));
setsockopt (fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof (flags));
setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof (flags));
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (c->port);
addr.sin_addr.s_addr = inet_addr (c->ip);
fcntl (fd, F_SETFL, O_NONBLOCK);
if (connect (fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) {
if (errno != EINPROGRESS) {
debug ( "Can not connect to %s:%d %m\n", c->ip, c->port);
start_fail_timer (c);
close (fd);
return;
}
}
c->fd = fd;
c->state = conn_connecting;
c->last_receive_time = get_double_time ();
start_ping_timer (c);
Connections[fd] = c;
char byte = 0xef;
assert (write_out (c, &byte, 1) == 1);
flush_out (c);
}
void fail_connection (struct connection *c) {
warning ("Lost connection to server... %s:%d\n", c->ip, c->port);
telegram_change_state(c->mtconnection->instance, STATE_ERROR, "Lost connection to server\n");
}
extern FILE *log_net_f;
int try_write (struct connection *c) {
debug ( "try write: fd = %d\n", c->fd);
int x = 0;
while (c->out_head) {
int r = write (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr);
// Log all written packages
if (r > 0 && log_net_f) {
// fprintf (log_net_f, "%.02lf %d OUT %s:%d", get_utime (CLOCK_REALTIME), r, c->ip, c->port);
int i;
for (i = 0; i < r; i++) {
// fprintf (log_net_f, " %02x", *(unsigned char *)(c->out_head->rptr + i));
}
fprintf (log_net_f, "\n");
fflush (log_net_f);
}
if (r >= 0) {
x += r;
c->out_head->rptr += r;
if (c->out_head->rptr != c->out_head->wptr) {
break;
}
struct connection_buffer *b = c->out_head;
c->out_head = b->next;
if (!c->out_head) {
c->out_tail = 0;
}
delete_connection_buffer (b);
} else {
if (errno != EAGAIN && errno != EWOULDBLOCK) {
debug ("fail_connection: write_error %m\n");
fail_connection (c);
return 0;
} else {
break;
}
}
}
debug ( "Sent %d bytes to %d\n", x, c->fd);
c->out_bytes -= x;
return x;
}
void hexdump_buf (struct connection_buffer *b) {
// TODO: figure out how to log hexdumps to purple log
int pos = 0;
int rem = 8;
while (b) {
unsigned char *c = b->rptr;
while (c != b->wptr) {
if (rem == 8) {
//if (pos) { printf ("\n"); }
//printf ("%04d", pos);
}
//printf (" %02x", (int)*c);
rem --;
pos ++;
if (!rem) {
rem = 8;
}
c ++;
}
b = b->next;
}
//printf ("\n");
}
void try_rpc_read (struct connection *c) {
assert (c->in_head);
if (verbosity >= 3) {
hexdump_buf (c->in_head);
}
while (1) {
if (c->in_bytes < 1) { return; }
unsigned len = 0;
unsigned t = 0;
assert (read_in_lookup (c, &len, 1) == 1);
if (len >= 1 && len <= 0x7e) {
if (c->in_bytes < (int)(1 + 4 * len)) { return; }
} else {
if (c->in_bytes < 4) { return; }
assert (read_in_lookup (c, &len, 4) == 4);
len = (len >> 8);
if (c->in_bytes < (int)(4 + 4 * len)) { return; }
len = 0x7f;
}
if (len >= 1 && len <= 0x7e) {
assert (read_in (c, &t, 1) == 1);
assert (t == len);
assert (len >= 1);
} else {
assert (len == 0x7f);
assert (read_in (c, &len, 4) == 4);
len = (len >> 8);
assert (len >= 1);
}
len *= 4;
int op;
assert (read_in_lookup (c, &op, 4) == 4);
c->methods->execute (c, op, len);
}
}
void try_read (struct connection *c) {
debug ( "try read: fd = %d\n", c->fd);
if (!c->in_tail) {
c->in_head = c->in_tail = new_connection_buffer (1 << 20);
}
int x = 0;
while (1) {
int r = read (c->fd, c->in_tail->wptr, c->in_tail->end - c->in_tail->wptr);
if (r > 0 && log_net_f) {
fprintf (log_net_f, "%.02lf %d IN %s:%d", get_utime (CLOCK_REALTIME), r, c->ip, c->port);
int i;
for (i = 0; i < r; i++) {
fprintf (log_net_f, " %02x", *(unsigned char *)(c->in_tail->wptr + i));
}
fprintf (log_net_f, "\n");
fflush (log_net_f);
}
if (r > 0) {
c->last_receive_time = get_double_time ();
stop_ping_timer (c);
start_ping_timer (c);
}
if (r >= 0) {
c->in_tail->wptr += r;
x += r;
if (c->in_tail->wptr != c->in_tail->end) {
break;
}
struct connection_buffer *b = new_connection_buffer (1 << 20);
c->in_tail->next = b;
c->in_tail = b;
} else {
if (errno != EAGAIN && errno != EWOULDBLOCK) {
debug ("fail_connection: read_error %m\n");
fail_connection (c);
return;
} else {
break;
}
}
}
debug ( "Received %d bytes from fd=#%d and DC %d(%s, %d)\n", x,
c->fd, c->session->dc->id, c->session->dc->ip, c->session->dc->port);
c->in_bytes += x;
if (x) {
try_rpc_read (c);
}
}
int send_all_acks (struct session *S) {
info ("send_all_acks(dc=%d)\n", S->dc->id);
if (!S->c) {
warning ("WARNING: cannot send acks, session has no active connection");
return -1;
}
struct mtproto_connection *mt = S->c->mtconnection;
clear_packet (mt);
out_int (mt, CODE_msgs_ack);
out_int (mt, CODE_vector);
out_int (mt, tree_count_long (S->ack_tree));
while (S->ack_tree) {
long long x = tree_get_min_long (S->ack_tree);
out_long (mt, x);
S->ack_tree = tree_delete_long (S->ack_tree, x);
}
encrypt_send_message (mt, mt->packet_buffer, mt->packet_ptr - mt->packet_buffer, 0);
return 0;
}
void insert_msg_id (struct session *S, long long id) {
if (!S->ack_tree) {
debug ("Creating ack_tree pointing to session %p\n");
S->ev.alarm = (void *)send_all_acks;
S->ev.self = (void *)S;
S->ev.timeout = get_double_time () + ACK_TIMEOUT;
insert_event_timer (S->c->instance, &S->ev);
}
if (!tree_lookup_long (S->ack_tree, id)) {
S->ack_tree = tree_insert_long (S->ack_tree, id, lrand48 ());
}
}
struct dc *alloc_dc (struct dc* DC_list[], int id, char *ip, int port UU) {
assert (!DC_list[id]);
struct dc *DC = talloc0 (sizeof (*DC));
DC->id = id;
DC->ip = ip;
DC->port = port;
DC_list[id] = DC;
return DC;
}
/**
* Wrap an existing socket file descriptor and make it usable as a connection,
*/
struct connection *fd_create_connection (struct dc *DC, int fd,
struct telegram *instance, struct connection_methods *methods,
struct mtproto_connection *mtp) {
// create a connection
struct connection *c = talloc0 (sizeof (*c));
c->fd = fd;
c->ip = tstrdup (DC->ip);
c->flags = 0;
c->state = conn_ready;
c->port = DC->port;
c->methods = methods;
c->instance = instance;
c->last_receive_time = get_double_time ();
debug ( "connect to %s:%d successful\n", DC->ip, DC->port);
if (!DC->sessions[0]) {
struct session *S = talloc0 (sizeof (*S));
assert (RAND_pseudo_bytes ((unsigned char *) &S->session_id, 8) >= 0);
S->dc = DC;
S->c = c;
DC->sessions[0] = S;
}
if (!DC->sessions[0]->c) {
DC->sessions[0]->c = c;
}
// add backreference to session
c->session = DC->sessions[0];
// add backreference to used mtproto-connection
c->mtconnection = mtp;
return c;
}
/**
* Close the connection by freeing all attached buffers and setting
* the state to conn_stopped, but does NOT close the attached file descriptor
*/
void fd_close_connection(struct connection *c) {
struct connection_buffer *b = c->out_head;
while (b) {
struct connection_buffer *d = b;
b = b->next;
delete_connection_buffer (d);
}
while (b) {
struct connection_buffer *d = b;
b = b->next;
delete_connection_buffer (d);
}
c->out_head = c->out_tail = c->in_head = c->in_tail = 0;
c->state = conn_stopped;
c->out_bytes = c->in_bytes = 0;
tfree(c, sizeof(struct connection));
}

163
net.h
View file

@ -1,163 +0,0 @@
/*
This file is part of telegram-client.
struct telegram-client 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.
struct telegram-client 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 telegram-client. If not, see <http://www.gnu.org/licenses/>.
Copyright Vitaly Valtman 2013
*/
#ifndef __NET_H__
#define __NET_H__
#pragma once
#include <poll.h>
struct dc;
#include "mtproto-client.h"
#include "telegram.h"
#include "queries.h"
#define TG_SERVER "149.154.167.50"
#define TG_DC_NUM 2
#define TG_SERVER_TEST "149.154.167.40"
#define TG_TEST_DC_NUM 2
#define TG_APP_HASH "99428c722d0ed59b9cd844e4577cb4bb"
#define TG_APP_ID 16154
#define TG_PORT 443
#define ACK_TIMEOUT 1
#define MAX_DC_ID 10
// typedef struct mtproto_connection not available right now
struct mtproto_connection;
struct connection;
struct connection_methods {
int (*ready) (struct connection *c);
int (*close) (struct connection *c);
int (*execute) (struct connection *c, int op, int len);
};
#define MAX_DC_SESSIONS 3
struct session {
struct dc *dc;
long long session_id;
int seq_no;
struct connection *c;
struct tree_long *ack_tree;
struct event_timer ev;
};
struct dc {
int id;
int port;
int flags;
char *ip;
char *user;
struct session *sessions[MAX_DC_SESSIONS];
char auth_key[256];
long long auth_key_id;
long long server_salt;
int server_time_delta;
double server_time_udelta;
int has_auth;
};
#define DC_SERIALIZED_MAGIC 0x64582faa
#define DC_SERIALIZED_MAGIC_V2 0x94032abb
#define STATE_FILE_MAGIC 0x84217a0d
#define SECRET_CHAT_FILE_MAGIC 0xa9840add
struct dc_serialized {
int magic;
int port;
char ip[64];
char user[64];
char auth_key[256];
long long auth_key_id, server_salt;
int authorized;
};
struct connection_buffer {
unsigned char *start;
unsigned char *end;
unsigned char *rptr;
unsigned char *wptr;
struct connection_buffer *next;
};
enum conn_state {
conn_none,
conn_connecting,
conn_ready,
conn_failed,
conn_stopped
};
struct connection {
int fd;
char *ip;
int port;
int flags;
enum conn_state state;
int ipv6[4];
struct connection_buffer *in_head;
struct connection_buffer *in_tail;
struct connection_buffer *out_head;
struct connection_buffer *out_tail;
int in_bytes;
int out_bytes;
int packet_num;
int out_packet_num;
int last_connect_time;
int in_fail_timer;
struct connection_methods *methods;
struct session *session;
void *extra;
struct event_timer ev;
double last_receive_time;
struct telegram *instance;
struct mtproto_connection *mtconnection;
};
extern struct connection *Connections[];
int write_out (struct connection *c, const void *data, int len);
void flush_out (struct connection *c);
int read_in (struct connection *c, void *data, int len);
void create_all_outbound_connections (void);
void dc_create_session (struct dc *DC);
void insert_msg_id (struct session *S, long long id);
struct dc *alloc_dc (struct dc* DC_list[], int id, char *ip, int port);
#define GET_DC(c) (c->session->dc)
// export read and write methods to redirect network control
void try_read (struct connection *c);
void try_rpc_read (struct connection *c);
int try_write (struct connection *c);
struct connection *fd_create_connection (struct dc *DC, int fd, struct telegram *instance,
struct connection_methods *methods, struct mtproto_connection *mtp);
void fd_close_connection(struct connection *c);
void start_ping_timer (struct connection *c);
void stop_ping_timer (struct connection *c);
int send_all_acks (struct session *S);
#endif

View file

@ -1,105 +0,0 @@
/*
This file is part of telegram-client.
Telegram-client 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.
Telegram-client 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 telegram-client. If not, see <http://www.gnu.org/licenses/>.
Copyright Vitaly Valtman 2013
*/
// Just sample jpg file 90x90
int thumb_file_size = (82 * 6 - 2) * 4;
int thumb_file [] = {
0xe0ffd8ff, 0x464a1000, 0x01004649, 0x64000101, 0x00006400, 0xa002e2ff,
0x5f434349, 0x464f5250, 0x00454c49, 0x00000101, 0x636c9002, 0x3004736d,
0x6e6d0000, 0x47527274, 0x59582042, 0xdd07205a, 0x04000b00, 0x1b001600,
0x63612400, 0x50417073, 0x00004c50, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x0100d6f6, 0x00000000, 0x636c2dd3,
0x0000736d, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x65640b00, 0x00006373, 0x00000801, 0x70633800, 0x00007472, 0x00004001,
0x74774e00, 0x00007470, 0x00009001, 0x68631400, 0x00006461, 0x0000a401,
0x58722c00, 0x00005a59, 0x0000d001, 0x58621400, 0x00005a59, 0x0000e401,
0x58671400, 0x00005a59, 0x0000f801, 0x54721400, 0x00004352, 0x00000c02,
0x54672000, 0x00004352, 0x00002c02, 0x54622000, 0x00004352, 0x00004c02,
0x68632000, 0x00006d72, 0x00006c02, 0x6c6d2400, 0x00006375, 0x00000000,
0x00000100, 0x6e650c00, 0x00005355, 0x00001c00, 0x73001c00, 0x47005200,
0x20004200, 0x75006200, 0x6c006900, 0x2d007400, 0x6e006900, 0x6c6d0000,
0x00006375, 0x00000000, 0x00000100, 0x6e650c00, 0x00005355, 0x00003200,
0x4e001c00, 0x20006f00, 0x6f006300, 0x79007000, 0x69007200, 0x68006700,
0x2c007400, 0x75002000, 0x65007300, 0x66002000, 0x65007200, 0x6c006500,
0x00007900, 0x59580000, 0x0000205a, 0x00000000, 0x0100d6f6, 0x00000000,
0x66732dd3, 0x00003233, 0x01000000, 0x00004a0c, 0xffffe305, 0x00002af3,
0x00009b07, 0xffff87fd, 0xffffa2fb, 0x0000a3fd, 0x0000d803, 0x595894c0,
0x0000205a, 0x00000000, 0x0000946f, 0x0000ee38, 0x59589003, 0x0000205a,
0x00000000, 0x00009d24, 0x0000830f, 0x5958beb6, 0x0000205a, 0x00000000,
0x0000a562, 0x000090b7, 0x6170de18, 0x00006172, 0x03000000, 0x02000000,
0x00006666, 0x0000a7f2, 0x0000590d, 0x0000d013, 0x61705b0a, 0x00006172,
0x03000000, 0x02000000, 0x00006666, 0x0000a7f2, 0x0000590d, 0x0000d013,
0x61705b0a, 0x00006172, 0x03000000, 0x02000000, 0x00006666, 0x0000a7f2,
0x0000590d, 0x0000d013, 0x68635b0a, 0x00006d72, 0x03000000, 0x00000000,
0x0000d7a3, 0x00007b54, 0x0000cd4c, 0x00009a99, 0x00006626, 0xdbff5c0f,
0x14004300, 0x0f120f0e, 0x1112140d, 0x14161712, 0x21331f18, 0x1f1c1c1f,
0x252f2d3f, 0x4e414a33, 0x4841494d, 0x765c5246, 0x6f575264, 0x66484658,
0x7a6f688c, 0x8485847d, 0x9b91634f, 0x769a808f, 0xff7f8481, 0x014300db,
0x1f171716, 0x213c1f1b, 0x547f3c21, 0x7f7f5448, 0x7f7f7f7f, 0x7f7f7f7f,
0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f,
0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x1100c0ff, 0x005a0008,
0x2201035a, 0x01110200, 0xff011103, 0x001900c4, 0x01010101, 0x00000101,
0x00000000, 0x00000000, 0x02030400, 0xc4ff0605, 0x00103600, 0x02010401,
0x06050304, 0x00000306, 0x01000000, 0x11030200, 0x05211204, 0x13514131,
0x32146122, 0x23918171, 0x72423424, 0x432515a1, 0xa2827444, 0xc4fff0b3,
0x01011400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1400c4ff,
0x00000111, 0x00000000, 0x00000000, 0x00000000, 0xdaff0000, 0x01030c00,
0x03110200, 0x003f0011, 0x404434fb, 0xbcb4875c, 0x006b38b0, 0x03dcdb12,
0xf4637f74, 0xe519f153, 0x09d7c5c7, 0x47d29160, 0x20692f18, 0xd06d786a,
0x53f7f922, 0x17b3e260, 0x2fe8668c, 0x1786a473, 0x9775efbd, 0xe917e43a,
0x1d0a1bb0, 0x114d0f82, 0x14651110, 0x35f299ed, 0xe9b09680, 0xf5a4fc2f,
0xe975bd03, 0xb506737b, 0x04444440, 0x5c444044, 0x8e8dedbd, 0xc61adc7b,
0x689c738b, 0x92a0dc01, 0x58e2b77f, 0x7bfb37d1, 0xb5b5e79d, 0xdbf968cc,
0xead3f48d, 0x38ed1313, 0xdea77c86, 0xae089963, 0xc743435a, 0x403fe4ce,
0x392ee1b9, 0xed39e718, 0xd6517e2d, 0x7fc4aa03, 0xb7ad7590, 0x77e7e6ab,
0x34bf705d, 0x7c77ca53, 0x3dea1299, 0x7fb0bcf4, 0x241fadc5, 0x95a7a816,
0x13fbe6f3, 0x3182b135, 0xd1b4b224, 0x1b0d48a2, 0xbf9d26d8, 0x82dc3640,
0x63569a2a, 0xbbd224c3, 0xb9b4714c, 0x1680aec6, 0x3d311856, 0x9b59be91,
0x09876ca6, 0x61d86564, 0x5a9f06d2, 0x36f51b0d, 0x8682e476, 0xacb1b131,
0xd1584363, 0x00456b4d, 0x22d2053b, 0x22202202, 0xf3f30222, 0xe3e513e5,
0xf1e6e1f0, 0x2380496e, 0x5fdcdb68, 0x549b3a27, 0x825e6a6c, 0x6522028b,
0xaf91ccc8, 0x341cf26b, 0x58dbc4b5, 0xf2289add, 0x0854ddbd, 0x0b9247d5,
0xf02b5c54, 0x3f917f92, 0xaf56affd, 0xe3760637, 0x05cebde0, 0xed4c76ce,
0x3cef1b63, 0x7fd8aff8, 0xa0c902ea, 0x7e730d0a, 0x435834f3, 0x26edbb76,
0xd3ec00fd, 0x76d48efa, 0xa8560f2d, 0x0e766331, 0xd319993c, 0x20243209,
0x61b7e6c8, 0x998331d0, 0x640ee802, 0x47a3d493, 0xfab99413, 0x4fd871f1,
0xe9443792, 0x627e051c, 0xd8f3051c, 0x2f28f558, 0x64b51745, 0x1b2bfee3,
0xb8783953, 0x9900fff6, 0xd8176a65, 0x5a3bf56a, 0x1b331fdb, 0x64b3572f,
0xd59a3643, 0xaf3abce1, 0x11dd20bd, 0x01111110, 0x5c141011, 0xb3e3083f,
0xd9b19cc4, 0x17edb20e, 0xa78e9aa1, 0x4ef4de06, 0x00c0bfe7, 0x7e1e442d,
0x9221fe38, 0xedb5c7dc, 0x6338078a, 0x62495b8d, 0xc11d9b8c, 0x49e81b16,
0x51d02bea, 0x3eb86d70, 0xc8bc4f13, 0xa10ec758, 0xd40751c0, 0x5ac94710,
0xc4c8b080, 0x95492b83, 0x975ee696, 0xb7bd96b4, 0x17379cce, 0x82e856e8,
0xe4c2c82a, 0x398e935f, 0x632437ea, 0x7c9c87d2, 0xdc1ddb7c, 0x65a80a48,
0x2309f164, 0x51fab475, 0x081dc11d, 0xda45573b, 0x6622f3f3, 0x48f1b214,
0x676c4edb, 0x243468c7, 0x00ffde60, 0xf1630350, 0xa0076c1d, 0x8f2c0c8b,
0x2383c26b, 0x361a8f4e, 0xaceea6c9, 0x01dd5a5d, 0x11111011, 0xc3780c04,
0xbf093ee2, 0xc7972c0b, 0x00d99040, 0xc0c20eb7, 0x659d3bd4, 0x269ab85e,
0x468e114f, 0x11ad4fdb, 0x83d083d8, 0x8c52f4bd, 0x3c9664bf, 0xa4f9c77c,
0x22a68876, 0xadb18784, 0xf480be83, 0x885a00ea, 0x220e0a88, 0xc303e4f6,
0xc866e058, 0xdddbd661, 0xdf395db1, 0xbad64343, 0xe6e65b03, 0x668e81c3,
0xad619e98, 0xeeb94563, 0xd4d19a3c, 0x3316ce95, 0x9d65f1e1, 0x3bf324fe,
0x0e468f53, 0xc386068c, 0xa89e24f7, 0xf0c7c73b, 0xb60e391f, 0x1b8827cb,
0x58601954, 0xc54f90f9, 0x80886ec5, 0x88088888, 0x1b7bb980, 0xb4c71c23,
0xe6148e39, 0xb12358b8, 0xbd08225d, 0x0ffef085, 0x72b4f025, 0x635ce389,
0xb90277e4, 0x0d05e000, 0x9bf9dbb9, 0x8e749fbc, 0x7ee6abbf, 0x4ddbf4af,
0x728df7f3, 0x10b59adf, 0xe3c38f49, 0xb23c638a, 0xdb3d9349, 0x66899a64,
0x00004dd5, 0xf51b5adf, 0x2220a255, 0xd9ff0f22};

View file

@ -1,177 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2"
version="1.1"
inkscape:version="0.48.4 r9939"
width="240"
height="240"
sodipodi:docname="a2c88e812ef42ae72650a2e4e4745a90.png">
<metadata
id="metadata8">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs6">
<linearGradient
id="linearGradient3877">
<stop
style="stop-color:#eff7fc;stop-opacity:1;"
offset="0"
id="stop3879" />
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="1"
id="stop3881" />
</linearGradient>
<linearGradient
id="linearGradient3829">
<stop
id="stop3831"
offset="0"
style="stop-color:#1f96d4;stop-opacity:1;" />
<stop
id="stop3833"
offset="1"
style="stop-color:#37aee2;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient3821">
<stop
style="stop-color:#37aee2;stop-opacity:1;"
offset="0"
id="stop3823" />
<stop
style="stop-color:#1e96c8;stop-opacity:1;"
offset="1"
id="stop3825" />
</linearGradient>
<linearGradient
id="linearGradient3783">
<stop
style="stop-color:#1e94d3;stop-opacity:1;"
offset="0"
id="stop3785" />
<stop
id="stop3803"
offset="1"
style="stop-color:#1e94d3;stop-opacity:1;" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3783"
id="linearGradient3827"
x1="-10"
y1="90"
x2="30"
y2="50"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3783-1"
id="linearGradient3827-7"
x1="-10"
y1="90"
x2="30"
y2="50"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3783-1">
<stop
style="stop-color:#1e94d3;stop-opacity:1;"
offset="0"
id="stop3785-2" />
<stop
id="stop3803-6"
offset="1"
style="stop-color:#1e94d3;stop-opacity:1;" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3821"
id="linearGradient3873"
x1="16.666666"
y1="56.666668"
x2="6.6666665"
y2="80"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3877"
id="linearGradient3883"
x1="135"
y1="120"
x2="160"
y2="160"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1366"
inkscape:window-height="705"
id="namedview4"
showgrid="false"
inkscape:zoom="0.70710678"
inkscape:cx="268.45834"
inkscape:cy="192.89138"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg2">
<inkscape:grid
type="xygrid"
id="grid2987" />
</sodipodi:namedview>
<path
sodipodi:type="arc"
style="fill:url(#linearGradient3873);fill-opacity:1;stroke:none"
id="path2995-1-0"
sodipodi:cx="10"
sodipodi:cy="70"
sodipodi:rx="20"
sodipodi:ry="20"
d="m 30,70 a 20,20 0 1 1 -40,0 20,20 0 1 1 40,0 z"
transform="matrix(6,0,0,6,60,-300)" />
<path
style="fill:#c8daea;fill-opacity:1;stroke:none"
d="m 98,175 c -3.887644,0 -3.226996,-1.46793 -4.567796,-5.16949 l -11.440678,-37.62712 70.805084,-44.237289 8.26271,2.161017 -6.8644,18.813562 z"
id="path2993"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
<path
style="fill:#a9c9dd;fill-opacity:1;stroke:none"
d="m 98,175 c 3,0 4.32989,-1.36747 6,-3 2.57835,-2.52034 36,-35 36,-35 l -20.47193,-4.95511 -19,12 L 98,174 z"
id="path2989"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csccccc" />
<path
style="fill:url(#linearGradient3883);stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1"
d="m 100.04237,144.40678 48.36017,35.72884 c 5.51851,3.04487 9.5014,1.46836 10.87626,-5.12353 l 19.68513,-92.762819 c 2.01542,-8.080226 -3.08008,-11.745195 -8.35944,-9.348192 L 55.010511,117.48476 c -7.890082,3.1647 -7.844107,7.56662 -1.438184,9.52797 l 29.662531,9.2583 68.673252,-43.325271 c 3.24187,-1.965881 6.21727,-0.908988 3.77523,1.25841 z"
id="path2991"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccc" />
</svg>

Before

Width:  |  Height:  |  Size: 5.4 KiB

3095
queries.c

File diff suppressed because it is too large Load diff

161
queries.h
View file

@ -1,161 +0,0 @@
/*
This file is part of telegram-client.
struct telegram-client 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.
struct telegram-client 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 telegram-client. If not, see <http://www.gnu.org/licenses/>.
Copyright Vitaly Valtman 2013
*/
#ifndef __QUERIES_H__
#define __QUERIES_H__
#pragma once
#include "structures.h"
struct telegram;
struct encr_video;
struct document;
struct secret_chat;
struct tree_query;
struct tree_timer;
#define QUERY_ACK_RECEIVED 1
struct query;
struct query_methods {
int (*on_answer)(struct query *q);
int (*on_error)(struct query *q, int error_code, int len, char *error);
int (*on_timeout)(struct query *q);
};
struct download_desc{
void *data;
int type;
};
struct download {
int offset;
int size;
long long volume;
long long secret;
long long access_hash;
int local_id;
int dc;
void *extra;
int fd;
char *name;
long long id;
unsigned char *iv;
unsigned char *key;
int type;
struct mtproto_connection *c;
};
void load_next_part (struct telegram *instance, struct download *D);
struct event_timer {
double timeout;
int (*alarm)(void *self);
void *self;
};
struct query {
long long msg_id;
int data_len;
int flags;
int seq_no;
void *data;
struct query_methods *methods;
struct event_timer ev;
struct dc *DC;
struct session *session;
void *extra;
};
struct query *send_query (struct telegram *instance, struct dc *DC, int len, void *data, struct query_methods *methods, void *extra);
void query_ack (struct telegram *instance, long long id);
void query_error (struct telegram *instance, long long id);
void query_result (struct telegram *instance, long long id);
void query_restart (struct telegram *instance, long long id);
void insert_event_timer (struct telegram *instance, struct event_timer *ev);
void remove_event_timer (struct telegram *instance, struct event_timer *ev);
double next_timer_in (struct telegram *instance);
void work_timers (struct telegram *instance);
extern struct query_methods help_get_config_methods;
void do_send_code (struct telegram *instance, const char *user);
void do_phone_call (struct telegram *instance, const char *user);
void do_send_code_result (struct telegram *instance, const char *code);
double get_double_time (void);
void do_update_contact_list (struct telegram *instance);
union user_chat;
void do_send_message (struct telegram *instance, peer_id_t id, const char *msg, int len);
void do_send_text (struct telegram *instance, peer_id_t id, char *file);
void do_get_history (struct telegram *instance, peer_id_t id, int limit);
void do_get_dialog_list (struct telegram*);
void do_get_dialog_list_ex (struct telegram*);
void do_send_photo (struct telegram *instance, int type, peer_id_t to_id, char *file_name);
void do_get_chat_info (struct telegram *instance, peer_id_t id);
void do_get_user_list_info_silent (struct telegram *instance, int num, int *list);
void do_get_user_info (struct telegram *instance, peer_id_t id, int showInfo);
void do_forward_message (struct telegram *instance, peer_id_t id, int n);
void do_rename_chat (struct telegram *instance, peer_id_t id, char *name);
void do_load_encr_video (struct telegram *instance, struct encr_video *V, void *extra);
void do_create_encr_chat_request (struct telegram *instance, int user_id);
void do_create_secret_chat (struct telegram *instance, peer_id_t id);
void do_create_group_chat (struct telegram *instance, peer_id_t id, char *chat_topic);
void do_get_suggested (struct telegram*);
struct photo;
struct video;
void do_load_photo (struct telegram *instance, struct photo *photo, int photoBig, void *extra);
void do_load_video_thumb (struct telegram *instance, struct video *video, void *extra);
void do_load_audio (struct telegram *instance, struct video *V, void *extra);
void do_load_video (struct telegram *instance, struct video *V, void *extra);
void do_load_document (struct telegram *instance, struct document *V, void *extra);
void do_load_document_thumb (struct telegram *instance, struct document *video, void *extra);
void do_help_get_config (struct telegram *instance);
void do_auth_check_phone (struct telegram *instance, const char *user);
void do_get_nearest_dc (struct telegram*);
void do_send_code_result_auth (struct telegram *instance, const char *code, const char *first_name, const char *last_name);
void do_import_auth (struct telegram *instance, int num, void (*cb)(void *extra), void *extra);
void do_export_auth (struct telegram *instance, int num, void (*cb)(char *export_auth_str, int len, void *extra), void *extra);
void do_add_contact (struct telegram *instance, const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, int force);
void do_msg_search (struct telegram *instance, peer_id_t id, int from, int to, int limit, const char *s);
void do_accept_encr_chat_request (struct telegram *instance, struct secret_chat *E);
void do_get_difference (struct telegram*, int sync_from_start);
void do_mark_read (struct telegram *instance, peer_id_t id);
void do_visualize_key (struct binlog *bl, peer_id_t id);
void do_create_keys_end (struct telegram *, struct secret_chat *U);
void do_add_user_to_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id, int limit);
void do_del_user_from_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id);
void do_update_status (struct telegram *instance, int online);
void do_contacts_search (struct telegram *instance, int limit, const char *s);
void do_send_msg (struct telegram *instance, struct message *M);
void do_delete_msg (struct telegram *instance, long long id);
void do_restore_msg (struct telegram *instance, long long id);
// For binlog
int get_dh_config_on_answer (struct query *q);
void fetch_dc_option (struct telegram *instance);
void free_queries (struct telegram *instance);
void free_timers (struct telegram *instance);
#endif
const char *get_last_err();
int all_queries_done();

File diff suppressed because it is too large Load diff

View file

@ -1,423 +0,0 @@
/*
This file is part of telegram-client.
Telegram-client 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.
Telegram-client 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 telegram-client. If not, see <http://www.gnu.org/licenses/>.
Copyright Vitaly Valtman 2013
*/
#ifndef __STRUCTURES_H__
#define __STRUCTURES_H__
#pragma once
// forward-declrataions
struct mtproto_connection;
struct binlog;
typedef struct { int type; int id; } peer_id_t;
#include <assert.h>
//#define FLAG_EMPTY 1
#define FLAG_MESSAGE_EMPTY 1
#define FLAG_DELETED 2
#define FLAG_FORBIDDEN 4
#define FLAG_HAS_PHOTO 8
#define FLAG_CREATED 16
#define FLAG_USER_SELF 128
#define FLAG_USER_FOREIGN 256
#define FLAG_USER_CONTACT 512
#define FLAG_USER_IN_CONTACT 1024
#define FLAG_USER_OUT_CONTACT 2048
#define FLAG_CHAT_IN_CHAT 128
#define FLAG_ENCRYPTED 4096
#define FLAG_PENDING 8192
struct file_location {
int dc;
long long volume;
int local_id;
long long secret;
};
struct photo_size {
char *type;
struct file_location loc;
int w;
int h;
int size;
char *data;
};
struct geo {
double longitude;
double latitude;
};
struct photo {
long long id;
long long access_hash;
int user_id;
int date;
char *caption;
struct geo geo;
int sizes_num;
struct photo_size *sizes;
};
struct encr_photo {
long long id;
long long access_hash;
int dc_id;
int size;
int key_fingerprint;
unsigned char *key;
unsigned char *iv;
int w;
int h;
};
struct encr_video {
long long id;
long long access_hash;
int dc_id;
int size;
int key_fingerprint;
unsigned char *key;
unsigned char *iv;
int w;
int h;
int duration;
};
struct encr_audio {
long long id;
long long access_hash;
int dc_id;
int size;
int key_fingerprint;
unsigned char *key;
unsigned char *iv;
int duration;
};
struct encr_document {
long long id;
long long access_hash;
int dc_id;
int size;
int key_fingerprint;
unsigned char *key;
unsigned char *iv;
char *file_name;
char *mime_type;
};
struct encr_file {
char *filename;
unsigned char *key;
unsigned char *iv;
};
struct user_status {
int online;
int when;
};
struct tgl_user {
peer_id_t id;
int flags;
struct message *last;
char *print_name;
int structure_version;
struct file_location photo_big;
struct file_location photo_small;
long long photo_id;
struct photo photo;
char *first_name;
char *last_name;
char *phone;
long long access_hash;
struct user_status status;
int blocked;
char *real_first_name;
char *real_last_name;
};
struct chat_user {
int user_id;
int inviter_id;
int date;
};
struct chat {
peer_id_t id;
int flags;
struct message *last;
char *print_title;
int structure_version;
struct file_location photo_big;
struct file_location photo_small;
struct photo photo;
char *title;
int users_num;
int user_list_size;
int user_list_version;
struct chat_user *user_list;
int date;
int version;
int admin_id;
};
enum secret_chat_state {
sc_none,
sc_waiting,
sc_request,
sc_ok,
sc_deleted
};
struct secret_chat {
peer_id_t id;
int flags;
struct message *last;
char *print_name;
int structure_version;
struct file_location photo_big;
struct file_location photo_small;
struct photo photo;
int user_id;
int admin_id;
int date;
int ttl;
long long access_hash;
unsigned char *g_key;
unsigned char *nonce;
enum secret_chat_state state;
int key[64];
long long key_fingerprint;
};
typedef union peer {
struct {
peer_id_t id;
int flags;
struct message *last;
char *print_name;
int structure_version;
struct file_location photo_big;
struct file_location photo_small;
struct photo photo;
};
struct tgl_user user;
struct chat chat;
struct secret_chat encr_chat;
} peer_t;
struct video {
long long id;
long long access_hash;
int user_id;
int date;
int size;
int dc_id;
struct photo_size thumb;
char *caption;
int duration;
int w;
int h;
};
struct audio {
long long id;
long long access_hash;
int user_id;
int date;
int size;
int dc_id;
int duration;
};
struct document {
long long id;
long long access_hash;
int user_id;
int date;
int size;
int dc_id;
struct photo_size thumb;
char *caption;
char *mime_type;
};
struct message_action {
unsigned type;
union {
struct {
char *title;
int user_num;
int *users;
};
char *new_title;
struct photo photo;
int user;
int ttl;
};
};
struct message_media {
unsigned type;
union {
struct photo photo;
struct video video;
struct audio audio;
struct document document;
struct geo geo;
struct {
char *phone;
char *first_name;
char *last_name;
int user_id;
};
struct encr_photo encr_photo;
struct encr_video encr_video;
struct encr_audio encr_audio;
struct encr_document encr_document;
struct encr_file encr_file;
struct {
void *data;
int data_size;
};
};
};
struct message {
struct message *next_use, *prev_use;
struct message *next, *prev;
long long id;
int flags;
peer_id_t fwd_from_id;
int fwd_date;
peer_id_t from_id;
peer_id_t to_id;
int out;
int unread;
int date;
int service;
struct telegram *instance;
union {
struct message_action action;
struct {
char *message;
int message_len;
struct message_media media;
};
};
};
int fetch_file_location (struct mtproto_connection *mtp, struct file_location *loc);
int fetch_user_status (struct mtproto_connection *mtp, struct user_status *S);
int fetch_user (struct mtproto_connection *mtp, struct tgl_user *U);
struct tgl_user *fetch_alloc_user (struct mtproto_connection *mtp);
struct tgl_user *fetch_alloc_user_full (struct mtproto_connection *mtp);
struct chat *fetch_alloc_chat (struct mtproto_connection *mtp);
struct chat *fetch_alloc_chat_full (struct mtproto_connection *mtp);
struct secret_chat *fetch_alloc_encrypted_chat (struct mtproto_connection *mtp);
struct message *fetch_alloc_message (struct mtproto_connection *self, struct telegram *instance);
struct message *fetch_alloc_geo_message (struct mtproto_connection *mtp, struct telegram *instance);
struct message *fetch_alloc_message_short (struct mtproto_connection *mtp, struct telegram *instance);
struct message *fetch_alloc_message_short_chat (struct mtproto_connection *self, struct telegram *instance);
struct message *fetch_alloc_encrypted_message (struct mtproto_connection *mtp, struct telegram *instance);
void fetch_encrypted_message_file (struct mtproto_connection *mtp, struct message_media *M);
void fetch_skip_encrypted_message_file (struct mtproto_connection *mtp);
void fetch_message_action_encrypted (struct mtproto_connection *mtp, struct message_action *M);
peer_id_t fetch_peer_id (struct mtproto_connection *mtp);
void fetch_message_media (struct mtproto_connection *mtp, struct message_media *M);
void fetch_message_media_encrypted (struct mtproto_connection *mtp, struct message_media *M);
void fetch_message_action (struct mtproto_connection *mtp, struct message_action *M);
void message_insert_tree (struct message *M);
void free_user (struct tgl_user *U);
void free_chat (struct chat *U);
char *create_print_name (struct binlog *bl, peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4);
int print_stat (struct binlog *bl, char *s, int len);
peer_t *user_chat_get (struct binlog *bl, peer_id_t id);
struct message *message_get (struct binlog *bl, long long id);
void update_message_id (struct message *M, long long id);
void message_insert (struct message *M);
void fetch_photo (struct mtproto_connection *mtp, struct photo *P);
void insert_encrypted_chat (struct binlog *bl, peer_t *P);
void insert_user (struct binlog *bl, peer_t *P);
void insert_chat (struct binlog *bl, peer_t *P);
void free_photo (struct photo *P);
void message_insert_unsent (struct message *M);
void message_remove_unsent (struct message *M);
void send_all_unsent (struct binlog *bl);
void message_remove_tree (struct message *M);
void message_add_peer (struct message *M);
void message_del_peer (struct message *M);
void free_message (struct message *M);
void message_del_use (struct message *M);
void peer_insert_name (struct binlog *bl, peer_t *P);
void peer_delete_name (struct binlog *bl, peer_t *P);
peer_t *peer_lookup_name (struct binlog *bl, const char *s);
int user_get_alias(peer_t *user, char *buffer, int maxlen);
#define PEER_USER 1
#define PEER_CHAT 2
#define PEER_GEO_CHAT 3
#define PEER_ENCR_CHAT 4
#define PEER_UNKNOWN 0
#define MK_USER(id) set_peer_id (PEER_USER,id)
#define MK_CHAT(id) set_peer_id (PEER_CHAT,id)
#define MK_GEO_CHAT(id) set_peer_id (PEER_GEO_CHAT,id)
#define MK_ENCR_CHAT(id) set_peer_id (PEER_ENCR_CHAT,id)
static inline int get_peer_type (peer_id_t id) {
return id.type;
}
static inline int get_peer_id (peer_id_t id) {
return id.id;
}
static inline peer_id_t set_peer_id (int type, int id) {
peer_id_t ID;
ID.id = id;
ID.type = type;
return ID;
}
static inline int cmp_peer_id (peer_id_t a, peer_id_t b) {
return memcmp (&a, &b, sizeof (a));
}
void free_messages (struct binlog *bl);
void free_peers (struct binlog *bl);
#endif

372
telegram-base.c Normal file
View file

@ -0,0 +1,372 @@
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <assert.h>
#include <tgl.h>
#include <binlog.h>
#include <glib.h>
#include <request.h>
#include "telegram-purple.h"
#include "msglog.h"
#define DC_SERIALIZED_MAGIC 0x868aa81d
#define STATE_FILE_MAGIC 0x28949a93
#define SECRET_CHAT_FILE_MAGIC 0x37a1988a
void read_state_file (struct tgl_state *TLS) {
char *name = 0;
if (asprintf (&name, "%s/%s", TLS->base_path, "state") < 0) {
return;
}
int state_file_fd = open (name, O_CREAT | O_RDWR, 0600);
free (name);
if (state_file_fd < 0) {
return;
}
int version, magic;
if (read (state_file_fd, &magic, 4) < 4) { close (state_file_fd); return; }
if (magic != (int)STATE_FILE_MAGIC) { close (state_file_fd); return; }
if (read (state_file_fd, &version, 4 || version < 0) < 4) { close (state_file_fd); return; }
int x[4];
if (read (state_file_fd, x, 16) < 16) {
close (state_file_fd);
return;
}
int pts = x[0];
int qts = x[1];
int seq = x[2];
int date = x[3];
close (state_file_fd);
bl_do_set_seq (TLS, seq);
bl_do_set_pts (TLS, pts);
bl_do_set_qts (TLS, qts);
bl_do_set_date (TLS, date);
}
void write_state_file (struct tgl_state *TLS) {
int wseq;
int wpts;
int wqts;
int wdate;
wseq = TLS->seq; wpts = TLS->pts; wqts = TLS->qts; wdate = TLS->date;
char *name = 0;
if (asprintf (&name, "%s/%s", TLS->base_path, "state") < 0) {
return;
}
int state_file_fd = open (name, O_CREAT | O_RDWR, 0600);
free (name);
if (state_file_fd < 0) {
return;
}
int x[6];
x[0] = STATE_FILE_MAGIC;
x[1] = 0;
x[2] = wpts;
x[3] = wqts;
x[4] = wseq;
x[5] = wdate;
assert (write (state_file_fd, x, 24) == 24);
close (state_file_fd);
}
void write_dc (struct tgl_dc *DC, void *extra) {
int auth_file_fd = *(int *)extra;
if (!DC) {
int x = 0;
assert (write (auth_file_fd, &x, 4) == 4);
return;
} else {
int x = 1;
assert (write (auth_file_fd, &x, 4) == 4);
}
assert (DC->has_auth);
assert (write (auth_file_fd, &DC->port, 4) == 4);
int l = strlen (DC->ip);
assert (write (auth_file_fd, &l, 4) == 4);
assert (write (auth_file_fd, DC->ip, l) == l);
assert (write (auth_file_fd, &DC->auth_key_id, 8) == 8);
assert (write (auth_file_fd, DC->auth_key, 256) == 256);
}
void write_auth_file (struct tgl_state *TLS) {
char *name = 0;
if (asprintf (&name, "%s/%s", TLS->base_path, "auth") < 0) {
return;
}
int auth_file_fd = open (name, O_CREAT | O_RDWR, 0600);
free (name);
if (auth_file_fd < 0) { return; }
int x = DC_SERIALIZED_MAGIC;
assert (write (auth_file_fd, &x, 4) == 4);
assert (write (auth_file_fd, &TLS->max_dc_num, 4) == 4);
assert (write (auth_file_fd, &TLS->dc_working_num, 4) == 4);
tgl_dc_iterator_ex (TLS, write_dc, &auth_file_fd);
assert (write (auth_file_fd, &TLS->our_id, 4) == 4);
close (auth_file_fd);
}
void read_dc (struct tgl_state *TLS, int auth_file_fd, int id, unsigned ver) {
int port = 0;
assert (read (auth_file_fd, &port, 4) == 4);
int l = 0;
assert (read (auth_file_fd, &l, 4) == 4);
assert (l >= 0 && l < 100);
char ip[100];
assert (read (auth_file_fd, ip, l) == l);
ip[l] = 0;
long long auth_key_id;
static unsigned char auth_key[256];
assert (read (auth_file_fd, &auth_key_id, 8) == 8);
assert (read (auth_file_fd, auth_key, 256) == 256);
//bl_do_add_dc (id, ip, l, port, auth_key_id, auth_key);
bl_do_dc_option (TLS, id, 2, "DC", l, ip, port);
bl_do_set_auth_key_id (TLS, id, auth_key);
bl_do_dc_signed (TLS, id);
}
void empty_auth_file (struct tgl_state *TLS) {
if (TLS->test_mode) {
bl_do_dc_option (TLS, 1, 0, "", strlen (TG_SERVER_TEST_1), TG_SERVER_TEST_1, 443);
bl_do_dc_option (TLS, 2, 0, "", strlen (TG_SERVER_TEST_2), TG_SERVER_TEST_2, 443);
bl_do_dc_option (TLS, 3, 0, "", strlen (TG_SERVER_TEST_3), TG_SERVER_TEST_3, 443);
bl_do_set_working_dc (TLS, TG_SERVER_TEST_DEFAULT);
} else {
bl_do_dc_option (TLS, 1, 0, "", strlen (TG_SERVER_1), TG_SERVER_1, 443);
bl_do_dc_option (TLS, 2, 0, "", strlen (TG_SERVER_2), TG_SERVER_2, 443);
bl_do_dc_option (TLS, 3, 0, "", strlen (TG_SERVER_3), TG_SERVER_3, 443);
bl_do_dc_option (TLS, 4, 0, "", strlen (TG_SERVER_4), TG_SERVER_4, 443);
bl_do_dc_option (TLS, 5, 0, "", strlen (TG_SERVER_5), TG_SERVER_5, 443);
bl_do_set_working_dc (TLS, TG_SERVER_DEFAULT);;
}
}
void read_auth_file (struct tgl_state *TLS) {
char *name = 0;
if (asprintf (&name, "%s/%s", TLS->base_path, "auth") < 0) {
return;
}
int auth_file_fd = open (name, O_CREAT | O_RDWR, 0600);
free (name);
if (auth_file_fd < 0) {
empty_auth_file (TLS);
return;
}
assert (auth_file_fd >= 0);
unsigned x;
unsigned m;
if (read (auth_file_fd, &m, 4) < 4 || (m != DC_SERIALIZED_MAGIC)) {
close (auth_file_fd);
empty_auth_file (TLS);
return;
}
assert (read (auth_file_fd, &x, 4) == 4);
assert (x > 0);
int dc_working_num;
assert (read (auth_file_fd, &dc_working_num, 4) == 4);
int i;
for (i = 0; i <= (int)x; i++) {
int y;
assert (read (auth_file_fd, &y, 4) == 4);
if (y) {
read_dc (TLS, auth_file_fd, i, m);
}
}
bl_do_set_working_dc (TLS, dc_working_num);
int our_id;
int l = read (auth_file_fd, &our_id, 4);
if (l < 4) {
assert (!l);
}
if (our_id) {
bl_do_set_our_id (TLS, our_id);
}
close (auth_file_fd);
}
void telegram_export_authorization (struct tgl_state *TLS);
void export_auth_callback (struct tgl_state *TLS, void *extra, int success) {
assert (success);
telegram_export_authorization (TLS);
}
void telegram_export_authorization (struct tgl_state *TLS) {
int i;
for (i = 0; i <= TLS->max_dc_num; i++) if (TLS->DC_list[i] && !tgl_signed_dc (TLS, TLS->DC_list[i])) {
tgl_do_export_auth (TLS, i, export_auth_callback, (void*)(long)TLS->DC_list[i]);
return;
}
write_auth_file (TLS);
telegram_on_ready (TLS);
}
static void request_code (struct tgl_state *TLS);
static void request_name_and_code (struct tgl_state *TLS);
static void code_receive_result (struct tgl_state *TLS, void *extra, int success, struct tgl_user *U) {
if (!success) {
debug ("Bad code...\n");
request_code (TLS);
} else {
telegram_export_authorization (TLS);
}
}
static void code_auth_receive_result (struct tgl_state *TLS, void *extra, int success, struct tgl_user *U) {
if (!success) {
debug ("Bad code...\n");
request_name_and_code (TLS);
} else {
telegram_export_authorization (TLS);
}
}
static void request_code_entered (gpointer data, const gchar *code) {
struct tgl_state *TLS = data;
telegram_conn *conn = TLS->ev_base;
char const *username = purple_account_get_username(conn->pa);
tgl_do_send_code_result (TLS, username, conn->hash, code, code_receive_result, 0) ;
}
static void request_code_canceled (gpointer data) {
struct tgl_state *TLS = data;
telegram_conn *conn = TLS->ev_base;
purple_connection_error_reason(conn->gc,
PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, "registration canceled");
}
static void request_name_code_entered (PurpleConnection* gc, PurpleRequestFields* fields) {
telegram_conn *conn = purple_connection_get_protocol_data(gc);
struct tgl_state *TLS = conn->TLS;
char const *username = purple_account_get_username(conn->pa);
const char* first = purple_request_fields_get_string(fields, "first_name");
const char* last = purple_request_fields_get_string(fields, "last_name");
const char* code = purple_request_fields_get_string(fields, "code");
if (!first || !last || !code) {
request_name_and_code (TLS);
return;
}
tgl_do_send_code_result_auth (TLS, username, conn->hash, code, first, last, code_auth_receive_result, NULL);
}
static void request_code (struct tgl_state *TLS) {
debug ("Client is not registered, registering...\n");
telegram_conn *conn = TLS->ev_base;
purple_request_input (
conn->gc, // handle (the PurpleAccount)
"Telegram Code", // title
"Enter Telegram Code", // primary
"Telegram wants to verify your identity, please enter the code, that you have received via SMS.", // secondary
NULL, // default_value
0, // multiline
0, // masked
"code", // hint
"OK", // ok_text
G_CALLBACK(request_code_entered), // ok_cb
"Cancel", // cancel_text
G_CALLBACK(request_code_canceled), // cancel_cb
conn->pa, // account
NULL, // who
NULL, // conv
TLS // user_data
);
}
static void request_name_and_code (struct tgl_state *TLS) {
telegram_conn *conn = TLS->ev_base;
debug ("Phone is not registered, registering...\n");
PurpleRequestFields* fields = purple_request_fields_new();
PurpleRequestField* field = 0;
PurpleRequestFieldGroup* group = purple_request_field_group_new("Registration");
field = purple_request_field_string_new("first_name", "First Name", "", 0);
purple_request_field_group_add_field(group, field);
field = purple_request_field_string_new("last_name", "Last Name", "", 0);
purple_request_field_group_add_field(group, field);
purple_request_fields_add_group(fields, group);
group = purple_request_field_group_new("Authorization");
field = purple_request_field_string_new("code", "Telegram Code", "", 0);
purple_request_field_group_add_field(group, field);
purple_request_fields_add_group(fields, group);
purple_request_fields(conn->gc, "Register", "Please register your phone number.", NULL, fields, "Ok",
G_CALLBACK( request_name_code_entered ), "Cancel", NULL, conn->pa, NULL, NULL, conn->gc);
}
static void sign_in_callback (struct tgl_state *TLS, void *extra, int success, int registered, const char *mhash) {
assert (success); // TODO proper error handle
telegram_conn *conn = TLS->ev_base;
conn->hash = strdup (mhash);
if (registered) {
request_code (TLS);
} else {
request_name_and_code (TLS);
}
}
static void telegram_send_sms (struct tgl_state *TLS) {
if (tgl_signed_dc (TLS, TLS->DC_working)) {
telegram_export_authorization (TLS);
return;
}
telegram_conn *conn = TLS->ev_base;
char const *username = purple_account_get_username(conn->pa);
tgl_do_send_code (TLS, username, sign_in_callback, 0);
}
static int all_authorized (struct tgl_state *TLS) {
int i;
for (i = 0; i <= TLS->max_dc_num; i++) if (TLS->DC_list[i]) {
if (!tgl_authorized_dc (TLS, TLS->DC_list[i])) {
return 0;
}
}
return 1;
}
static int check_all_authorized (gpointer arg) {
struct tgl_state *TLS = arg;
if (all_authorized (TLS)) {
telegram_send_sms (TLS);
return FALSE;
} else {
return TRUE;
}
}
void telegram_login (struct tgl_state *TLS) {
read_auth_file (TLS);
read_state_file (TLS);
if (all_authorized (TLS)) {
telegram_send_sms (TLS);
return;
}
purple_timeout_add (100, check_all_authorized, TLS);
}

9
telegram-base.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef __TELEGRAM_BASE_H__
#define __TELEGRAM_BASE_H__
void read_state_file (struct tgl_state *TLS);
void read_auth_file (struct tgl_state *TLS);
void write_auth_file (struct tgl_state *TLS);
void write_state_file (struct tgl_state *TLS);
void telegram_login (struct tgl_state *TLS);
#endif

File diff suppressed because it is too large Load diff

View file

@ -26,62 +26,45 @@
#define TG_BUILD "8"
#include <glib.h>
#include "notify.h"
#include "plugin.h"
#include "version.h"
#include "account.h"
#include "connection.h"
#include "mtproto-client.h"
#include <notify.h>
#include <plugin.h>
#include <version.h>
#include <account.h>
#include <connection.h>
typedef struct {
struct telegram *tg;
PurpleAccount *pa;
struct tgl_state *TLS;
/*
* Used during login
*/
char *hash;
PurpleAccount *pa;
PurpleConnection *gc;
/**
* Whether the state of the protocol has changed since the last save
*/
int updated;
/**
* Whether the state of the protocol has changed since the last save
*/
int updated;
/**
* The used purple timeout handler
*/
guint timer;
/**
* Queue of all new messages that need to be added to a chat
*/
GQueue *new_messages;
/**
* Queue of all new messages that need to be added to a chat
*/
GQueue *new_messages;
/**
* Queue of all joined chats
*/
GHashTable *joining_chats;
/**
* Queue of all joined chats
*/
GHashTable *joining_chats;
guint timer;
} telegram_conn;
typedef struct {
/**
* The mtproto_connection associated with this handle
*/
struct mtproto_connection *mtp;
/**
* Write handler returned by purple_input_add
*/
guint wh;
/**
* Read handler returned by purple_input_add
*/
guint rh;
/**
* The file descriptor of the used socket
*/
int fd;
} mtproto_handle;
struct download_desc {
int type;
void *data;
};
void telegram_on_ready (struct tgl_state *TLS);
#endif

View file

@ -1,480 +0,0 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <assert.h>
#include "telegram.h"
#include "msglog.h"
#include "glib.h"
#include "tools.h"
#include "mtproto-client.h"
#include "binlog.h"
#include "loop.h"
/*
* Events
*/
void event_user_info_received_handler(struct telegram *instance, struct tgl_user *peer, int show_info)
{
if (instance->config->on_user_info_received_handler) {
instance->config->on_user_info_received_handler (instance, peer, show_info);
}
}
DEFINE_EVENT_HANDLER (peer_allocated, void);
DEFINE_EVENT_HANDLER (update_user_status, void);
DEFINE_EVENT_HANDLER (update_user_typing, void);
DEFINE_EVENT_HANDLER (update_user_name, peer_t);
DEFINE_EVENT_HANDLER (update_user_photo, peer_t);
DEFINE_EVENT_HANDLER (update_user_registered, peer_t);
DEFINE_EVENT_HANDLER (update_chat_participants, peer_t);
DEFINE_EVENT_HANDLER_3(update_chat_add_participant, peer_t *, peer_id_t, peer_id_t);
DEFINE_EVENT_HANDLER_3(update_chat_del_participant, peer_t *, peer_id_t, void *);
DEFINE_EVENT_HANDLER_3(update_chat_user_typing, peer_t *, peer_t *, void *);
DEFINE_EVENT_HANDLER (update_auth_new, char);
DEFINE_EVENT_HANDLER (update_new_message, struct message);
DEFINE_EVENT_HANDLER (download_finished, struct download);
/**
* Calculate the configuration path for the given config file and the given instance
*
* @returns The full path to the configuration.
*
* NOTE: the returned string must be freed manually using gfree
*/
char *telegram_get_config(struct telegram *instance, char *config)
{
return g_strdup_printf("%s/%s", instance->config_path, config);
}
/**
* Return whether the current client is registered.
*/
int telegram_is_registered(struct telegram *tg)
{
return telegram_get_working_dc(tg)->has_auth;
}
/**
* Handle state changes of the telegram instance
*
* Execute all actions necessary when a certain state is reached. The state machine executes
* the authorization and registration steps needed to connect the client to the telegram network,
* and will either trigger RPC queries or callbacks to the GUI to request input from the user.
*/
void telegram_change_state (struct telegram *instance, int state, void *data)
{
instance->session_state = state;
debug("on_state_change: %d\n", state);
switch (state) {
case STATE_ERROR: {
const char* err = data;
if (err == NULL) {
err = "<no error description>";
}
debug("telegram errored: %s\n", err);
mtproto_close (instance->connection);
instance->config->on_error (instance, err);
}
break;
case STATE_AUTHORIZED:
debug("requesting configuration\n");
telegram_change_state(instance, STATE_CONFIG_REQUESTED, NULL);
if (telegram_is_registered(instance)) {
telegram_change_state (instance, STATE_READY, NULL);
return;
}
do_help_get_config (instance);
break;
case STATE_CONFIG_RECEIVED:
debug("received network configuration, checking whether phone is registered.\n");
telegram_store_session(instance);
do_auth_check_phone(instance, instance->login);
break;
case STATE_PHONE_NOT_REGISTERED:
debug("phone is not registered, need to register phone number.\n");
do_send_code(instance, instance->login);
break;
case STATE_PHONE_CODE_NOT_ENTERED:
debug("phone authenticion, user needs to enter code, first and last name.\n");
assert (instance->config->on_phone_registration_required);
instance->config->on_phone_registration_required (instance);
break;
case STATE_CLIENT_NOT_REGISTERED:
debug("phone is already registered, need to register client.\n");
do_send_code(instance, instance->login);
break;
case STATE_CLIENT_CODE_NOT_ENTERED:
debug("client authentication, user needs to enter code.\n");
assert (instance->config->on_client_registration_required);
instance->config->on_client_registration_required (instance);
// wait for user input ...
break;
case STATE_READY:
debug("telegram is registered and ready.\n");
telegram_store_session (instance);
instance->config->on_ready (instance);
break;
case STATE_DISCONNECTED_SWITCH_DC: {
// telegram demands that we use a different data center, which caused
// the current mtproto_connection to be disconnected
int target_dc = *(int*) data;
debug ("Disconnected: Migrate to data center %d\n", target_dc);
// close old connection and mark it for destruction
mtproto_close (instance->connection);
assert (instance->config->proxy_request_cb);
// remove all left over queries and timers
free_timers (instance);
free_queries (instance);
// start a new connection to the demanded data center. The pointer to the
// new dc should was already updated by the on_error function of the query
telegram_connect (instance);
}
break;
}
}
struct telegram *telegram_new(const char* login, struct telegram_config *config)
{
struct telegram *this = talloc0(sizeof(struct telegram));
this->protocol_data = NULL;
this->bl = talloc0 (sizeof(struct binlog));
this->config = config;
this->login = g_strdup(login);
this->config_path = g_strdup_printf("%s/%s", config->base_config_path, login);
this->download_path = telegram_get_config(this, "downloads");
this->auth_path = telegram_get_config(this, "auth");
this->state_path = telegram_get_config(this, "state");
this->secret_path = telegram_get_config(this, "secret");
debug("%s\n", this->login);
debug("%s\n", this->config_path);
debug("%s\n", this->download_path);
debug("%s\n", this->auth_path);
debug("%s\n", this->state_path);
debug("%s\n", this->secret_path);
telegram_change_state(this, STATE_INITIALISED, NULL);
return this;
}
void free_bl (struct binlog *bl);
void free_auth (struct dc* DC_list[], int count);
void telegram_destroy(struct telegram *this)
{
// close all open connections
int i = 0;
for (; i < 100; i++) {
if (this->Cs[i] != NULL && !this->Cs[i]->destroy) {
mtproto_close (this->Cs[i]);
}
}
free_queries (this);
free_timers (this);
mtproto_free_closed (this, 1);
free_bl (this->bl);
free_auth (this->auth.DC_list, 11);
g_free(this->login);
g_free(this->config_path);
g_free(this->download_path);
g_free(this->auth_path);
g_free(this->state_path);
g_free(this->secret_path);
// TODO: BN_CTX *ctx
if (this->phone_code_hash) free (this->phone_code_hash);
if (this->suser) free (this->suser);
if (this->export_auth_str) free (this->export_auth_str);
//tfree (this->ML, sizeof(struct message) * MSG_STORE_SIZE);
tfree(this, sizeof(struct telegram));
}
void free_bl (struct binlog *bl)
{
// TODO: rptr, wptr
free_peers (bl);
free_messages (bl);
tfree (bl, sizeof (struct binlog));
}
void free_auth (struct dc* DC_list[], int count)
{
int i;
for (i = 0; i < count; i++ ) if (DC_list[i]) {
tfree (DC_list[i], sizeof(struct dc));
}
}
void assert_file_usable(const char *file)
{
debug ("assert_file_usable (%s)\n", file);
assert(access(file, W_OK | R_OK | F_OK) != -1);
}
void assure_file_exists(const char *dir, const char *file)
{
g_mkdir_with_parents(dir, 0700);
char *f = g_strdup_printf("%s/%s", dir, file);
close(open(f, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR));
assert_file_usable(f);
g_free(f);
}
/**
* Get the currently used connection
*
* Will only work after telegram_connect has been called and the connection has
* not errored.
*/
struct connection *telegram_get_connection(struct telegram *instance)
{
assert(instance->session_state != STATE_ERROR);
struct dc *DC = telegram_get_working_dc(instance);
assert(DC);
assert(DC->sessions[0]);
assert(DC->sessions[0]->c);
return DC->sessions[0]->c;
}
/**
* Get the currently used DC
*
* Will only work after restore_session has been called and the data center configuration
* was properly loaded
*/
struct dc *telegram_get_working_dc(struct telegram *instance)
{
assert(instance->session_state != STATE_ERROR);
assert(instance->auth.DC_list);
assert(instance->auth.dc_working_num > 0);
struct dc *DC = instance->auth.DC_list[instance->auth.dc_working_num];
return DC;
}
/**
* Store the current session state to a file
*/
void telegram_restore_session(struct telegram *instance)
{
g_mkdir_with_parents(instance->config_path, 0700);
g_mkdir_with_parents(instance->download_path, 0700);
instance->auth = read_auth_file(instance->auth_path);
instance->proto = read_state_file(instance->state_path);
read_secret_chat_file (instance, instance->secret_path);
}
/**
* Load the current session state
*/
void telegram_store_session(struct telegram *instance)
{
assure_file_exists(instance->config_path, "auth");
assure_file_exists(instance->config_path, "state");
assure_file_exists(instance->config_path, "secret");
write_auth_file(&instance->auth, instance->auth_path);
write_state_file(&instance->proto, instance->state_path);
write_secret_chat_file(instance, instance->secret_path);
}
void on_authorized(struct mtproto_connection *c, void* data);
void telegram_main_connected (struct proxy_request *req)
{
struct telegram *instance = req->data;
debug("Authorized... storing current session %d.\n",
instance->connection->connection->session[0]);
telegram_store_session(instance);
telegram_change_state(instance, STATE_AUTHORIZED, NULL);
}
/**
* Connect to the nearest data center
*/
void telegram_connect (struct telegram *instance)
{
debug ("telegram_network_connect()\n");
if (! instance->auth.DC_list) {
debug("telegram_network_connect(): cannot connect, restore / init a session first.\n");
assert(0);
}
struct dc *DC_working = telegram_get_working_dc (instance);
struct proxy_request *req = talloc0(sizeof(struct proxy_request));
req->type = REQ_CONNECTION;
req->tg = instance;
req->data = instance;
req->DC = DC_working;
req->done = telegram_main_connected;
assert (instance->config->proxy_request_cb);
instance->config->proxy_request_cb (instance, req);
}
void on_auth_imported (void *extra)
{
debug ("on_auth_imported()\n");
struct download *dl = extra;
struct mtproto_connection *c = dl->c;
struct telegram *tg = c->instance;
bl_do_dc_signed (tg->bl, c, dl->dc);
write_auth_file (&tg->auth, tg->auth_path);
load_next_part (tg, dl);
telegram_flush (tg);
}
void on_auth_exported (char *export_auth_str UU, int len UU, void *extra)
{
debug ("on_auth_exported()\n");
struct download *dl = extra;
do_import_auth (dl->c->instance, dl->dc, on_auth_imported, extra);
telegram_flush (dl->c->instance);
}
void telegram_dl_connected (struct proxy_request *req)
{
debug ("telegram_dl_connected(dc=%d)\n", req->DC->id);
struct telegram *tg = req->tg;
// TODO: error handling
struct download *dl = req->data;
dl->c = req->conn;
struct dc *DC = tg->auth.DC_list[dl->dc];
if (!DC->has_auth) {
do_export_auth (tg, dl->dc, on_auth_exported, dl);
telegram_flush (tg);
} else {
on_auth_imported (dl);
}
}
/**
* Create a connection for the given download
*/
void telegram_dl_add (struct telegram *instance, struct download *dl)
{
debug ("telegram_connect_dl(dc_num=%d, dc=%d)\n", dl->dc, instance->auth.DC_list[dl->dc]);
if (!instance->dl_queue) {
instance->dl_queue = g_queue_new ();
}
g_queue_push_tail(instance->dl_queue, dl);
}
void telegram_dl_next (struct telegram *instance)
{
assert (instance->dl_queue);
assert (instance->config->proxy_request_cb);
if (!instance->dl_curr) {
struct download *dl = g_queue_pop_head (instance->dl_queue);
if (dl) {
struct proxy_request *req = talloc0(sizeof(struct proxy_request));
req->type = REQ_DOWNLOAD;
req->DC = instance->auth.DC_list[dl->dc];
req->tg = instance;
req->done = telegram_dl_connected;
req->data = dl;
instance->dl_curr = dl;
debug ("telegrma_dl_start(workin_dc=%d, ): starting new download..\n", instance->auth.dc_working_num);
if (dl->dc == instance->auth.dc_working_num) {
debug ("is working DC, start download...\n");
assert (telegram_get_working_dc(instance)->sessions[0]->c);
req->conn = instance->connection;
dl->c = req->conn;
telegram_dl_connected (req);
} else {
debug ("is remote DC, requesting connection...\n");
instance->config->proxy_request_cb (instance, req);
}
} else {
debug ("telegrma_dl_start(): no more downloads, DONE!\n");
mtproto_close_foreign (instance);
}
} else {
debug ("telegrma_dl_start(): download busy...\n");
}
}
void on_authorized(struct mtproto_connection *c UU, void *data)
{
debug ("on_authorized()...\n");
struct proxy_request *req = data;
assert (req->done);
req->done (req);
tfree (req, sizeof(struct proxy_request));
}
struct mtproto_connection *telegram_add_proxy(struct telegram *instance, struct proxy_request *req,
int fd, void *handle)
{
struct mtproto_connection *c = mtproto_new (req->DC, fd, instance);
c->handle = handle;
c->on_ready = on_authorized;
c->on_ready_data = req;
req->conn = c;
if (req->type == REQ_CONNECTION) {
req->tg->connection = c;
}
mtproto_connect (c);
return c;
}
void mtp_read_input (struct mtproto_connection *mtp)
{
try_read (mtp->connection);
}
int mtp_write_output (struct mtproto_connection *mtp)
{
return try_write(mtp->connection);
}
int telegram_authenticated (struct telegram *instance)
{
return telegram_get_working_dc (instance)->auth_key_id > 0;
}
void telegram_flush (struct telegram *instance)
{
debug ("telegram flush()\n");
int i;
for (i = 0; i < 100; i++) {
struct mtproto_connection *c = instance->Cs[i];
if (!c) continue;
if (!c->connection) continue;
if (c->connection->out_bytes) {
debug ("connection %d has %d bytes, triggering on_output.\n",
i, c->connection->out_bytes);
instance->config->on_output(c->handle);
} else {
debug ("connection %d has no bytes, skipping\n", i);
}
}
}

View file

@ -1,484 +0,0 @@
#ifndef __TELEGRAM_H__
#define __TELEGRAM_H__
#define MAX_PACKED_SIZE (1 << 24)
#define MAX_DC_NUM 9
#define MAX_PEER_NUM 100000
#ifndef PROG_NAME
#define PROG_NAME "telegram-purple"
#endif
#include <sys/types.h>
#include "glib.h"
#include "loop.h"
#include "tree.h"
#include "queries.h"
#include <openssl/bn.h>
// forward declarations
struct message;
struct protocol_state;
struct authorization_state;
struct tree_query;
struct tree_timer;
/*
* telegram states
*/
#define STATE_INITIALISED 0
#define STATE_DISCONNECTED 1
#define STATE_ERROR 2
#define STATE_AUTHORIZED 6
// dc discovery
#define STATE_CONFIG_REQUESTED 7
#define STATE_EXPORTING_CONFIG 8
#define STATE_DISCONNECTED_SWITCH_DC 9
#define STATE_CONFIG_RECEIVED 11
// login
// - Phone Registration
#define STATE_PHONE_NOT_REGISTERED 13
#define STATE_PHONE_CODE_REQUESTED 14
#define STATE_PHONE_CODE_NOT_ENTERED 15
#define STATE_PHONE_CODE_ENTERED 16
// - Client Registration
#define STATE_CLIENT_IS_REGISTERED_SENT 17
#define STATE_CLIENT_NOT_REGISTERED 18
#define STATE_CLIENT_CODE_REQUESTED 19
#define STATE_CLIENT_CODE_NOT_ENTERED 20
#define STATE_CLIENT_CODE_ENTERED 21
// Ready for sending and receiving messages
#define STATE_READY 22
struct tree_peer;
struct tree_peer_by_name;
struct tree_message;
#define BINLOG_BUFFER_SIZE (1 << 20)
/**
* Binary log
*/
struct binlog {
int binlog_buffer[BINLOG_BUFFER_SIZE];
int *rptr;
int *wptr;
int test_dc; // = 0
int in_replay_log;
int binlog_enabled; // = 0;
int binlog_fd;
long long binlog_pos;
int s[1000];
//
struct tree_peer *peer_tree;
struct tree_peer_by_name *peer_by_name_tree;
struct tree_message *message_tree;
struct tree_message *message_unsent_tree;
int users_allocated;
int chats_allocated;
int messages_allocated;
int peer_num;
int encr_chats_allocated;
int geo_chats_allocated;
peer_t *Peers[MAX_PEER_NUM];
};
#define REQ_CONNECTION 1
#define REQ_DOWNLOAD 2
struct proxy_request {
struct telegram *tg;
struct dc *DC;
struct mtproto_connection *conn;
int type;
void *data;
void (*done) (struct proxy_request *req);
void *extra;
};
struct telegram;
struct download;
/*
* Events 1 arg
*/
#define DEFINE_EVENT_LISTENER(E_NAME, D_TYPE) void (*on_ ## E_NAME) (struct telegram *tg, D_TYPE *data);
#define DECLARE_EVENT_HANDLER(E_NAME, D_TYPE) \
void event_ ## E_NAME (struct telegram *tg, D_TYPE *data)
#define DEFINE_EVENT_HANDLER(E_NAME, D_TYPE) \
void event_ ## E_NAME (struct telegram *tg, D_TYPE *data) \
{ \
if (tg->config->on_ ## E_NAME) { \
tg->config->on_ ## E_NAME (tg, data); \
} else { \
warning ("Trying to execute non-existing event listener %s\n", "E_NAME"); \
} \
}
/*
* Events 3 args
*/
#define DEFINE_EVENT_LISTENER_3(E_NAME, D_TYPE, D_TYPE2, D_TYPE3) void (*on_ ## E_NAME) (struct telegram *tg, D_TYPE data, D_TYPE2 data2, D_TYPE3 data3);
#define DECLARE_EVENT_HANDLER_3(E_NAME, D_TYPE, D_TYPE2, D_TYPE3) \
void event_ ## E_NAME (struct telegram *tg, D_TYPE data, D_TYPE2 data2, D_TYPE3 data3)
#define DEFINE_EVENT_HANDLER_3(E_NAME, D_TYPE, D_TYPE2, D_TYPE3) \
void event_ ## E_NAME (struct telegram *tg, D_TYPE data, D_TYPE2 data2, D_TYPE3 data3) \
{ \
if (tg->config->on_ ## E_NAME) { \
tg->config->on_ ## E_NAME (tg, data, data2, data3); \
} else { \
warning ("Trying to execute non-existing event listener %s\n", "E_NAME"); \
} \
}
/**
* Contains all options and pointer to callback functions required by telegram
*/
struct telegram_config {
/**
* The base path containing the telegram configuration
*/
char* base_config_path;
/**
* Called when there is pending network output
*/
void (*on_output)(void *handle);
/**
* A callback function that delivers a connections to the given hostname
* and port by calling telegram_set_proxy. This is useful for tunelling
* the connection through a proxy server.
*/
void (*proxy_request_cb) (struct telegram *instance, struct proxy_request *req);
/**
* A callback function that is called once the proxy connection is no longer
* needed. This is useful for freeing all used resources.
*/
void (*proxy_close_cb) (void *handle);
/**
* A callback function that is called when a phone registration is required.
*
* This callback must query first name, last name and the
* authentication code from the user and call do_send_code_result_auth once done
*/
void (*on_phone_registration_required) (struct telegram *instance);
/**
* A callback function that is called when a client registration is required.
*
* This callback must query the authentication code from the user and
* call do_send_code_result once done
*/
void (*on_client_registration_required) (struct telegram *instance);
/**
* A callback function that is called when telegram is ready
*/
void (*on_ready) (struct telegram *instance);
/**
* A callback function that is called when telegram is disconnected
*/
void (*on_error) (struct telegram *instance, const char *err);
/**
* A callback function that is called when a new peer was allocated. This is useful
* for populating the GUI with new peers.
*/
DEFINE_EVENT_LISTENER(peer_allocated, void);
/**
* A callback function that is called when a user's status has changed
*/
DEFINE_EVENT_LISTENER(update_user_status, void);
/**
* A callback function that is called when a user starts or stops typing
*/
DEFINE_EVENT_LISTENER(update_user_typing, void);
DEFINE_EVENT_LISTENER(update_user_name, peer_t);
DEFINE_EVENT_LISTENER(update_user_photo, peer_t);
DEFINE_EVENT_LISTENER(update_user_registered, peer_t);
DEFINE_EVENT_LISTENER(update_chat_participants, peer_t);
/**
* A new user is added to a chat
*
* @param data1 The chat
* @param data2 The added user
* @param data3 The inviter
*/
DEFINE_EVENT_LISTENER_3(update_chat_add_participant, peer_t *, peer_id_t, peer_id_t);
/**
* A user is deleted from a chat
*
* @param data1 The chat
* @param data2 The added user
* @param data3 NULL
*/
DEFINE_EVENT_LISTENER_3(update_chat_del_participant, peer_t *, peer_id_t, void *);
/**
* A user in a chat is typing
*
* @param data1 The chat
* @param data2 The user
* @param data3 NULL
*/
DEFINE_EVENT_LISTENER_3(update_chat_user_typing, peer_t *, peer_t *, void *);
/**
* A new device was registered for @location
*
* @param tg
* @param location
*/
DEFINE_EVENT_LISTENER(update_auth_new, char);
/**
* A callback function that is called when a new message was allocated. This is useful
* for adding new messages to the GUI.
*/
DEFINE_EVENT_LISTENER(update_new_message, struct message);
/**
* A callback function that is called when a download is completed. This is useful
* for populating the GUI with new user photos.
*/
DEFINE_EVENT_LISTENER(download_finished, struct download);
/**
* A callback function that is called when a peer user info was received. This is useful
* for populating the GUI with new user photos.
*/
void (*on_user_info_received_handler) (struct telegram *instance, struct tgl_user *peer, int showInfo);
/**
* A callback function that is called when chat info is received
*/
void (*on_chat_info_received) (struct telegram *instance, peer_id_t chatid);
};
DECLARE_EVENT_HANDLER (peer_allocated, void);
DECLARE_EVENT_HANDLER (update_user_status, void);
DECLARE_EVENT_HANDLER (update_user_typing, void);
DECLARE_EVENT_HANDLER (update_user_name, peer_t);
DECLARE_EVENT_HANDLER (update_user_photo, peer_t);
DECLARE_EVENT_HANDLER (update_user_registered, peer_t);
DECLARE_EVENT_HANDLER (update_chat_participants, peer_t);
DECLARE_EVENT_HANDLER_3 (update_chat_add_participant, peer_t *, peer_id_t, peer_id_t);
DECLARE_EVENT_HANDLER_3 (update_chat_del_participant, peer_t *, peer_id_t, void *);
DECLARE_EVENT_HANDLER_3 (update_chat_user_typing, peer_t *, peer_t *, void *);
DECLARE_EVENT_HANDLER (update_auth_new, char);
DECLARE_EVENT_HANDLER (update_new_message, struct message);
DECLARE_EVENT_HANDLER (download_finished, struct download);
#define MSG_STORE_SIZE 10000
/**
* A telegram session
*
* Contains all globals from the telegram-cli application is passed to every
* query call
*/
struct telegram {
void *protocol_data;
//int curr_dc;
char *login;
char *config_path;
char *download_path;
char *auth_path;
char *state_path;
char *secret_path;
int session_state;
struct telegram_config *config;
/*
* protocol state
*/
struct protocol_state proto;
struct authorization_state auth;
/*
* connection
*/
struct mtproto_connection *connection;
/*
* binlog
*/
struct binlog *bl;
// TODO: Bind this to the current data center, since the code hash is only
// valid in its context
char *phone_code_hash;
int unread_messages;
long long cur_uploading_bytes;
long long cur_uploaded_bytes;
long long cur_downloading_bytes;
long long cur_downloaded_bytes;
int our_id;
struct tgl_user User;
BN_CTX *ctx;
int encr_root;
unsigned char *encr_prime;
int encr_param_version;
int max_chat_size;
int max_bcast_size;
int want_dc_num;
int new_dc_num;
int out_message_num;
char *suser;
int nearest_dc_num;
int packed_buffer[MAX_PACKED_SIZE / 4];
struct tree_query *queries_tree;
struct tree_timer *timer_tree;
char *export_auth_str;
int export_auth_str_len;
char g_a[256];
// do_get_difference
int get_difference_active;
struct message *ML[MSG_STORE_SIZE];
/*
* All active MtProto connections
*/
int cs;
struct mtproto_connection *Cs[100];
/*
* Downloads
*/
GQueue *dl_queue;
struct download *dl_curr;
/*
* additional user data
*/
void *extra;
};
/**
* Create a new telegram application
*
* @param login The phone number to use as login name
* @param config Contains all callbacks used for the telegram instance
*/
struct telegram *telegram_new(const char* login, struct telegram_config *config);
void telegram_restore_session(struct telegram *instance);
void telegram_store_session(struct telegram *instance);
void telegram_destroy(struct telegram *instance);
/**
* Get the currently active connection
*/
struct connection *telegram_get_connection(struct telegram *instance);
/**
* Return the current working dc
*/
struct dc *telegram_get_working_dc(struct telegram *instance);
/*
* Events
*/
/**
* Change the state of the given telegram instance and execute all event handlers
*
* @param instance The telegram instance that changed its state
* @param state The changed state
* @param data Extra data that depends on switched state
*/
void telegram_change_state(struct telegram *instance, int state, void *data);
/**
* Connect to the telegram network with the given configuration
*/
void telegram_connect(struct telegram *instance);
/**
* Read and process all available input from the network
*/
void mtp_read_input (struct mtproto_connection *mtp);
/**
* Write all available output to the network
*/
int mtp_write_output (struct mtproto_connection *mtp);
/**
* Try to interpret RPC calls and apply the changes to the current telegram state
*/
void try_rpc_interpret(struct telegram *instance, int op, int len);
/**
* Request a registration code
*/
char* network_request_registration();
/**
* Verify the registration with the given registration code
*/
int network_verify_registration(const char *code, const char *sms_hash);
/**
* Verify the registration with the given registration code
*/
int network_verify_phone_registration(const char *code, const char *sms_hash,
const char *first, const char *last);
/*
* Load known users and chats on connect
*/
void event_user_info_received_handler(struct telegram *instance, struct tgl_user *peer, int showInfo);
/**
* Set the connection after a proxy_request_cb
*
* @param fd The file-descriptor of the acquired connection
* @param handle A handle that will be passed back on output and close callbacks
*/
struct mtproto_connection *telegram_add_proxy(struct telegram *tg, struct proxy_request *req, int fd, void *handle);
/**
* Return wether telegram is authenticated with the currently active data center
*/
int telegram_authenticated (struct telegram *instance);
void telegram_flush (struct telegram *instance);
void telegram_dl_add (struct telegram *instance, struct download *dl);
void telegram_dl_next (struct telegram *instance);
#endif

View file

@ -6,4 +6,3 @@ Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+
8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n
Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
-----END RSA PUBLIC KEY-----

584
tgp-net.c Normal file
View file

@ -0,0 +1,584 @@
/*
This file is part of tgl-library
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Copyright Vitaly Valtman 2013-2014
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#define _GNU_SOURCE
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <poll.h>
#include <openssl/rand.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <time.h>
#include "tgp-net.h"
//#include "include.h"
#include <tgl.h>
#include <tgl-inner.h>
//#include "mtproto-client.h"
//#include "mtproto-common.h"
//#include "tree.h"
//#include "tools.h"
#include <glib.h>
#include <eventloop.h>
#include "telegram-purple.h"
#ifndef POLLRDHUP
#define POLLRDHUP 0
#endif
//double get_utime (int clock_id);
//extern struct mtproto_methods auth_methods;
static void fail_connection (struct connection *c);
#define PING_TIMEOUT 10
static void start_ping_timer (struct connection *c);
static int ping_alarm (gpointer arg) {
struct connection *c = arg;
struct tgl_state *TLS = c->TLS;
vlogprintf (E_DEBUG + 2,"ping alarm\n");
assert (c->state == conn_ready || c->state == conn_connecting);
if (tglt_get_double_time () - c->last_receive_time > 6 * PING_TIMEOUT) {
vlogprintf (E_WARNING, "fail connection: reason: ping timeout\n");
c->state = conn_failed;
fail_connection (c);
return FALSE;
} else if (tglt_get_double_time () - c->last_receive_time > 3 * PING_TIMEOUT && c->state == conn_ready) {
tgl_do_send_ping (c->TLS, c);
return TRUE;
} else {
return TRUE;
}
}
static void stop_ping_timer (struct connection *c) {
purple_timeout_remove (c->ping_ev);
}
static void start_ping_timer (struct connection *c) {
c->ping_ev = purple_timeout_add_seconds (PING_TIMEOUT, ping_alarm, c);
}
static void restart_connection (struct connection *c);
static int fail_alarm (gpointer arg) {
struct connection *c = arg;
c->in_fail_timer = 0;
restart_connection (c);
return FALSE;
}
static void start_fail_timer (struct connection *c) {
if (c->in_fail_timer) { return; }
c->in_fail_timer = 1;
c->fail_ev = purple_timeout_add_seconds (10, fail_alarm, c);
}
static struct connection_buffer *new_connection_buffer (int size) {
struct connection_buffer *b = malloc (sizeof (*b));
memset (b, 0, sizeof (*b));
b->start = malloc (size);
b->end = b->start + size;
b->rptr = b->wptr = b->start;
return b;
}
static void delete_connection_buffer (struct connection_buffer *b) {
free (b->start);
free (b);
}
static void conn_try_write (gpointer arg, gint source, PurpleInputCondition cond);
int tgln_write_out (struct connection *c, const void *_data, int len) {
struct tgl_state *TLS = c->TLS;
vlogprintf (E_DEBUG, "write_out: %d bytes\n", len);
const unsigned char *data = _data;
if (!len) { return 0; }
assert (len > 0);
int x = 0;
if (!c->out_bytes) {
assert (c->write_ev == -1);
c->write_ev = purple_input_add (c->fd, PURPLE_INPUT_WRITE, conn_try_write, c);
}
if (!c->out_head) {
struct connection_buffer *b = new_connection_buffer (1 << 20);
c->out_head = c->out_tail = b;
}
while (len) {
if (c->out_tail->end - c->out_tail->wptr >= len) {
memcpy (c->out_tail->wptr, data, len);
c->out_tail->wptr += len;
c->out_bytes += len;
return x + len;
} else {
int y = c->out_tail->end - c->out_tail->wptr;
assert (y < len);
memcpy (c->out_tail->wptr, data, y);
x += y;
len -= y;
data += y;
struct connection_buffer *b = new_connection_buffer (1 << 20);
c->out_tail->next = b;
b->next = 0;
c->out_tail = b;
c->out_bytes += y;
}
}
return x;
}
int tgln_read_in (struct connection *c, void *_data, int len) {
unsigned char *data = _data;
if (!len) { return 0; }
assert (len > 0);
if (len > c->in_bytes) {
len = c->in_bytes;
}
int x = 0;
while (len) {
int y = c->in_head->wptr - c->in_head->rptr;
if (y > len) {
memcpy (data, c->in_head->rptr, len);
c->in_head->rptr += len;
c->in_bytes -= len;
return x + len;
} else {
memcpy (data, c->in_head->rptr, y);
c->in_bytes -= y;
x += y;
data += y;
len -= y;
void *old = c->in_head;
c->in_head = c->in_head->next;
if (!c->in_head) {
c->in_tail = 0;
}
delete_connection_buffer (old);
}
}
return x;
}
int tgln_read_in_lookup (struct connection *c, void *_data, int len) {
unsigned char *data = _data;
if (!len || !c->in_bytes) { return 0; }
assert (len > 0);
if (len > c->in_bytes) {
len = c->in_bytes;
}
int x = 0;
struct connection_buffer *b = c->in_head;
while (len) {
int y = b->wptr - b->rptr;
if (y >= len) {
memcpy (data, b->rptr, len);
return x + len;
} else {
memcpy (data, b->rptr, y);
x += y;
data += y;
len -= y;
b = b->next;
}
}
return x;
}
void tgln_flush_out (struct connection *c) {
}
//#define MAX_CONNECTIONS 100
//static struct connection *Connections[MAX_CONNECTIONS];
//static int max_connection_fd;
static void rotate_port (struct connection *c) {
switch (c->port) {
case 443:
c->port = 80;
break;
case 80:
c->port = 25;
break;
case 25:
c->port = 443;
break;
}
}
static void try_read (struct connection *c);
static void try_write (struct connection *c);
static void conn_try_read (gpointer arg, gint source, PurpleInputCondition cond) {
struct connection *c = arg;
struct tgl_state *TLS = c->TLS;
vlogprintf (E_DEBUG + 1, "Try read. Fd = %d\n", c->fd);
try_read (c);
}
static void conn_try_write (gpointer arg, gint source, PurpleInputCondition cond) {
struct connection *c = arg;
struct tgl_state *TLS = c->TLS;
if (c->state == conn_connecting) {
c->state = conn_ready;
c->methods->ready (TLS, c);
}
try_write (c);
if (!c->out_bytes) {
purple_input_remove (c->write_ev);
c->write_ev = -1;
}
}
static void net_on_connected (gpointer arg, gint fd, const gchar *error_message) {
struct connection *c = arg;
struct tgl_state *TLS = c->TLS;
vlogprintf (E_DEBUG - 2, "connect result: %d\n", fd);
if (fd == -1) {
fail_connection (c);
return;
}
c->fd = fd;
c->read_ev = purple_input_add (fd, PURPLE_INPUT_READ, conn_try_read, c);
char byte = 0xef;
assert (tgln_write_out (c, &byte, 1) == 1);
c->last_receive_time = tglt_get_double_time ();
start_ping_timer (c);
}
struct connection *tgln_create_connection (struct tgl_state *TLS, const char *host, int port, struct tgl_session *session, struct tgl_dc *dc, struct mtproto_methods *methods) {
struct connection *c = malloc (sizeof (*c));
memset (c, 0, sizeof (*c));
c->TLS = TLS;
c->fd = -1;
c->state = conn_connecting;
c->last_receive_time = tglt_get_double_time ();
c->ip = strdup (host);
c->flags = 0;
c->port = port;
c->ping_ev = -1;
c->fail_ev = -1;
c->write_ev = -1;
c->read_ev = -1;
c->dc = dc;
c->session = session;
c->methods = methods;
telegram_conn *conn = TLS->ev_base;
c->prpl_data = purple_proxy_connect (conn->gc, conn->pa, host, port, net_on_connected, c);
return c;
}
static void restart_connection (struct connection *c) {
struct tgl_state *TLS = c->TLS;
if (c->last_connect_time == time (0)) {
start_fail_timer (c);
return;
}
telegram_conn *conn = TLS->ev_base;
c->prpl_data = purple_proxy_connect (conn->gc, conn->pa, c->ip, c->port, net_on_connected, c);
}
static void fail_connection (struct connection *c) {
struct tgl_state *TLS = c->TLS;
if (c->state == conn_ready) {
stop_ping_timer (c);
}
if (c->write_ev >= 0) {
purple_input_remove (c->write_ev);
c->write_ev = -1;
}
if (c->read_ev >= 0) {
purple_input_remove (c->write_ev);
c->read_ev = -1;
}
rotate_port (c);
struct connection_buffer *b = c->out_head;
while (b) {
struct connection_buffer *d = b;
b = b->next;
delete_connection_buffer (d);
}
b = c->in_head;
while (b) {
struct connection_buffer *d = b;
b = b->next;
delete_connection_buffer (d);
}
c->out_head = c->out_tail = c->in_head = c->in_tail = 0;
c->state = conn_failed;
c->out_bytes = c->in_bytes = 0;
if (c->state == conn_ready) {
telegram_conn *conn = TLS->ev_base;
purple_connection_error_reason(conn->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, "connection fail");
}
c->prpl_data = NULL; // Did not find any destroy code. What should be done here?
vlogprintf (E_NOTICE, "Lost connection to server... %s:%d\n", c->ip, c->port);
restart_connection (c);
}
//extern FILE *log_net_f;
static void try_write (struct connection *c) {
struct tgl_state *TLS = c->TLS;
vlogprintf (E_DEBUG, "try write: fd = %d\n", c->fd);
int x = 0;
while (c->out_head) {
int r = write (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr);
if (r >= 0) {
x += r;
c->out_head->rptr += r;
if (c->out_head->rptr != c->out_head->wptr) {
break;
}
struct connection_buffer *b = c->out_head;
c->out_head = b->next;
if (!c->out_head) {
c->out_tail = 0;
}
delete_connection_buffer (b);
} else {
if (errno != EAGAIN && errno != EWOULDBLOCK) {
vlogprintf (E_NOTICE, "fail_connection: write_error %m\n");
fail_connection (c);
return;
} else {
break;
}
}
}
vlogprintf (E_DEBUG, "Sent %d bytes to %d\n", x, c->fd);
c->out_bytes -= x;
}
static void try_rpc_read (struct connection *c) {
assert (c->in_head);
struct tgl_state *TLS = c->TLS;
while (1) {
if (c->in_bytes < 1) { return; }
unsigned len = 0;
unsigned t = 0;
assert (tgln_read_in_lookup (c, &len, 1) == 1);
if (len >= 1 && len <= 0x7e) {
if (c->in_bytes < (int)(1 + 4 * len)) { return; }
} else {
if (c->in_bytes < 4) { return; }
assert (tgln_read_in_lookup (c, &len, 4) == 4);
len = (len >> 8);
if (c->in_bytes < (int)(4 + 4 * len)) { return; }
len = 0x7f;
}
if (len >= 1 && len <= 0x7e) {
assert (tgln_read_in (c, &t, 1) == 1);
assert (t == len);
assert (len >= 1);
} else {
assert (len == 0x7f);
assert (tgln_read_in (c, &len, 4) == 4);
len = (len >> 8);
assert (len >= 1);
}
len *= 4;
int op;
assert (tgln_read_in_lookup (c, &op, 4) == 4);
c->methods->execute (TLS, c, op, len);
}
}
static void try_read (struct connection *c) {
struct tgl_state *TLS = c->TLS;
vlogprintf (E_DEBUG, "try read: fd = %d\n", c->fd);
if (!c->in_tail) {
c->in_head = c->in_tail = new_connection_buffer (1 << 20);
}
#ifdef EVENT_V1
struct timeval tv = {5, 0};
event_add (c->read_ev, &tv);
#endif
int x = 0;
while (1) {
int r = read (c->fd, c->in_tail->wptr, c->in_tail->end - c->in_tail->wptr);
if (r > 0) {
c->last_receive_time = tglt_get_double_time ();
stop_ping_timer (c);
start_ping_timer (c);
}
if (r >= 0) {
c->in_tail->wptr += r;
x += r;
if (c->in_tail->wptr != c->in_tail->end) {
break;
}
struct connection_buffer *b = new_connection_buffer (1 << 20);
c->in_tail->next = b;
c->in_tail = b;
} else {
if (errno != EAGAIN && errno != EWOULDBLOCK) {
vlogprintf (E_NOTICE, "fail_connection: read_error %m\n");
fail_connection (c);
return;
} else {
break;
}
}
}
vlogprintf (E_DEBUG, "Received %d bytes from %d\n", x, c->fd);
c->in_bytes += x;
if (x) {
try_rpc_read (c);
}
}
/*
int tgl_connections_make_poll_array (struct pollfd *fds, int max) {
int _max = max;
int i;
for (i = 0; i <= max_connection_fd; i++) {
if (Connections[i] && Connections[i]->state == conn_failed) {
restart_connection (Connections[i]);
}
if (Connections[i] && Connections[i]->state != conn_failed) {
assert (max > 0);
struct connection *c = Connections[i];
fds[0].fd = c->fd;
fds[0].events = POLLERR | POLLHUP | POLLRDHUP | POLLIN;
if (c->out_bytes || c->state == conn_connecting) {
fds[0].events |= POLLOUT;
}
fds ++;
max --;
}
}
return _max - max;
}
void tgl_connections_poll_result (struct pollfd *fds, int max) {
int i;
for (i = 0; i < max; i++) {
struct connection *c = Connections[fds[i].fd];
if (fds[i].revents & POLLIN) {
try_read (c);
}
if (fds[i].revents & (POLLHUP | POLLERR | POLLRDHUP)) {
vlogprintf (E_NOTICE, "fail_connection: events_mask=0x%08x\n", fds[i].revents);
fail_connection (c);
} else if (fds[i].revents & POLLOUT) {
if (c->state == conn_connecting) {
vlogprintf (E_DEBUG, "connection ready\n");
c->state = conn_ready;
c->last_receive_time = tglt_get_double_time ();
}
if (c->out_bytes) {
try_write (c);
}
}
}
}*/
static void incr_out_packet_num (struct connection *c) {
c->out_packet_num ++;
}
static struct tgl_dc *get_dc (struct connection *c) {
return c->dc;
}
static struct tgl_session *get_session (struct connection *c) {
return c->session;
}
static void tgln_free (struct connection *c) {
if (c->ip) { free (c->ip); }
struct connection_buffer *b = c->out_head;
while (b) {
struct connection_buffer *d = b;
b = b->next;
delete_connection_buffer (d);
}
b = c->in_head;
while (b) {
struct connection_buffer *d = b;
b = b->next;
delete_connection_buffer (d);
}
if (c->ping_ev >= 0) {
purple_timeout_remove (c->ping_ev);
c->ping_ev = -1;
}
if (c->fail_ev >= 0) {
purple_timeout_remove (c->fail_ev);
c->fail_ev = -1;
}
if (c->read_ev >= 0) {
purple_input_remove (c->read_ev);
}
if (c->write_ev >= 0) {
purple_input_remove (c->write_ev);
}
c->fd = -1;
}
struct tgl_net_methods tgp_conn_methods = {
.write_out = tgln_write_out,
.read_in = tgln_read_in,
.read_in_lookup = tgln_read_in_lookup,
.flush_out = tgln_flush_out,
.incr_out_packet_num = incr_out_packet_num,
.get_dc = get_dc,
.get_session = get_session,
.create_connection = tgln_create_connection,
.free = tgln_free
};

88
tgp-net.h Normal file
View file

@ -0,0 +1,88 @@
/*
This file is part of tgl-library
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Copyright Vitaly Valtman 2013-2014
*/
#ifndef __NET_H__
#define __NET_H__
struct connection_buffer {
unsigned char *start;
unsigned char *end;
unsigned char *rptr;
unsigned char *wptr;
struct connection_buffer *next;
};
enum conn_state {
conn_none,
conn_connecting,
conn_ready,
conn_failed,
conn_stopped
};
struct connection {
int fd;
char *ip;
int port;
int flags;
enum conn_state state;
int ipv6[4];
struct connection_buffer *in_head;
struct connection_buffer *in_tail;
struct connection_buffer *out_head;
struct connection_buffer *out_tail;
int in_bytes;
int out_bytes;
int packet_num;
int out_packet_num;
int last_connect_time;
int in_fail_timer;
struct mtproto_methods *methods;
struct tgl_state *TLS;
struct tgl_session *session;
struct tgl_dc *dc;
void *extra;
int ping_ev;
int fail_ev;
int read_ev;
int write_ev;
double last_receive_time;
void *prpl_data;
};
//extern struct connection *Connections[];
int tgln_write_out (struct connection *c, const void *data, int len);
void tgln_flush_out (struct connection *c);
int tgln_read_in (struct connection *c, void *data, int len);
int tgln_read_in_lookup (struct connection *c, void *data, int len);
//void tgln_insert_msg_id (struct tgl_session *S, long long id);
extern struct tgl_net_methods tgp_conn_methods;
//void create_all_outbound_connections (void);
//struct connection *create_connection (const char *host, int port, struct tgl_session *session, struct connection_methods *methods);
//struct tgl_dc *tgln_alloc_dc (int id, char *ip, int port);
//void tgln_dc_create_session (struct tgl_dc *DC, struct mtproto_methods *methods);
struct connection *tgln_create_connection (struct tgl_state *TLS, const char *host, int port, struct tgl_session *session, struct tgl_dc *dc, struct mtproto_methods *methods);
#define GET_DC(c) (c->session->dc)
#endif

75
tgp-timers.c Normal file
View file

@ -0,0 +1,75 @@
/*
This file is part of tgl-library
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Copyright Vitaly Valtman 2013-2014
*/
#include <tgl.h>
#include <stdlib.h>
#include <glib.h>
#include <eventloop.h>
struct tgl_timer {
struct tgl_state *TLS;
void (*cb)(struct tgl_state *, void *);
void *arg;
int fd;
};
static int timer_alarm (gpointer arg) {
struct tgl_timer *t = arg;
t->cb (t->TLS, t->arg);
return FALSE;
}
static struct tgl_timer *tgl_timer_alloc (struct tgl_state *TLS, void (*cb)(struct tgl_state *TLS, void *arg), void *arg) {
struct tgl_timer *t = malloc (sizeof (*t));
t->TLS = TLS;
t->cb = cb;
t->arg = arg;
t->fd = -1;
return t;
}
static void tgl_timer_insert (struct tgl_timer *t, double p) {
if (p < 0) { p = 0; }
if (p < 1) {
t->fd = purple_timeout_add (1000 * p, timer_alarm, t);
} else {
t->fd = purple_timeout_add_seconds (p, timer_alarm, t);
}
}
static void tgl_timer_delete (struct tgl_timer *t) {
if (t->fd >= 0) {
purple_timeout_remove (t->fd);
t->fd = -1;
}
}
static void tgl_timer_free (struct tgl_timer *t) {
if (t->fd >= 0) {
tgl_timer_delete (t);
}
free (t);
}
struct tgl_timer_methods tgp_timers = {
.alloc = tgl_timer_alloc,
.insert = tgl_timer_insert,
.delete = tgl_timer_delete,
.free = tgl_timer_free
};

27
tgp-timers.h Normal file
View file

@ -0,0 +1,27 @@
/*
This file is part of tgl-library
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Copyright Vitaly Valtman 2013-2014
*/
#ifndef __TGL_TIMERS_H__
#define __TGL_TIMERS_H__
#include "tgl.h"
extern struct tgl_timer_methods tgp_timers;
#endif

259
tools.c
View file

@ -1,259 +0,0 @@
/*
This file is part of telegram-client.
Telegram-client 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.
Telegram-client 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 telegram-client. If not, see <http://www.gnu.org/licenses/>.
Copyright Vitaly Valtman 2013
*/
#define _GNU_SOURCE
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/err.h>
#include <zlib.h>
#include "tools.h"
#include "msglog.h"
#ifdef DEBUG
#define RES_PRE 8
#define RES_AFTER 8
#define MAX_BLOCKS 1000000
void *blocks[MAX_BLOCKS];
void *free_blocks[MAX_BLOCKS];
int used_blocks;
int free_blocks_cnt;
#endif
extern int verbosity;
long long total_allocated_bytes;
static void out_of_memory (void) {
fprintf (stderr, "Out of memory\n");
exit (1);
}
int tsnprintf (char *buf, int len, const char *format, ...) {
va_list ap;
va_start (ap, format);
int r = vsnprintf (buf, len, format, ap);
va_end (ap);
assert (r <= len && "tsnprintf buffer overflow");
return r;
}
int tasprintf (char **res, const char *format, ...) {
va_list ap;
va_start (ap, format);
int r = vasprintf (res, format, ap);
assert (r >= 0);
va_end (ap);
void *rs = talloc (strlen (*res) + 1);
memcpy (rs, *res, strlen (*res) + 1);
free (*res);
*res = rs;
return r;
}
void print_backtrace (void);
void tfree (void *ptr, int size __attribute__ ((unused))) {
#ifdef DEBUG
total_allocated_bytes -= size;
ptr -= RES_PRE;
if (size != (int)((*(int *)ptr) ^ 0xbedabeda)) {
debug ("size = %d, ptr = %d\n", size, (*(int *)ptr) ^ 0xbedabeda);
}
assert (*(int *)ptr == (int)((size) ^ 0xbedabeda));
assert (*(int *)(ptr + RES_PRE + size) == (int)((size) ^ 0x7bed7bed));
assert (*(int *)(ptr + 4) == size);
int block_num = *(int *)(ptr + 4 + RES_PRE + size);
if (block_num >= used_blocks) {
debug ("block_num = %d, used = %d\n", block_num, used_blocks);
}
assert (block_num < used_blocks);
if (block_num < used_blocks - 1) {
void *p = blocks[used_blocks - 1];
int s = (*(int *)p) ^ 0xbedabeda;
*(int *)(p + 4 + RES_PRE + s) = block_num;
blocks[block_num] = p;
}
blocks[--used_blocks] = 0;
memset (ptr, 0, size + RES_PRE + RES_AFTER);
*(int *)ptr = size + 12;
free_blocks[free_blocks_cnt ++] = ptr;
#else
free (ptr);
#endif
}
void tfree_str (void *ptr) {
if (!ptr) { return; }
tfree (ptr, strlen (ptr) + 1);
}
void tfree_secure (void *ptr, int size) {
memset (ptr, 0, size);
tfree (ptr, size);
}
void *trealloc (void *ptr, size_t old_size __attribute__ ((unused)), size_t size) {
#ifdef DEBUG
void *p = talloc (size);
memcpy (p, ptr, size >= old_size ? old_size : size);
tfree (ptr, old_size);
return p;
#else
void *p = realloc (ptr, size);
ensure_ptr (p);
return p;
#endif
}
void *talloc (size_t size) {
#ifdef DEBUG
total_allocated_bytes += size;
void *p = malloc (size + RES_PRE + RES_AFTER);
ensure_ptr (p);
*(int *)p = size ^ 0xbedabeda;
*(int *)(p + 4) = size;
*(int *)(p + RES_PRE + size) = size ^ 0x7bed7bed;
*(int *)(p + RES_AFTER + 4 + size) = used_blocks;
blocks[used_blocks ++] = p;
return p + 8;
#else
void *p = malloc (size);
ensure_ptr (p);
return p;
#endif
}
void *talloc0 (size_t size) {
void *p = talloc (size);
memset (p, 0, size);
return p;
}
char *tstrdup (const char *s) {
#ifdef DEBUG
int l = strlen (s);
char *p = talloc (l + 1);
memcpy (p, s, l + 1);
return p;
#else
char *p = strdup (s);
if (p == NULL) {
out_of_memory ();
}
return p;
#endif
}
char *tstrndup (const char *s, size_t n) {
#ifdef DEBUG
size_t l = 0;
for (l = 0; l < n && s[l]; l++) { }
char *p = talloc (l + 1);
memcpy (p, s, l);
p[l] = 0;
return p;
#else
char *p = strndup (s, n);
if (p == NULL) {
out_of_memory ();
}
return p;
#endif
}
void ensure (int r) {
if (!r) {
debug ("Open SSL error\n");
ERR_print_errors_fp (stderr);
assert (0);
}
}
void ensure_ptr (void *p) {
if (p == NULL) {
out_of_memory ();
}
}
int tinflate (void *input, int ilen, void *output, int olen) {
z_stream strm;
memset (&strm, 0, sizeof (strm));
assert (inflateInit2 (&strm, 16 + MAX_WBITS) == Z_OK);
strm.avail_in = ilen;
strm.next_in = input;
strm.avail_out = olen ;
strm.next_out = output;
int err = inflate (&strm, Z_FINISH), total_out = 0;
if (err == Z_OK || err == Z_STREAM_END) {
total_out = (int) strm.total_out;
if (err == Z_STREAM_END && verbosity >= 2) {
debug ( "inflated %d bytes\n", (int) strm.total_out);
}
}
if (err != Z_STREAM_END) {
debug ( "inflate error = %d\n", err);
debug ( "inflated %d bytes\n", (int) strm.total_out);
}
inflateEnd (&strm);
return total_out;
}
#ifdef DEBUG
void tcheck (void) {
int i;
for (i = 0; i < used_blocks; i++) {
void *ptr = blocks[i];
int size = (*(int *)ptr) ^ 0xbedabeda;
assert (*(int *)(ptr + 4) == size);
assert (*(int *)(ptr + RES_PRE + size) == (size ^ 0x7bed7bed));
assert (*(int *)(ptr + RES_PRE + 4 + size) == i);
}
for (i = 0; i < free_blocks_cnt; i++) {
void *ptr = free_blocks[i];
int l = *(int *)ptr;
int j = 0;
for (j = 0; j < l; j++) {
if (*(char *)(ptr + 4 + j)) {
hexdump (ptr + 8, ptr + 8 + l + ((-l) & 3));
debug ("Used freed memory size = %d. ptr = %p\n", l + 4 - RES_PRE - RES_AFTER, ptr);
assert (0);
}
}
}
debug ("ok. Used_blocks = %d. Free blocks = %d\n", used_blocks, free_blocks_cnt);
}
void texists (void *ptr, int size) {
ptr -= RES_PRE;
if (size != (int)((*(int *)ptr) ^ 0xbedabeda)) {
debug ("size = %d, ptr = %d\n", size, (*(int *)ptr) ^ 0xbedabeda);
}
assert (*(int *)ptr == (int)((size) ^ 0xbedabeda));
assert (*(int *)(ptr + RES_PRE + size) == (int)((size) ^ 0x7bed7bed));
assert (*(int *)(ptr + 4) == size);
int block_num = *(int *)(ptr + 4 + RES_PRE + size);
if (block_num >= used_blocks) {
debug ("block_num = %d, used = %d\n", block_num, used_blocks);
}
assert (block_num < used_blocks);
}
#endif

43
tools.h
View file

@ -1,43 +0,0 @@
/*
This file is part of telegram-client.
Telegram-client 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.
Telegram-client 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 telegram-client. If not, see <http://www.gnu.org/licenses/>.
Copyright Vitaly Valtman 2013
*/
#pragma once
void *talloc (size_t size);
void *trealloc (void *ptr, size_t old_size, size_t size);
void *talloc0 (size_t size);
char *tstrdup (const char *s);
char *tstrndup (const char *s, size_t n);
//char *stradd(const char *, ...);
int tinflate (void *input, int ilen, void *output, int olen);
void ensure (int r);
void ensure_ptr (void *p);
void tfree (void *ptr, int size);
void tfree_str (void *ptr);
void tfree_secure (void *ptr, int size);
int tsnprintf (char *buf, int len, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
int tasprintf (char **res, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
#ifdef DEBUG
void tcheck (void);
void texists (void *ptr, int size);
#endif

157
tree.h
View file

@ -1,157 +0,0 @@
/*
This file is part of telegram-client.
Telegram-client 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.
Telegram-client 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 telegram-client. If not, see <http://www.gnu.org/licenses/>.
Copyright Vitaly Valtman 2013
*/
#ifndef __TREE_H__
#define __TREE_H__
#include <stdio.h>
#include <memory.h>
#include <tools.h>
#include <assert.h>
#pragma pack(push,4)
#define DEFINE_TREE(X_NAME, X_TYPE, X_CMP, X_UNSET) \
struct tree_ ## X_NAME { \
struct tree_ ## X_NAME *left, *right;\
X_TYPE x;\
int y;\
};\
\
struct tree_ ## X_NAME *new_tree_node_ ## X_NAME (X_TYPE x, int y) {\
struct tree_ ## X_NAME *T = talloc (sizeof (*T));\
T->x = x;\
T->y = y;\
T->left = T->right = 0;\
return T;\
}\
\
void delete_tree_node_ ## X_NAME (struct tree_ ## X_NAME *T) {\
tfree (T, sizeof (*T));\
}\
\
void tree_split_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, struct tree_ ## X_NAME **L, struct tree_ ## X_NAME **R) {\
if (!T) {\
*L = *R = 0;\
} else {\
int c = X_CMP (x, T->x);\
if (c < 0) {\
tree_split_ ## X_NAME (T->left, x, L, &T->left);\
*R = T;\
} else {\
tree_split_ ## X_NAME (T->right, x, &T->right, R);\
*L = T;\
}\
}\
}\
\
struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, int y) __attribute__ ((warn_unused_result));\
struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, int y) {\
if (!T) {\
return new_tree_node_ ## X_NAME (x, y);\
} else {\
if (y > T->y) {\
struct tree_ ## X_NAME *N = new_tree_node_ ## X_NAME (x, y);\
tree_split_ ## X_NAME (T, x, &N->left, &N->right);\
return N;\
} else {\
int c = X_CMP (x, T->x);\
assert (c);\
if (c < 0) { \
T->left = tree_insert_ ## X_NAME (T->left, x, y);\
} else { \
T->right = tree_insert_ ## X_NAME (T->right, x, y);\
} \
return T; \
}\
}\
}\
\
struct tree_ ## X_NAME *tree_merge_ ## X_NAME (struct tree_ ## X_NAME *L, struct tree_ ## X_NAME *R) {\
if (!L || !R) {\
return L ? L : R;\
} else {\
if (L->y > R->y) {\
L->right = tree_merge_ ## X_NAME (L->right, R);\
return L;\
} else {\
R->left = tree_merge_ ## X_NAME (L, R->left);\
return R;\
}\
}\
}\
\
struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) __attribute__ ((warn_unused_result));\
struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\
assert (T);\
int c = X_CMP (x, T->x);\
if (!c) {\
struct tree_ ## X_NAME *N = tree_merge_ ## X_NAME (T->left, T->right);\
delete_tree_node_ ## X_NAME (T);\
return N;\
} else {\
if (c < 0) { \
T->left = tree_delete_ ## X_NAME (T->left, x); \
} else { \
T->right = tree_delete_ ## X_NAME (T->right, x); \
} \
return T; \
}\
}\
\
X_TYPE tree_get_min_ ## X_NAME (struct tree_ ## X_NAME *T) {\
if (!T) { return X_UNSET; } \
while (T->left) { T = T->left; }\
return T->x; \
} \
\
X_TYPE tree_lookup_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\
int c;\
while (T && (c = X_CMP (x, T->x))) {\
T = (c < 0 ? T->left : T->right);\
}\
return T ? T->x : X_UNSET;\
}\
\
void tree_act_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE)) {\
if (!T) { return; } \
tree_act_ ## X_NAME (T->left, act); \
act (T->x); \
tree_act_ ## X_NAME (T->right, act); \
}\
\
int tree_count_ ## X_NAME (struct tree_ ## X_NAME *T) { \
if (!T) { return 0; }\
return 1 + tree_count_ ## X_NAME (T->left) + tree_count_ ## X_NAME (T->right); \
}\
void tree_check_ ## X_NAME (struct tree_ ## X_NAME *T) { \
if (!T) { return; }\
if (T->left) { \
assert (T->left->y <= T->y);\
assert (X_CMP (T->left->x, T->x) < 0); \
}\
if (T->right) { \
assert (T->right->y <= T->y);\
assert (X_CMP (T->right->x, T->x) > 0); \
}\
tree_check_ ## X_NAME (T->left); \
tree_check_ ## X_NAME (T->right); \
}\
#define int_cmp(a,b) ((a) - (b))
#pragma pack(pop)
#endif