From f46c685bbd15a538d2c6bd41882fb04a5e27550a Mon Sep 17 00:00:00 2001 From: Vysheng Date: Tue, 11 Nov 2014 20:29:09 +0300 Subject: [PATCH] Rewritten to use libtgl --- .gitignore | 21 - .travis.yml | 12 - LICENSE | 339 -- LICENSE.h | 339 -- Makefile | 43 +- README.md | 15 +- binlog.c | 1686 --------- binlog.h | 150 - binlog.tl | 10 - constants.h | 383 -- gen_constants_h.awk | 37 - {purple-plugin => imgs}/telegram.png | Bin {purple-plugin => imgs}/telegram16.png | Bin {purple-plugin => imgs}/telegram22.png | Bin {purple-plugin => imgs}/telegram48.png | Bin include.h | 24 - loop.c | 350 -- loop.h | 79 - msglog.c | 4 +- mtproto-client.c | 1735 --------- mtproto-client.h | 514 --- mtproto-common.c | 357 -- net.c | 549 --- net.h | 163 - no-preview.h | 105 - purple-plugin/telegram.svg | 177 - queries.c | 3095 ----------------- queries.h | 161 - structures.c | 2090 ----------- structures.h | 423 --- telegram-base.c | 372 ++ telegram-base.h | 9 + .../telegram-purple.c => telegram-purple.c | 801 ++--- .../telegram-purple.h => telegram-purple.h | 79 +- telegram.c | 480 --- telegram.h | 484 --- tg-server.pub | 1 - tgp-net.c | 584 ++++ tgp-net.h | 88 + tgp-timers.c | 75 + tgp-timers.h | 27 + tools.c | 259 -- tools.h | 43 - tree.h | 157 - 44 files changed, 1506 insertions(+), 14814 deletions(-) delete mode 100644 .gitignore delete mode 100644 .travis.yml delete mode 100644 LICENSE delete mode 100644 LICENSE.h delete mode 100644 binlog.c delete mode 100644 binlog.h delete mode 100644 binlog.tl delete mode 100644 constants.h delete mode 100644 gen_constants_h.awk rename {purple-plugin => imgs}/telegram.png (100%) rename {purple-plugin => imgs}/telegram16.png (100%) rename {purple-plugin => imgs}/telegram22.png (100%) rename {purple-plugin => imgs}/telegram48.png (100%) delete mode 100644 include.h delete mode 100644 loop.c delete mode 100644 loop.h delete mode 100644 mtproto-client.c delete mode 100644 mtproto-client.h delete mode 100644 mtproto-common.c delete mode 100644 net.c delete mode 100644 net.h delete mode 100644 no-preview.h delete mode 100644 purple-plugin/telegram.svg delete mode 100644 queries.c delete mode 100644 queries.h delete mode 100644 structures.c delete mode 100644 structures.h create mode 100644 telegram-base.c create mode 100644 telegram-base.h rename purple-plugin/telegram-purple.c => telegram-purple.c (57%) rename purple-plugin/telegram-purple.h => telegram-purple.h (58%) delete mode 100755 telegram.c delete mode 100644 telegram.h create mode 100644 tgp-net.c create mode 100644 tgp-net.h create mode 100644 tgp-timers.c create mode 100644 tgp-timers.h delete mode 100644 tools.c delete mode 100644 tools.h delete mode 100644 tree.h diff --git a/.gitignore b/.gitignore deleted file mode 100644 index d9775cd..0000000 --- a/.gitignore +++ /dev/null @@ -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/* diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 915d880..0000000 --- a/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -language: c - -compiler: - - gcc - - clang - -install: - - sudo apt-get install libssl-dev libglib2.0-dev libpurple-dev - -script: - - ./configure - - make diff --git a/LICENSE b/LICENSE deleted file mode 100644 index d159169..0000000 --- a/LICENSE +++ /dev/null @@ -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. - - - Copyright (C) - - 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. - - , 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. diff --git a/LICENSE.h b/LICENSE.h deleted file mode 100644 index 0dcf708..0000000 --- a/LICENSE.h +++ /dev/null @@ -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" -" \n" -" Copyright (C) \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" -" , 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" diff --git a/Makefile b/Makefile index c85fe48..c66802c 100644 --- a/Makefile +++ b/Makefile @@ -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: diff --git a/README.md b/README.md index 3e4d86c..6ed0288 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/binlog.c b/binlog.c deleted file mode 100644 index e49e655..0000000 --- a/binlog.c +++ /dev/null @@ -1,1686 +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 . - - Copyright Vitaly Valtman 2013 -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "binlog.h" -#include "net.h" -#include "include.h" -#include "mtproto-client.h" -#include "telegram.h" - -#include - -#define MAX_LOG_EVENT_SIZE (1 << 17) - -int binlog_enabled = 0; - -void *alloc_log_event (struct binlog *bl, int l UU) { - return bl->binlog_buffer; -} - -void replay_log_event (struct telegram *instance) { - struct mtproto_connection *self = instance->connection; - struct binlog *bl = instance->bl; - - int *start = bl->rptr; - bl->in_replay_log = 1; - assert (bl->rptr < bl->wptr); - int op = *bl->rptr; - - if (verbosity >= 2) { - debug ("log_pos %lld, op 0x%08x\n", bl->binlog_pos, op); - } - - self->in_ptr = bl->rptr; - self->in_end = bl->wptr; - switch (op) { - case LOG_START: - bl->rptr ++; - break; - case CODE_binlog_dc_option: - self->in_ptr ++; - { - int id = fetch_int (self); - int l1 = prefetch_strlen (self); - char *name = fetch_str (self, l1); - int l2 = prefetch_strlen (self); - char *ip = fetch_str (self, l2); - int port = fetch_int (self); - debug ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); - alloc_dc (instance->auth.DC_list, id, tstrndup (ip, l2), port); - } - bl->rptr = self->in_ptr; - break; - case LOG_AUTH_KEY: - bl->rptr ++; - { - int num = *(bl->rptr ++); - assert (num >= 0 && num <= MAX_DC_ID); - assert (instance->auth.DC_list[num]); - instance->auth.DC_list[num]->auth_key_id = *(long long *)bl->rptr; - bl->rptr += 2; - memcpy (instance->auth.DC_list[num]->auth_key, bl->rptr, 256); - bl->rptr += 64; - instance->auth.DC_list[num]->flags |= 1; - }; - break; - case LOG_DEFAULT_DC: - bl->rptr ++; - { - int num = *(bl->rptr ++); - assert (num >= 0 && num <= MAX_DC_ID); - instance->auth.dc_working_num = num; - } - break; - case LOG_OUR_ID: - bl->rptr ++; - { - instance->our_id = *(bl->rptr ++); - } - break; - case LOG_DC_SIGNED: - bl->rptr ++; - { - int num = *(bl->rptr ++); - assert (num >= 0 && num <= MAX_DC_ID); - assert (instance->auth.DC_list[num]); - instance->auth.DC_list[num]->has_auth = 1; - } - break; - case LOG_DC_SALT: - bl->rptr ++; - { - int num = *(bl->rptr ++); - assert (num >= 0 && num <= MAX_DC_ID); - assert (instance->auth.DC_list[num]); - instance->auth.DC_list[num]->server_salt = *(long long *)bl->rptr; - bl->rptr += 2; - }; - break; -// case CODE_user_empty: -// case CODE_user_self: -// case CODE_user_contact: -// case CODE_user_request: -// case CODE_user_foreign: - case CODE_user_deleted: - fetch_alloc_user (self); - bl->rptr = self->in_ptr; - break; - case LOG_DH_CONFIG: - get_dh_config_on_answer (0); - bl->rptr = self->in_ptr; - break; - case LOG_ENCR_CHAT_KEY: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - struct secret_chat *U = (void *)user_chat_get (bl, id); - assert (U); - U->key_fingerprint = *(long long *)bl->rptr; - bl->rptr += 2; - memcpy (U->key, bl->rptr, 256); - bl->rptr += 64; - }; - break; - case LOG_ENCR_CHAT_SEND_ACCEPT: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - struct secret_chat *U = (void *)user_chat_get (bl, id); - assert (U); - U->key_fingerprint = *(long long *)bl->rptr; - bl->rptr += 2; - memcpy (U->key, bl->rptr, 256); - bl->rptr += 64; - if (!U->g_key) { - U->g_key = talloc (256); - } - memcpy (U->g_key, bl->rptr, 256); - bl->rptr += 64; - }; - break; - case LOG_ENCR_CHAT_SEND_CREATE: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - struct secret_chat *U = (void *)user_chat_get (bl, id); - assert (!U || !(U->flags & FLAG_CREATED)); - if (!U) { - U = talloc0 (sizeof (peer_t)); - U->id = id; - insert_encrypted_chat (bl, (void *)U); - } - U->flags |= FLAG_CREATED; - U->user_id = *(bl->rptr ++); - memcpy (U->key, bl->rptr, 256); - bl->rptr += 64; - if (!U->print_name) { - peer_t *P = user_chat_get (bl, MK_USER (U->user_id)); - if (P) { - U->print_name = create_print_name (bl, U->id, "!", P->user.first_name, P->user.last_name, 0); - } else { - static char buf[100]; - tsnprintf (buf, 99, "user#%d", U->user_id); - U->print_name = create_print_name (bl, U->id, "!", buf, 0, 0); - } - peer_insert_name (bl, (void *)U); - } - }; - break; - case LOG_ENCR_CHAT_DELETED: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - struct secret_chat *U = (void *)user_chat_get (bl, id); - if (!U) { - U = talloc0 (sizeof (peer_t)); - U->id = id; - insert_encrypted_chat (bl, (void *)U); - } - U->flags |= FLAG_CREATED; - U->state = sc_deleted; - }; - break; - case LOG_ENCR_CHAT_WAITING: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - struct secret_chat *U = (void *)user_chat_get (bl, id); - assert (U); - U->state = sc_waiting; - U->date = *(bl->rptr ++); - U->admin_id = *(bl->rptr ++); - U->user_id = *(bl->rptr ++); - U->access_hash = *(long long *)bl->rptr; - bl->rptr += 2; - }; - break; - case LOG_ENCR_CHAT_REQUESTED: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - struct secret_chat *U = (void *)user_chat_get (bl, id); - if (!U) { - U = talloc0 (sizeof (peer_t)); - U->id = id; - insert_encrypted_chat (bl, (void *)U); - } - U->flags |= FLAG_CREATED; - U->state = sc_request; - U->date = *(bl->rptr ++); - U->admin_id = *(bl->rptr ++); - U->user_id = *(bl->rptr ++); - U->access_hash = *(long long *)bl->rptr; - if (!U->print_name) { - peer_t *P = user_chat_get (bl, MK_USER (U->user_id)); - if (P) { - U->print_name = create_print_name (bl, U->id, "!", P->user.first_name, P->user.last_name, 0); - } else { - static char buf[100]; - tsnprintf (buf, 99, "user#%d", U->user_id); - U->print_name = create_print_name (bl, U->id, "!", buf, 0, 0); - } - peer_insert_name (bl, (void *)U); - } - bl->rptr += 2; - }; - break; - case LOG_ENCR_CHAT_OK: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - struct secret_chat *U = (void *)user_chat_get (bl, id); - assert (U); - U->state = sc_ok; - } - break; - case CODE_binlog_new_user: - self->in_ptr ++; - { - peer_id_t id = MK_USER (fetch_int (self)); - peer_t *_U = user_chat_get (bl, id); - if (!_U) { - _U = talloc0 (sizeof (*_U)); - _U->id = id; - insert_user (bl, _U); - } else { - assert (!(_U->flags & FLAG_CREATED)); - } - struct tgl_user *U = (void *)_U; - U->flags |= FLAG_CREATED; - if (get_peer_id (id) == instance->our_id) { - U->flags |= FLAG_USER_SELF; - } - U->first_name = fetch_str_dup (self); - U->last_name = fetch_str_dup (self); - assert (!U->print_name); - U->print_name = create_print_name (bl, U->id, U->first_name, U->last_name, 0, 0); - peer_insert_name (bl, (void *)U); - U->access_hash = fetch_long (self); - U->phone = fetch_str_dup (self); - if (fetch_int (self)) { - U->flags |= FLAG_USER_CONTACT; - } - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_user_delete: - bl->rptr ++; - { - peer_id_t id = MK_USER (*(bl->rptr ++)); - peer_t *U = user_chat_get (bl, id); - assert (U); - U->flags |= FLAG_DELETED; - } - break; - case CODE_binlog_set_user_access_token: - bl->rptr ++; - { - peer_id_t id = MK_USER (*(bl->rptr ++)); - peer_t *U = user_chat_get (bl, id); - assert (U); - U->user.access_hash = *(long long *)bl->rptr; - bl->rptr += 2; - } - break; - case CODE_binlog_set_user_phone: - self->in_ptr ++; - { - peer_id_t id = MK_USER (fetch_int (self)); - peer_t *U = user_chat_get (bl, id); - assert (U); - if (U->user.phone) { tfree_str (U->user.phone); } - U->user.phone = fetch_str_dup (self); - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_set_user_friend: - bl->rptr ++; - { - peer_id_t id = MK_USER (*(bl->rptr ++)); - peer_t *U = user_chat_get (bl, id); - assert (U); - int friend = *(bl->rptr ++); - if (friend) { U->flags |= FLAG_USER_CONTACT; } - else { U->flags &= ~FLAG_USER_CONTACT; } - } - break; - case CODE_binlog_user_full_photo: - self->in_ptr ++; - { - peer_id_t id = MK_USER (fetch_int (self)); - peer_t *U = user_chat_get (bl, id); - assert (U); - if (U->flags & FLAG_HAS_PHOTO) { - free_photo (&U->user.photo); - } - fetch_photo (self, &U->user.photo); - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_user_blocked: - bl->rptr ++; - { - peer_id_t id = MK_USER (*(bl->rptr ++)); - peer_t *U = user_chat_get (bl, id); - assert (U); - U->user.blocked = *(bl->rptr ++); - } - break; - case CODE_binlog_set_user_full_name: - self->in_ptr ++; - { - peer_id_t id = MK_USER (fetch_int (self)); - peer_t *U = user_chat_get (bl, id); - assert (U); - if (U->user.real_first_name) { tfree_str (U->user.real_first_name); } - if (U->user.real_last_name) { tfree_str (U->user.real_last_name); } - U->user.real_first_name = fetch_str_dup (self); - U->user.real_last_name = fetch_str_dup (self); - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_encr_chat_delete: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - peer_t *_U = user_chat_get (bl, id); - assert (_U); - struct secret_chat *U = &_U->encr_chat; - memset (U->key, 0, sizeof (U->key)); - U->flags |= FLAG_DELETED; - U->state = sc_deleted; - if (U->nonce) { - tfree_secure (U->nonce, 256); - U->nonce = 0; - } - if (U->g_key) { - tfree_secure (U->g_key, 256); - U->g_key = 0; - } - } - break; - case CODE_binlog_encr_chat_requested: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - peer_t *_U = user_chat_get (bl, id); - if (!_U) { - _U = talloc0 (sizeof (*_U)); - _U->id = id; - insert_encrypted_chat (bl, _U); - } else { - assert (!(_U->flags & FLAG_CREATED)); - } - struct secret_chat *U = (void *)_U; - U->access_hash = *(long long *)bl->rptr; - bl->rptr += 2; - U->date = *(bl->rptr ++); - U->admin_id = *(bl->rptr ++); - U->user_id = *(bl->rptr ++); - - peer_t *Us = user_chat_get (bl, MK_USER (U->user_id)); - assert (!U->print_name); - if (Us) { - U->print_name = create_print_name (bl, id, "!", Us->user.first_name, Us->user.last_name, 0); - } else { - static char buf[100]; - tsnprintf (buf, 99, "user#%d", U->user_id); - U->print_name = create_print_name (bl, id, "!", buf, 0, 0); - } - peer_insert_name (bl, (void *)U); - U->g_key = talloc (256); - U->nonce = talloc (256); - memcpy (U->g_key, bl->rptr, 256); - bl->rptr += 64; - memcpy (U->nonce, bl->rptr, 256); - bl->rptr += 64; - - U->flags |= FLAG_CREATED; - U->state = sc_request; - } - break; - case CODE_binlog_set_encr_chat_access_hash: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - peer_t *U = user_chat_get (bl, id); - assert (U); - U->encr_chat.access_hash = *(long long *)bl->rptr; - bl->rptr += 2; - } - break; - case CODE_binlog_set_encr_chat_date: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - peer_t *U = user_chat_get (bl, id); - assert (U); - U->encr_chat.date = *(bl->rptr ++); - } - break; - case CODE_binlog_set_encr_chat_state: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - peer_t *U = user_chat_get (bl, id); - assert (U); - U->encr_chat.state = *(bl->rptr ++); - } - break; - case CODE_binlog_encr_chat_accepted: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - peer_t *_U = user_chat_get (bl, id); - assert (_U); - struct secret_chat *U = &_U->encr_chat; - if (!U->g_key) { - U->g_key = talloc (256); - } - if (!U->nonce) { - U->nonce = talloc (256); - } - memcpy (U->g_key, bl->rptr, 256); - bl->rptr += 64; - memcpy (U->nonce, bl->rptr, 256); - bl->rptr += 64; - U->key_fingerprint = *(long long *)bl->rptr; - bl->rptr += 2; - if (U->state == sc_waiting) { - do_create_keys_end (instance, U); - } - U->state = sc_ok; - } - break; - case CODE_binlog_set_encr_chat_key: - bl->rptr ++; - { - peer_id_t id = MK_ENCR_CHAT (*(bl->rptr ++)); - peer_t *_U = user_chat_get (bl, id); - assert (_U); - struct secret_chat *U = &_U->encr_chat; - memcpy (U->key, bl->rptr, 256); - bl->rptr += 64; - U->key_fingerprint = *(long long *)bl->rptr; - bl->rptr += 2; - } - break; - case CODE_binlog_set_dh_params: - bl->rptr ++; - { - if (instance->encr_prime) { tfree (instance->encr_prime, 256); } - instance->encr_root = *(bl->rptr ++); - instance->encr_prime = talloc (256); - memcpy (instance->encr_prime, bl->rptr, 256); - bl->rptr += 64; - instance->encr_param_version = *(bl->rptr ++); - } - break; - case CODE_binlog_encr_chat_init: - bl->rptr ++; - { - peer_t *P = talloc0 (sizeof (*P)); - P->id = MK_ENCR_CHAT (*(bl->rptr ++)); - assert (!user_chat_get (bl, P->id)); - P->encr_chat.user_id = *(bl->rptr ++); - P->encr_chat.admin_id = instance->our_id; - insert_encrypted_chat (bl, P); - peer_t *Us = user_chat_get (bl, MK_USER (P->encr_chat.user_id)); - assert (Us); - P->print_name = create_print_name (bl, P->id, "!", Us->user.first_name, Us->user.last_name, 0); - peer_insert_name (bl, P); - memcpy (P->encr_chat.key, bl->rptr, 256); - bl->rptr += 64; - P->encr_chat.g_key = talloc (256); - memcpy (P->encr_chat.g_key, bl->rptr, 256); - bl->rptr += 64; - P->flags |= FLAG_CREATED; - } - break; - case CODE_binlog_set_pts: - bl->rptr ++; - instance->proto.pts = *(bl->rptr ++); - break; - case CODE_binlog_set_qts: - bl->rptr ++; - instance->proto.qts = *(bl->rptr ++); - break; - case CODE_binlog_set_date: - bl->rptr ++; - instance->proto.last_date = *(bl->rptr ++); - break; - case CODE_binlog_set_seq: - bl->rptr ++; - instance->proto.seq = *(bl->rptr ++); - break; - case CODE_binlog_chat_create: - self->in_ptr ++; - { - peer_id_t id = MK_CHAT (fetch_int (self)); - peer_t *_C = user_chat_get (bl, id); - if (!_C) { - _C = talloc0 (sizeof (*_C)); - _C->id = id; - insert_chat (bl, _C); - } else { - assert (!(_C->flags & FLAG_CREATED)); - } - struct chat *C = &_C->chat; - C->flags = FLAG_CREATED | fetch_int (self); - C->title = fetch_str_dup (self); - assert (!C->print_title); - C->print_title = create_print_name (bl, id, C->title, 0, 0, 0); - peer_insert_name (bl, (void *)C); - C->users_num = fetch_int (self); - C->date = fetch_int (self); - C->version = fetch_int (self); - fetch_data (self, &C->photo_big, sizeof (struct file_location)); - fetch_data (self, &C->photo_small, sizeof (struct file_location)); - }; - bl->rptr = self->in_ptr; - break; - case CODE_binlog_chat_change_flags: - bl->rptr ++; - { - peer_t *C = user_chat_get (bl, MK_CHAT (*(bl->rptr ++))); - assert (C && (C->flags & FLAG_CREATED)); - C->flags |= *(bl->rptr ++); - C->flags &= ~*(bl->rptr ++); - }; - break; - case CODE_binlog_set_chat_title: - self->in_ptr ++; - { - peer_t *_C = user_chat_get (bl, MK_CHAT (fetch_int (self))); - assert (_C && (_C->flags & FLAG_CREATED)); - struct chat *C = &_C->chat; - if (C->title) { tfree_str (C->title); } - C->title = fetch_str_dup (self); - if (C->print_title) { - peer_delete_name (bl, (void *)C); - tfree_str (C->print_title); - } - C->print_title = create_print_name (bl, C->id, C->title, 0, 0, 0); - peer_insert_name (bl, (void *)C); - }; - bl->rptr = self->in_ptr; - break; - case CODE_binlog_set_chat_photo: - self->in_ptr ++; - { - peer_t *C = user_chat_get (bl, MK_CHAT (fetch_int (self))); - assert (C && (C->flags & FLAG_CREATED)); - fetch_data (self, &C->photo_big, sizeof (struct file_location)); - fetch_data (self, &C->photo_small, sizeof (struct file_location)); - }; - bl->rptr = self->in_ptr; - break; - case CODE_binlog_set_chat_date: - bl->rptr ++; - { - peer_t *C = user_chat_get (bl, MK_CHAT (*(bl->rptr ++))); - assert (C && (C->flags & FLAG_CREATED)); - C->chat.date = *(bl->rptr ++); - }; - break; - case CODE_binlog_set_chat_version: - bl->rptr ++; - { - peer_t *C = user_chat_get (bl, MK_CHAT (*(bl->rptr ++))); - assert (C && (C->flags & FLAG_CREATED)); - C->chat.version = *(bl->rptr ++); - C->chat.users_num = *(bl->rptr ++); - }; - break; - case CODE_binlog_set_chat_admin: - bl->rptr ++; - { - peer_t *C = user_chat_get (bl, MK_CHAT (*(bl->rptr ++))); - assert (C && (C->flags & FLAG_CREATED)); - C->chat.admin_id = *(bl->rptr ++); - }; - break; - case CODE_binlog_set_chat_participants: - bl->rptr ++; - { - peer_t *C = user_chat_get (bl, MK_CHAT (*(bl->rptr ++))); - assert (C && (C->flags & FLAG_CREATED)); - C->chat.user_list_version = *(bl->rptr ++); - if (C->chat.user_list) { tfree (C->chat.user_list, 12 * C->chat.user_list_size); } - C->chat.user_list_size = *(bl->rptr ++); - C->chat.user_list = talloc (12 * C->chat.user_list_size); - memcpy (C->chat.user_list, bl->rptr, 12 * C->chat.user_list_size); - bl->rptr += 3 * C->chat.user_list_size; - }; - break; - case CODE_binlog_chat_full_photo: - self->in_ptr ++; - { - peer_id_t id = MK_CHAT (fetch_int (self)); - peer_t *U = user_chat_get (bl, id); - assert (U && (U->flags & FLAG_CREATED)); - if (U->flags & FLAG_HAS_PHOTO) { - free_photo (&U->chat.photo); - } - fetch_photo (self, &U->chat.photo); - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_add_chat_participant: - bl->rptr ++; - { - peer_id_t id = MK_CHAT (*(bl->rptr ++)); - peer_t *_C = user_chat_get (bl, id); - assert (_C && (_C->flags & FLAG_CREATED)); - struct chat *C = &_C->chat; - - int version = *(bl->rptr ++); - int user = *(bl->rptr ++); - int inviter = *(bl->rptr ++); - int date = *(bl->rptr ++); - assert (C->user_list_version < version); - - int i; - for (i = 0; i < C->user_list_size; i++) { - assert (C->user_list[i].user_id != user); - } - C->user_list_size ++; - C->user_list = trealloc (C->user_list, 12 * C->user_list_size - 12, 12 * C->user_list_size); - C->user_list[C->user_list_size - 1].user_id = user; - C->user_list[C->user_list_size - 1].inviter_id = inviter; - C->user_list[C->user_list_size - 1].date = date; - C->user_list_version = version; - } - break; - case CODE_binlog_del_chat_participant: - bl->rptr ++; - { - peer_id_t id = MK_CHAT (*(bl->rptr ++)); - peer_t *_C = user_chat_get (bl, id); - assert (_C && (_C->flags & FLAG_CREATED)); - struct chat *C = &_C->chat; - - int version = *(bl->rptr ++); - int user = *(bl->rptr ++); - assert (C->user_list_version < version); - - int i; - for (i = 0; i < C->user_list_size; i++) { - if (C->user_list[i].user_id == user) { - struct chat_user t; - t = C->user_list[i]; - C->user_list[i] = C->user_list[C->user_list_size - 1]; - C->user_list[C->user_list_size - 1] = t; - } - } - assert (C->user_list[C->user_list_size - 1].user_id == user); - C->user_list_size --; - C->user_list = trealloc (C->user_list, 12 * C->user_list_size + 12, 12 * C->user_list_size); - C->user_list_version = version; - } - break; - case CODE_binlog_create_message_text: - case CODE_binlog_send_message_text: - self->in_ptr ++; - { - long long id; - if (op == CODE_binlog_create_message_text) { - id = fetch_int (self); - } else { - id = fetch_long (self); - } - struct message *M = message_get(bl, id); - if (!M) { - M = talloc0 (sizeof (*M)); - M->id = id; - M->instance = instance; - message_insert_tree (M); - bl->messages_allocated ++; - event_update_new_message (instance, M); - } else { - assert (!(M->flags & FLAG_CREATED)); - } - M->flags |= FLAG_CREATED; - M->from_id = MK_USER (fetch_int (self)); - int t = fetch_int (self); - if (t == PEER_ENCR_CHAT) { - M->flags |= FLAG_ENCRYPTED; - } - M->to_id = set_peer_id (t, fetch_int (self)); - M->date = fetch_int (self); - - int l = prefetch_strlen (self); - M->message = talloc (l + 1); - memcpy (M->message, fetch_str (self, l), l); - M->message[l] = 0; - M->message_len = l; - - if (t == PEER_ENCR_CHAT) { - M->media.type = CODE_decrypted_message_media_empty; - } else { - M->media.type = CODE_message_media_empty; - } - M->unread = 1; - M->out = get_peer_id (M->from_id) == instance->our_id; - - message_insert (M); - if (op == CODE_binlog_send_message_text) { - message_insert_unsent (M); - M->flags |= FLAG_PENDING; - } - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_create_message_text_fwd: - self->in_ptr ++; - { - int id = fetch_int (self); - struct message *M = message_get(bl, id); - if (!M) { - M = talloc0 (sizeof (*M)); - M->id = id; - message_insert_tree (M); - bl->messages_allocated ++; - } else { - assert (!(M->flags & FLAG_CREATED)); - } - M->flags |= FLAG_CREATED; - M->from_id = MK_USER (fetch_int (self)); - int t = fetch_int (self); - M->to_id = set_peer_id (t, fetch_int (self)); - M->date = fetch_int (self); - M->fwd_from_id = MK_USER (fetch_int (self)); - M->fwd_date = fetch_int (self); - - int l = prefetch_strlen (self); - M->message = talloc (l + 1); - memcpy (M->message, fetch_str (self, l), l); - M->message[l] = 0; - M->message_len = l; - - M->media.type = CODE_message_media_empty; - M->unread = 1; - M->out = get_peer_id (M->from_id) == instance->our_id; - - message_insert (M); - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_create_message_media: - self->in_ptr ++; - { - int id = fetch_int (self); - struct message *M = message_get(bl, id); - if (!M) { - M = talloc0 (sizeof (*M)); - M->id = id; - message_insert_tree (M); - bl->messages_allocated ++; - } else { - assert (!(M->flags & FLAG_CREATED)); - } - M->flags |= FLAG_CREATED; - M->from_id = MK_USER (fetch_int (self)); - int t = fetch_int (self); - M->to_id = set_peer_id (t, fetch_int (self)); - M->date = fetch_int (self); - - int l = prefetch_strlen (self); - M->message = talloc (l + 1); - memcpy (M->message, fetch_str (self, l), l); - M->message[l] = 0; - M->message_len = l; - - fetch_message_media (self, &M->media); - M->unread = 1; - M->out = get_peer_id (M->from_id) == instance->our_id; - - message_insert (M); - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_create_message_media_encr: - self->in_ptr ++; - { - long long id = fetch_long (self); - struct message *M = message_get(bl, id); - if (!M) { - M = talloc0 (sizeof (*M)); - M->id = id; - message_insert_tree (M); - bl->messages_allocated ++; - } else { - assert (!(M->flags & FLAG_CREATED)); - } - M->flags |= FLAG_CREATED | FLAG_ENCRYPTED; - M->from_id = MK_USER (fetch_int (self)); - int t = fetch_int (self); - M->to_id = set_peer_id (t, fetch_int (self)); - M->date = fetch_int (self); - - int l = prefetch_strlen (self); - M->message = talloc (l + 1); - memcpy (M->message, fetch_str (self, l), l); - M->message[l] = 0; - M->message_len = l; - - fetch_message_media_encrypted (self, &M->media); - fetch_encrypted_message_file (self, &M->media); - - M->unread = 1; - M->out = get_peer_id (M->from_id) == instance->our_id; - - message_insert (M); - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_create_message_media_fwd: - self->in_ptr ++; - { - int id = fetch_int (self); - struct message *M = message_get(bl, id); - if (!M) { - M = talloc0 (sizeof (*M)); - M->id = id; - message_insert_tree (M); - bl->messages_allocated ++; - } else { - assert (!(M->flags & FLAG_CREATED)); - } - M->flags |= FLAG_CREATED; - M->from_id = MK_USER (fetch_int (self)); - int t = fetch_int (self); - M->to_id = set_peer_id (t, fetch_int (self)); - M->date = fetch_int (self); - M->fwd_from_id = MK_USER (fetch_int (self)); - M->fwd_date = fetch_int (self); - - int l = prefetch_strlen (self); - M->message = talloc (l + 1); - memcpy (M->message, fetch_str (self, l), l); - M->message[l] = 0; - M->message_len = l; - - fetch_message_media (self, &M->media); - M->unread = 1; - M->out = get_peer_id (M->from_id) == instance->our_id; - - message_insert (M); - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_create_message_service: - self->in_ptr ++; - { - int id = fetch_int (self); - struct message *M = message_get(bl, id); - if (!M) { - M = talloc0 (sizeof (*M)); - M->id = id; - message_insert_tree (M); - bl->messages_allocated ++; - } else { - assert (!(M->flags & FLAG_CREATED)); - } - M->flags |= FLAG_CREATED; - M->from_id = MK_USER (fetch_int (self)); - int t = fetch_int (self); - M->to_id = set_peer_id (t, fetch_int (self)); - M->date = fetch_int (self); - - fetch_message_action (self, &M->action); - M->unread = 1; - M->out = get_peer_id (M->from_id) == instance->our_id; - M->service = 1; - - message_insert (M); - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_create_message_service_encr: - self->in_ptr ++; - { - long long id = fetch_long (self); - struct message *M = message_get(bl, id); - if (!M) { - M = talloc0 (sizeof (*M)); - M->id = id; - message_insert_tree (M); - bl->messages_allocated ++; - } else { - assert (!(M->flags & FLAG_CREATED)); - } - M->flags |= FLAG_CREATED | FLAG_ENCRYPTED; - M->from_id = MK_USER (fetch_int (self)); - int t = fetch_int (self); - M->to_id = set_peer_id (t, fetch_int (self)); - M->date = fetch_int (self); - - fetch_message_action_encrypted (self, &M->action); - - M->unread = 1; - M->out = get_peer_id (M->from_id) == instance->our_id; - M->service = 1; - - message_insert (M); - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_create_message_service_fwd: - self->in_ptr ++; - { - int id = fetch_int (self); - struct message *M = message_get(bl, id); - if (!M) { - M = talloc0 (sizeof (*M)); - M->id = id; - message_insert_tree (M); - bl->messages_allocated ++; - } else { - assert (!(M->flags & FLAG_CREATED)); - } - M->flags |= FLAG_CREATED; - M->from_id = MK_USER (fetch_int (self)); - int t = fetch_int (self); - M->to_id = set_peer_id (t, fetch_int (self)); - M->date = fetch_int (self); - M->fwd_from_id = MK_USER (fetch_int (self)); - M->fwd_date = fetch_int (self); - fetch_message_action (self, &M->action); - M->unread = 1; - M->out = get_peer_id (M->from_id) == instance->our_id; - M->service = 1; - - message_insert (M); - } - bl->rptr = self->in_ptr; - break; - case CODE_binlog_set_unread: - bl->rptr ++; - { - struct message *M = message_get(bl, *(bl->rptr ++)); - assert (M); - M->unread = 0; - } - break; - case CODE_binlog_set_message_sent: - bl->rptr ++; - { - struct message *M = message_get(bl, *(long long *)bl->rptr); - bl->rptr += 2; - assert (M); - message_remove_unsent (M); - M->flags &= ~FLAG_PENDING; - } - break; - case CODE_binlog_set_msg_id: - bl->rptr ++; - { - struct message *M = message_get(bl, *(long long *)bl->rptr); - bl->rptr += 2; - assert (M); - if (M->flags & FLAG_PENDING) { - message_remove_unsent (M); - M->flags &= ~FLAG_PENDING; - } - message_remove_tree (M); - message_del_peer (M); - M->id = *(bl->rptr ++); - if (message_get(bl, M->id)) { - free_message (M); - tfree (M, sizeof (*M)); - } else { - message_insert_tree (M); - message_add_peer (M); - } - } - break; - case CODE_binlog_delete_msg: - bl->rptr ++; - { - struct message *M = message_get(bl, *(long long *)bl->rptr); - bl->rptr += 2; - assert (M); - if (M->flags & FLAG_PENDING) { - message_remove_unsent (M); - M->flags &= ~FLAG_PENDING; - } - message_remove_tree (M); - message_del_peer (M); - message_del_use (M); - free_message (M); - tfree (M, sizeof (*M)); - } - break; - case CODE_update_user_photo: - case CODE_update_user_name: - work_update_binlog (self); - bl->rptr = self->in_ptr; - break; - default: - debug ("Unknown logevent [0x%08x] 0x%08x [0x%08x] at %lld\n", *(bl->rptr - 1), op, *(bl->rptr + 1), bl->binlog_pos); - - assert (0); - } - if (verbosity >= 2) { - debug ("Event end\n"); - } - bl->in_replay_log = 0; - bl->binlog_pos += (bl->rptr - start) * 4; -} - -void add_log_event (struct binlog *bl, struct mtproto_connection *self, const int *data, int len) { - debug ("Add log event: magic = 0x%08x, len = %d\n", data[0], len); - assert (!(len & 3)); - if (bl->in_replay_log) { return; } - bl->rptr = (void *)data; - bl->wptr = bl->rptr + (len / 4); - int *in = self->in_ptr; - int *end = self->in_end; - replay_log_event (self->connection->instance); - if (bl->rptr != bl->wptr) { - debug ("Unread %lld ints. Len = %d\n", (long long)(bl->wptr - bl->rptr), len); - assert (bl->rptr == bl->wptr); - } - if (bl->binlog_enabled) { - assert (bl->binlog_fd > 0); - assert (write (bl->binlog_fd, data, len) == len); - } - self->in_ptr = in; - self->in_end = end; -} - -void bl_do_set_auth_key_id (struct telegram *instance, int num, unsigned char *buf) { - struct mtproto_connection *self = instance->connection; - struct binlog *bl = instance->bl; - - static unsigned char sha1_buffer[20]; - SHA1 (buf, 256, sha1_buffer); - long long fingerprint = *(long long *)(sha1_buffer + 12); - int *ev = alloc_log_event (bl, 8 + 8 + 256); - ev[0] = LOG_AUTH_KEY; - ev[1] = num; - *(long long *)(ev + 2) = fingerprint; - memcpy (ev + 4, buf, 256); - add_log_event (bl, self, ev, 8 + 8 + 256); -} - -void bl_do_set_our_id (struct binlog *bl, struct mtproto_connection *self, int id) { - int *ev = alloc_log_event (bl, 8); - ev[0] = LOG_OUR_ID; - ev[1] = id; - add_log_event (bl, self, ev, 8); -} - -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) { - - clear_packet (self); - out_int (self, CODE_binlog_new_user); - out_int (self, id); - out_cstring (self, f ? f : "", fl); - out_cstring (self, l ? l : "", ll); - out_long (self, access_token); - out_cstring (self, p ? p : "", pl); - out_int (self, contact); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_user_delete (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U) { - if (U->flags & FLAG_DELETED) { return; } - int *ev = alloc_log_event (bl, 8); - ev[0] = CODE_binlog_user_delete; - ev[1] = get_peer_id (U->id); - add_log_event (bl, self, ev, 8); -} - -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) { - if (photo_id == U->photo_id) { return; } - if (!photo_id) { - int *ev = alloc_log_event (bl, 20); - ev[0] = CODE_update_user_photo; - ev[1] = get_peer_id (U->id); - ev[2] = self->connection->instance->proto.last_date; - ev[3] = CODE_user_profile_photo_empty; - ev[4] = CODE_bool_false; - add_log_event (bl, self, ev, 20); - } else { - clear_packet (self); - out_int (self, CODE_update_user_photo); - out_int (self, get_peer_id (U->id)); - out_int (self, self->connection->instance->proto.last_date); - out_int (self, CODE_user_profile_photo); - out_long (self, photo_id); - if (small->dc >= 0) { - out_int (self, CODE_file_location); - out_int (self, small->dc); - out_long (self, small->volume); - out_int (self, small->local_id); - out_long (self, small->secret); - } else { - out_int (self, CODE_file_location_unavailable); - out_long (self, small->volume); - out_int (self, small->local_id); - out_long (self, small->secret); - } - if (big->dc >= 0) { - out_int (self, CODE_file_location); - out_int (self, big->dc); - out_long (self, big->volume); - out_int (self, big->local_id); - out_long (self, big->secret); - } else { - out_int (self, CODE_file_location_unavailable); - out_long (self, big->volume); - out_int (self, big->local_id); - out_long (self, big->secret); - } - out_int (self, CODE_bool_false); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); - } -} - -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) { - if ((U->first_name && (int)strlen (U->first_name) == fl && !strncmp (U->first_name, f, fl)) && - (U->last_name && (int)strlen (U->last_name) == ll && !strncmp (U->last_name, l, ll))) { - return; - } - clear_packet (self); - out_int (self, CODE_update_user_name); - out_int (self, get_peer_id (U->id)); - out_cstring (self, f, fl); - out_cstring (self, l, ll); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_set_user_access_token (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, long long access_token) { - if (U->access_hash == access_token) { return; } - int *ev = alloc_log_event (bl, 16); - ev[0] = CODE_binlog_set_user_access_token; - ev[1] = get_peer_id (U->id); - *(long long *)(ev + 2) = access_token; - add_log_event (bl, self, ev, 16); -} - -void bl_do_set_user_phone (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, -const char *p, int pl) { - if (U->phone && (int)strlen (U->phone) == pl && !strncmp (U->phone, p, pl)) { - return; - } - clear_packet (self); - out_int (self, CODE_binlog_set_user_phone); - out_int (self, get_peer_id (U->id)); - out_cstring (self, p, pl); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_set_user_friend (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, int friend) { - if (friend == ((U->flags & FLAG_USER_CONTACT) != 0)) { return ; } - int *ev = alloc_log_event (bl, 12); - ev[0] = CODE_binlog_set_user_friend; - ev[1] = get_peer_id (U->id); - ev[2] = friend; - add_log_event (bl, self, ev, 12); -} - -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) { - struct dc *DC = instance->auth.DC_list[id]; - if (DC) { return; } - - clear_packet (self); - out_int (self, CODE_binlog_dc_option); - out_int (self, id); - out_cstring (self, name, l1); - out_cstring (self, ip, l2); - out_int (self, port); - - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_dc_signed (struct binlog *bl, struct mtproto_connection *self, int id) { - int *ev = alloc_log_event (bl, 8); - ev[0] = LOG_DC_SIGNED; - ev[1] = id; - add_log_event (bl, self, ev, 8); -} - -void bl_do_set_working_dc (struct binlog *bl, struct mtproto_connection *self, int num) { - int *ev = alloc_log_event (bl, 8); - ev[0] = LOG_DEFAULT_DC; - ev[1] = num; - add_log_event (bl, self, ev, 8); -} - -void bl_do_set_user_full_photo (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, const int *start, int len) { - if (U->photo.id == *(long long *)(start + 1)) { return; } - int *ev = alloc_log_event (bl, len + 8); - ev[0] = CODE_binlog_user_full_photo; - ev[1] = get_peer_id (U->id); - memcpy (ev + 2, start, len); - add_log_event (bl, self, ev, len + 8); -} - -void bl_do_set_user_blocked (struct binlog *bl, struct mtproto_connection *self, struct tgl_user *U, int blocked) { - if (U->blocked == blocked) { return; } - int *ev = alloc_log_event (bl, 12); - ev[0] = CODE_binlog_user_blocked; - ev[1] = get_peer_id (U->id); - ev[2] = blocked; - add_log_event (bl, self, ev, 12); -} - -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) { - if ((U->real_first_name && (int)strlen (U->real_first_name) == fl && !strncmp (U->real_first_name, f, fl)) && - (U->real_last_name && (int)strlen (U->real_last_name) == ll && !strncmp (U->real_last_name, l, ll))) { - return; - } - clear_packet (self); - out_int (self, CODE_binlog_set_user_full_name); - out_int (self, get_peer_id (U->id)); - out_cstring (self, f, fl); - out_cstring (self, l, ll); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_encr_chat_delete (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U) { - if (!(U->flags & FLAG_CREATED) || U->state == sc_deleted || U->state == sc_none) { return; } - int *ev = alloc_log_event (bl, 8); - ev[0] = CODE_binlog_encr_chat_delete; - ev[1] = get_peer_id (U->id); - add_log_event (bl, self, ev, 8); -} - -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[]) { - if (U->state != sc_none) { return; } - int *ev = alloc_log_event (bl, 540); - ev[0] = CODE_binlog_encr_chat_requested; - ev[1] = get_peer_id (U->id); - *(long long *)(ev + 2) = access_hash; - ev[4] = date; - ev[5] = admin_id; - ev[6] = user_id; - memcpy (ev + 7, g_key, 256); - memcpy (ev + 7 + 64, nonce, 256); - add_log_event (bl, self, ev, 540); -} - -void bl_do_set_encr_chat_access_hash (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, - long long access_hash) { - if (U->access_hash == access_hash) { return; } - int *ev = alloc_log_event (bl, 16); - ev[0] = CODE_binlog_set_encr_chat_access_hash; - ev[1] = get_peer_id (U->id); - *(long long *)(ev + 2) = access_hash; - add_log_event (bl, self, ev, 16); -} - -void bl_do_set_encr_chat_date (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, int date) { - if (U->date == date) { return; } - int *ev = alloc_log_event (bl, 12); - ev[0] = CODE_binlog_set_encr_chat_date; - ev[1] = get_peer_id (U->id); - ev[2] = date; - add_log_event (bl, self, ev, 12); -} - -void bl_do_set_encr_chat_state (struct binlog *bl, struct mtproto_connection *self, struct secret_chat *U, enum secret_chat_state state) { - if (U->state == state) { return; } - int *ev = alloc_log_event (bl, 12); - ev[0] = CODE_binlog_set_encr_chat_state; - ev[1] = get_peer_id (U->id); - ev[2] = state; - add_log_event (bl, self, ev, 12); -} - -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) { - if (U->state != sc_waiting && U->state != sc_request) { return; } - int *ev = alloc_log_event (bl, 528); - ev[0] = CODE_binlog_encr_chat_accepted; - ev[1] = get_peer_id (U->id); - memcpy (ev + 2, g_key, 256); - memcpy (ev + 66, nonce, 256); - *(long long *)(ev + 130) = key_fingerprint; - add_log_event (bl, self, ev, 528); -} - -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) { - int *ev = alloc_log_event (bl, 272); - ev[0] = CODE_binlog_set_encr_chat_key; - ev[1] = get_peer_id (E->id); - memcpy (ev + 2, key, 256); - *(long long *)(ev + 66) = key_fingerprint; - add_log_event (bl, self, ev, 272); -} - -void bl_do_set_dh_params (struct binlog *bl, struct mtproto_connection *self, int root, unsigned char prime[], int version) { - int *ev = alloc_log_event (bl, 268); - ev[0] = CODE_binlog_set_dh_params; - ev[1] = root; - memcpy (ev + 2, prime, 256); - ev[66] = version; - add_log_event (bl, self, ev, 268); -} - -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[]) { - int *ev = alloc_log_event (bl, 524); - ev[0] = CODE_binlog_encr_chat_init; - ev[1] = id; - ev[2] = user_id; - memcpy (ev + 3, random, 256); - memcpy (ev + 67, g_a, 256); - add_log_event (bl, self, ev, 524); -} - -void bl_do_set_pts (struct binlog *bl, struct mtproto_connection *self, int pts) { - int *ev = alloc_log_event (bl, 8); - ev[0] = CODE_binlog_set_pts; - ev[1] = pts; - add_log_event (bl, self, ev, 8); -} - -void bl_do_set_qts (struct binlog *bl, struct mtproto_connection *self, int qts) { - int *ev = alloc_log_event (bl, 8); - ev[0] = CODE_binlog_set_qts; - ev[1] = qts; - add_log_event (bl, self, ev, 8); -} - -void bl_do_set_date (struct binlog *bl, struct mtproto_connection *self, int date) { - int *ev = alloc_log_event (bl, 8); - ev[0] = CODE_binlog_set_date; - ev[1] = date; - add_log_event (bl, self, ev, 8); -} - -void bl_do_set_seq (struct binlog *bl, struct mtproto_connection *self, int seq) { - int *ev = alloc_log_event (bl, 8); - ev[0] = CODE_binlog_set_seq; - ev[1] = seq; - add_log_event (bl, self, ev, 8); -} - -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) { - clear_packet (self); - out_int (self, CODE_binlog_chat_create); - out_int (self, get_peer_id (C->id)); - out_int (self, y); - out_cstring (self, s, l); - out_int (self, users_num); - out_int (self, date); - out_int (self, version); - out_data (self, big, sizeof (struct file_location)); - out_data (self, small, sizeof (struct file_location)); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_chat_forbid (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int on) { - if (on) { - if (C->flags & FLAG_FORBIDDEN) { return; } - int *ev = alloc_log_event (bl, 16); - ev[0] = CODE_binlog_chat_change_flags; - ev[1] = get_peer_id (C->id); - ev[2] = FLAG_FORBIDDEN; - ev[3] = 0; - add_log_event (bl, self, ev, 16); - } else { - if (!(C->flags & FLAG_FORBIDDEN)) { return; } - int *ev = alloc_log_event (bl, 16); - ev[0] = CODE_binlog_chat_change_flags; - ev[1] = get_peer_id (C->id); - ev[2] = 0; - ev[3] = FLAG_FORBIDDEN; - add_log_event (bl, self, ev, 16); - } -} - -void bl_do_set_chat_title (struct binlog *bl, struct mtproto_connection *self, struct chat *C, const char *s, int l) { - if (C->title && (int)strlen (C->title) == l && !strncmp (C->title, s, l)) { return; } - clear_packet (self); - out_int (self, CODE_binlog_set_chat_title); - out_int (self, get_peer_id (C->id)); - out_cstring (self, s, l); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_set_chat_photo (struct binlog *bl, struct mtproto_connection *self, struct chat *C, struct file_location *big, struct file_location *small) { - if (!memcmp (&C->photo_small, small, sizeof (struct file_location)) && - !memcmp (&C->photo_big, big, sizeof (struct file_location))) { return; } - clear_packet (self); - out_int (self, CODE_binlog_set_chat_photo); - out_int (self, get_peer_id (C->id)); - out_data (self, big, sizeof (struct file_location)); - out_data (self, small, sizeof (struct file_location)); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_set_chat_date (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int date) { - if (C->date == date) { return; } - int *ev = alloc_log_event (bl, 12); - ev[0] = CODE_binlog_set_chat_date; - ev[1] = get_peer_id (C->id); - ev[2] = date; - add_log_event (bl, self, ev, 12); -} - -void bl_do_set_chat_set_in_chat (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int on) { - if (on) { - if (C->flags & FLAG_CHAT_IN_CHAT) { return; } - int *ev = alloc_log_event (bl, 16); - ev[0] = CODE_binlog_chat_change_flags; - ev[1] = get_peer_id (C->id); - ev[2] = FLAG_CHAT_IN_CHAT; - ev[3] = 0; - add_log_event (bl, self, ev, 16); - } else { - if (!(C->flags & FLAG_CHAT_IN_CHAT)) { return; } - int *ev = alloc_log_event (bl, 16); - ev[0] = CODE_binlog_chat_change_flags; - ev[1] = get_peer_id (C->id); - ev[2] = 0; - ev[3] = FLAG_CHAT_IN_CHAT; - add_log_event (bl, self, ev, 16); - } -} - -void bl_do_set_chat_version (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int version, int user_num) { - if (C->version >= version) { return; } - int *ev = alloc_log_event (bl, 16); - ev[0] = CODE_binlog_set_chat_version; - ev[1] = get_peer_id (C->id); - ev[2] = version; - ev[3] = user_num; - add_log_event (bl, self, ev, 16); -} - -void bl_do_set_chat_admin (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int admin) { - if (C->admin_id == admin) { return; } - int *ev = alloc_log_event (bl, 12); - ev[0] = CODE_binlog_set_chat_admin; - ev[1] = get_peer_id (C->id); - ev[2] = admin; - add_log_event (bl, self, ev, 12); -} - -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) { - if (C->user_list_version >= version) { return; } - int *ev = alloc_log_event (bl, 12 * user_num + 16); - ev[0] = CODE_binlog_set_chat_participants; - ev[1] = get_peer_id (C->id); - ev[2] = version; - ev[3] = user_num; - memcpy (ev + 4, users, 12 * user_num); - add_log_event (bl, self, ev, 12 * user_num + 16); -} - -void bl_do_set_chat_full_photo (struct binlog *bl, struct mtproto_connection *self, struct chat *U, const int *start, int len) { - if (U->photo.id == *(long long *)(start + 1)) { return; } - int *ev = alloc_log_event (bl, len + 8); - ev[0] = CODE_binlog_chat_full_photo; - ev[1] = get_peer_id (U->id); - memcpy (ev + 2, start, len); - add_log_event (bl, self, ev, len + 8); -} - -void bl_do_chat_add_user (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int version, int user, int inviter, int date) { - if (C->user_list_version >= version || !C->user_list_version) { return; } - int *ev = alloc_log_event (bl, 24); - ev[0] = CODE_binlog_add_chat_participant; - ev[1] = get_peer_id (C->id); - ev[2] = version; - ev[3] = user; - ev[4] = inviter; - ev[5] = date; - add_log_event (bl, self, ev, 24); -} - -void bl_do_chat_del_user (struct binlog *bl, struct mtproto_connection *self, struct chat *C, int version, int user) { - if (C->user_list_version >= version || !C->user_list_version) { return; } - int *ev = alloc_log_event (bl, 16); - ev[0] = CODE_binlog_add_chat_participant; - ev[1] = get_peer_id (C->id); - ev[2] = version; - ev[3] = user; - add_log_event (bl, self, ev, 16); -} - -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) { - clear_packet (self); - out_int (self, CODE_binlog_create_message_text); - out_int (self, msg_id); - out_int (self, from_id); - out_int (self, to_type); - out_int (self, to_id); - out_int (self, date); - out_cstring (self, s, l); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -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) { - clear_packet (self); - out_int (self, CODE_binlog_send_message_text); - out_long (self, msg_id); - out_int (self, from_id); - out_int (self, to_type); - out_int (self, to_id); - out_int (self, date); - out_cstring (self, s, l); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -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) { - clear_packet (self); - out_int (self, CODE_binlog_create_message_text_fwd); - out_int (self, msg_id); - out_int (self, from_id); - out_int (self, to_type); - out_int (self, to_id); - out_int (self, date); - out_int (self, fwd); - out_int (self, fwd_date); - out_cstring (self, s, l); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -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) { - clear_packet (self); - out_int (self, CODE_binlog_create_message_media); - out_int (self, msg_id); - out_int (self, from_id); - out_int (self, to_type); - out_int (self, to_id); - out_int (self, date); - out_cstring (self, s, l); - out_ints (self, data, len); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -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) { - clear_packet (self); - out_int (self, CODE_binlog_create_message_media_encr); - out_long (self, msg_id); - out_int (self, from_id); - out_int (self, to_type); - out_int (self, to_id); - out_int (self, date); - out_cstring (self, s, l); - out_ints (self, data, len); - out_ints (self, data2, len2); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -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) { - clear_packet (self); - out_int (self, CODE_binlog_create_message_media_fwd); - out_int (self, msg_id); - out_int (self, from_id); - out_int (self, to_type); - out_int (self, to_id); - out_int (self, date); - out_int (self, fwd); - out_int (self, fwd_date); - out_cstring (self, s, l); - out_ints (self, data, len); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -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) { - clear_packet (self); - out_int (self, CODE_binlog_create_message_service); - out_int (self, msg_id); - out_int (self, from_id); - out_int (self, to_type); - out_int (self, to_id); - out_int (self, date); - out_ints (self, data, len); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} -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) { - clear_packet (self); - out_int (self, CODE_binlog_create_message_service_encr); - out_long (self, msg_id); - out_int (self, from_id); - out_int (self, to_type); - out_int (self, to_id); - out_int (self, date); - out_ints (self, data, len); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -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) { - clear_packet (self); - out_int (self, CODE_binlog_create_message_service_fwd); - out_int (self, msg_id); - out_int (self, from_id); - out_int (self, to_type); - out_int (self, to_id); - out_int (self, date); - out_int (self, fwd); - out_int (self, fwd_date); - out_ints (self, data, len); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_set_unread (struct binlog *bl, struct mtproto_connection *self, struct message *M, int unread) { - if (unread || !M->unread) { return; } - clear_packet (self); - out_int (self, CODE_binlog_set_unread); - out_int (self, M->id); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_set_message_sent (struct binlog *bl, struct mtproto_connection *self, struct message *M) { - if (!(M->flags & FLAG_PENDING)) { return; } - clear_packet (self); - out_int (self, CODE_binlog_set_message_sent); - out_long (self, M->id); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_set_msg_id (struct binlog *bl, struct mtproto_connection *self, struct message *M, int id) { - if (M->id == id) { return; } - clear_packet (self); - out_int (self, CODE_binlog_set_msg_id); - out_long (self, M->id); - out_int (self, id); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} - -void bl_do_delete_msg (struct binlog *bl, struct mtproto_connection *self, struct message *M) { - clear_packet (self); - out_int (self, CODE_binlog_delete_msg); - out_long (self, M->id); - add_log_event (bl, self, self->packet_buffer, 4 * (self->packet_ptr - self->packet_buffer)); -} diff --git a/binlog.h b/binlog.h deleted file mode 100644 index ac4b7b1..0000000 --- a/binlog.h +++ /dev/null @@ -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 . - - 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 diff --git a/binlog.tl b/binlog.tl deleted file mode 100644 index c7c80b7..0000000 --- a/binlog.tl +++ /dev/null @@ -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; - diff --git a/constants.h b/constants.h deleted file mode 100644 index cd19aa8..0000000 --- a/constants.h +++ /dev/null @@ -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 . - - 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 diff --git a/gen_constants_h.awk b/gen_constants_h.awk deleted file mode 100644 index 06e6835..0000000 --- a/gen_constants_h.awk +++ /dev/null @@ -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 ."; - 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"; -} diff --git a/purple-plugin/telegram.png b/imgs/telegram.png similarity index 100% rename from purple-plugin/telegram.png rename to imgs/telegram.png diff --git a/purple-plugin/telegram16.png b/imgs/telegram16.png similarity index 100% rename from purple-plugin/telegram16.png rename to imgs/telegram16.png diff --git a/purple-plugin/telegram22.png b/imgs/telegram22.png similarity index 100% rename from purple-plugin/telegram22.png rename to imgs/telegram22.png diff --git a/purple-plugin/telegram48.png b/imgs/telegram48.png similarity index 100% rename from purple-plugin/telegram48.png rename to imgs/telegram48.png diff --git a/include.h b/include.h deleted file mode 100644 index bf290a1..0000000 --- a/include.h +++ /dev/null @@ -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 . - - Copyright Vitaly Valtman 2013 -*/ -#ifndef __INCLUDE_H__ -#define __INCLUDE_H__ - -#define UU __attribute__ ((unused)) - -#endif diff --git a/loop.c b/loop.c deleted file mode 100644 index b20ad5b..0000000 --- a/loop.c +++ /dev/null @@ -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 . - - Copyright Vitaly Valtman 2013 -*/ - -#define _GNU_SOURCE -#define READLINE_CALLBACKS - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#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); -} - diff --git a/loop.h b/loop.h deleted file mode 100644 index a48e34c..0000000 --- a/loop.h +++ /dev/null @@ -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 . - - 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 diff --git a/msglog.c b/msglog.c index 2c131b9..0518025 100644 --- a/msglog.c +++ b/msglog.c @@ -1,7 +1,7 @@ #include #include -#include "debug.h" -#include "purple-plugin/telegram-purple.h" +#include +#include "telegram-purple.h" #ifdef DEBUG #define COLOR_GREY "\033[37;1m" diff --git a/mtproto-client.c b/mtproto-client.c deleted file mode 100644 index 3f71d6c..0000000 --- a/mtproto-client.c +++ /dev/null @@ -1,1735 +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 . - - Copyright Nikolay Durov, Andrey Lopatin 2012-2013 - Copyright Vitaly Valtman 2013 -*/ - -#define _FILE_OFFSET_BITS 64 - -#include -#include -#include -#include -#include -#include -#include -#if defined(__FreeBSD__) || defined(__OpenBSD__) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "telegram.h" -#include "net.h" -#include "include.h" -#include "queries.h" -#include "loop.h" -#include "structures.h" -#include "binlog.h" - -#if defined(__FreeBSD__) -#define __builtin_bswap32(x) bswap32(x) -#endif - -#if defined(__OpenBSD__) -#define __builtin_bswap32(x) __swap32gen(x) -#endif - -#define sha1 SHA1 - -#include "mtproto-client.h" - -#define MAX_NET_RES (1L << 16) -int log_level = 2; - - -int verbosity = 0; -int allow_weak_random = 0; -int disable_auto_accept = 0; - -int rpc_execute (struct connection *c, int op, int len); -int rpc_becomes_ready (struct connection *c); -int rpc_close (struct connection *c); - -struct connection_methods auth_methods = { - .execute = rpc_execute, - .ready = rpc_becomes_ready, - .close = rpc_close -}; - -long long precise_time; - -double get_utime (int clock_id) { - struct timespec T; - my_clock_gettime (clock_id, &T); - double res = T.tv_sec + (double) T.tv_nsec * 1e-9; - if (clock_id == CLOCK_REALTIME) { - precise_time = (long long) (res * (1LL << 32)); - } - return res; -} - -void secure_random (void *s, int l) { - if (RAND_bytes (s, l) < 0) { - if (allow_weak_random) { - RAND_pseudo_bytes (s, l); - } else { - assert (0 && "End of random. If you want, you can start with -w"); - } - } -} - - -#define STATS_BUFF_SIZE (64 << 10) -int stats_buff_len; -char stats_buff[STATS_BUFF_SIZE]; - -#define MAX_RESPONSE_SIZE (1L << 24) - -char Response[MAX_RESPONSE_SIZE]; -int Response_len; - -/* - * - * STATE MACHINE - * - */ - -#define TG_SERVER_PUBKEY_FILENAME "/etc/telegram-purple/server.pub" -char *rsa_public_key_name = 0; -RSA *pubKey; -long long pk_fingerprint; - -static int rsa_load_public_key (const char *public_key_name) { - pubKey = NULL; - FILE *f = fopen (public_key_name, "r"); - if (f == NULL) { - debug ( "Couldn't open public key file: %s\n", public_key_name); - return -1; - } - pubKey = PEM_read_RSAPublicKey (f, NULL, NULL, NULL); - fclose (f); - if (pubKey == NULL) { - debug ( "PEM_read_RSAPublicKey returns NULL.\n"); - return -1; - } - - debug ( "public key '%s' loaded successfully\n", rsa_public_key_name); - - return 0; -} - - - - - -int auth_work_start (struct connection *c); - -/* - * - * UNAUTHORIZED (DH KEY EXCHANGE) PROTOCOL PART - * - */ - - -int encrypt_packet_buffer (struct mtproto_connection *self) { - return pad_rsa_encrypt (self, (char *) self->packet_buffer, (self->packet_ptr - self->packet_buffer) * 4, (char *) self->encrypt_buffer, - ENCRYPT_BUFFER_INTS * 4, pubKey->n, pubKey->e); -} - -int encrypt_packet_buffer_aes_unauth (struct mtproto_connection *self, const char server_nonce[16], const char hidden_client_nonce[32]) { - init_aes_unauth (self, server_nonce, hidden_client_nonce, AES_ENCRYPT); - return pad_aes_encrypt (self, (char *) self->packet_buffer, (self->packet_ptr - self->packet_buffer) * 4, - (char *) self->encrypt_buffer, ENCRYPT_BUFFER_INTS * 4); -} - - -int rpc_send_packet (struct connection *c) { - debug("rpc_send_packet()\n"); - struct mtproto_connection *self = c->mtconnection; - - int len = (self->packet_ptr - self->packet_buffer) * 4; - c->out_packet_num ++; - long long next_msg_id = (long long) ((1LL << 32) * get_utime (CLOCK_REALTIME)) & -4; - if (next_msg_id <= self->unenc_msg_header.out_msg_id) { - self->unenc_msg_header.out_msg_id += 4; - } else { - self->unenc_msg_header.out_msg_id = next_msg_id; - } - self->unenc_msg_header.msg_len = len; - - int total_len = len + 20; - assert (total_len > 0 && !(total_len & 0xfc000003)); - total_len >>= 2; - if (total_len < 0x7f) { - assert (write_out (c, &total_len, 1) == 1); - } else { - total_len = (total_len << 8) | 0x7f; - assert (write_out (c, &total_len, 4) == 4); - } - write_out (c, &self->unenc_msg_header, 20); - write_out (c, self->packet_buffer, len); - flush_out (c); - - self->total_packets_sent ++; - self->total_data_sent += total_len; - return 1; -} - -int rpc_send_message (struct connection *c, void *data, int len) { - struct mtproto_connection *self = c->mtconnection; - - //debug("rpc_send_message(...)\n"); - assert (len > 0 && !(len & 0xfc000003)); - int total_len = len >> 2; - if (total_len < 0x7f) { - assert (write_out (c, &total_len, 1) == 1); - } else { - total_len = (total_len << 8) | 0x7f; - assert (write_out (c, &total_len, 4) == 4); - } - c->out_packet_num ++; - assert (write_out (c, data, len) == len); - flush_out (c); - - self->total_packets_sent ++; - self->total_data_sent += total_len; - return 1; -} - -int send_req_pq_packet (struct connection *c) { - struct mtproto_connection *self = c->mtconnection; - - assert (self->c_state == st_init); - secure_random (self->nonce, 16); - self->unenc_msg_header.out_msg_id = 0; - clear_packet (self); - out_int (self, CODE_req_pq); - out_ints (self, (int *)self->nonce, 4); - rpc_send_packet (c); - self->c_state = st_reqpq_sent; - return 1; -} - - -unsigned long long gcd (unsigned long long a, unsigned long long b) { - return b ? gcd (b, a % b) : a; -} - -//typedef unsigned int uint128_t __attribute__ ((mode(TI))); - -int process_respq_answer (struct connection *c, char *packet, int len) { - debug ( "process_respq_answer(), len=%d\n", len); - - struct mtproto_connection *self = c->mtconnection; - int i; - assert (len >= 76); - assert (!*(long long *) packet); - assert (*(int *) (packet + 16) == len - 20); - assert (!(len & 3)); - assert (*(int *) (packet + 20) == CODE_resPQ); - assert (!memcmp (packet + 24, self->nonce, 16)); - memcpy (self->server_nonce, packet + 40, 16); - char *from = packet + 56; - int clen = *from++; - assert (clen <= 8); - self->what = 0; - for (i = 0; i < clen; i++) { - self->what = (self->what << 8) + (unsigned char)*from++; - } - - while (((unsigned long)from) & 3) ++from; - - self->p1 = 0, self->p2 = 0; - - debug ( "%lld received\n", self->what); - - int it = 0; - unsigned long long g = 0; - for (i = 0; i < 3 || it < 1000; i++) { - int q = ((lrand48() & 15) + 17) % self->what; - unsigned long long x = (long long)lrand48 () % (self->what - 1) + 1, y = x; - int lim = 1 << (i + 18); - int j; - for (j = 1; j < lim; j++) { - ++it; - unsigned long long a = x, b = x, c = q; - while (b) { - if (b & 1) { - c += a; - if (c >= self->what) { - c -= self->what; - } - } - a += a; - if (a >= self->what) { - a -= self->what; - } - b >>= 1; - } - x = c; - unsigned long long z = x < y ? self->what + x - y : x - y; - g = gcd (z, self->what); - if (g != 1) { - break; - } - if (!(j & (j - 1))) { - y = x; - } - } - if (g > 1 && g < self->what) break; - } - - assert (g > 1 && g < self->what); - self->p1 = g; - self->p2 = self->what / g; - if (self->p1 > self->p2) { - unsigned t = self->p1; self->p1 = self->p2; self->p2 = t; - } - - debug ( "Calculated primes: self->p1 = %d, self->p2 = %d, %d iterations\n", self->p1, self->p2, it); - - /// ++p1; /// - - assert (*(int *) (from) == CODE_vector); - int fingerprints_num = *(int *)(from + 4); - assert (fingerprints_num >= 1 && fingerprints_num <= 64 && len == fingerprints_num * 8 + 8 + (from - packet)); - long long *fingerprints = (long long *) (from + 8); - debug("Got %d fingerprints\n", fingerprints_num); - for (i = 0; i < fingerprints_num; i++) { - if (fingerprints[i] == pk_fingerprint) { - debug ( "found our public key at position %d\n", i); - break; - } - } - if (i == fingerprints_num) { - debug ( "fatal: don't have any matching keys (%016llx expected)\n", pk_fingerprint); - exit (2); - } - // create inner part (P_Q_inner_data) - clear_packet (self); - self->packet_ptr += 5; - out_int (self, CODE_p_q_inner_data); - out_cstring (self, packet + 57, clen); - //out_int (0x0f01); // pq=15 - - if (self->p1 < 256) { - clen = 1; - } else if (self->p1 < 65536) { - clen = 2; - } else if (self->p1 < 16777216) { - clen = 3; - } else { - clen = 4; - } - self->p1 = __builtin_bswap32 (self->p1); - out_cstring (self, (char *)&self->p1 + 4 - clen, clen); - self->p1 = __builtin_bswap32 (self->p1); - - if (self->p2 < 256) { - clen = 1; - } else if (self->p2 < 65536) { - clen = 2; - } else if (self->p2 < 16777216) { - clen = 3; - } else { - clen = 4; - } - self->p2 = __builtin_bswap32 (self->p2); - out_cstring (self, (char *)&self->p2 + 4 - clen, clen); - self->p2 = __builtin_bswap32 (self->p2); - - //out_int (0x0301); // p=3 - //out_int (0x0501); // q=5 - out_ints (self, (int *) self->nonce, 4); - out_ints (self, (int *) self->server_nonce, 4); - secure_random (self->new_nonce, 32); - out_ints (self, (int *) self->new_nonce, 8); - sha1 ((unsigned char *) (self->packet_buffer + 5), (self->packet_ptr - self->packet_buffer - 5) * 4, (unsigned char *) self->packet_buffer); - - int l = encrypt_packet_buffer (self); - - clear_packet (self); - out_int (self, CODE_req_DH_params); - out_ints (self, (int *) self->nonce, 4); - out_ints (self, (int *) self->server_nonce, 4); - //out_int (0x0301); // p=3 - //out_int (0x0501); // q=5 - if (self->p1 < 256) { - clen = 1; - } else if (self->p1 < 65536) { - clen = 2; - } else if (self->p1 < 16777216) { - clen = 3; - } else { - clen = 4; - } - self->p1 = __builtin_bswap32 (self->p1); - out_cstring (self, (char *)&self->p1 + 4 - clen, clen); - self->p1 = __builtin_bswap32 (self->p1); - if (self->p2 < 256) { - clen = 1; - } else if (self->p2 < 65536) { - clen = 2; - } else if (self->p2 < 16777216) { - clen = 3; - } else { - clen = 4; - } - self->p2 = __builtin_bswap32 (self->p2); - out_cstring (self, (char *)&self->p2 + 4 - clen, clen); - self->p2 = __builtin_bswap32 (self->p2); - - out_long (self, pk_fingerprint); - out_cstring (self, (char *) self->encrypt_buffer, l); - - self->c_state = st_reqdh_sent; - - return rpc_send_packet (c); -} - -int check_prime (struct mtproto_connection *self, BIGNUM *p) { - int r = BN_is_prime (p, BN_prime_checks, 0, self->BN_ctx, 0); - ensure (r >= 0); - return r; -} - -int check_DH_params (struct mtproto_connection *self, BIGNUM *p, int g) { - if (g < 2 || g > 7) { return -1; } - BIGNUM t; - BN_init (&t); - - BN_init (&self->dh_g); - ensure (BN_set_word (&self->dh_g, 4 * g)); - - ensure (BN_mod (&t, p, &self->dh_g, self->BN_ctx)); - int x = BN_get_word (&t); - assert (x >= 0 && x < 4 * g); - - BN_free (&self->dh_g); - - switch (g) { - case 2: - if (x != 7) { return -1; } - break; - case 3: - if (x % 3 != 2 ) { return -1; } - break; - case 4: - break; - case 5: - if (x % 5 != 1 && x % 5 != 4) { return -1; } - break; - case 6: - if (x != 19 && x != 23) { return -1; } - break; - case 7: - if (x % 7 != 3 && x % 7 != 5 && x % 7 != 6) { return -1; } - break; - } - - if (!check_prime (self, p)) { return -1; } - - BIGNUM b; - BN_init (&b); - ensure (BN_set_word (&b, 2)); - ensure (BN_div (&t, 0, p, &b, self->BN_ctx)); - if (!check_prime (self, &t)) { return -1; } - BN_free (&b); - BN_free (&t); - return 0; -} - -int check_g (unsigned char p[256], BIGNUM *g) { - static unsigned char s[256]; - memset (s, 0, 256); - assert (BN_num_bytes (g) <= 256); - BN_bn2bin (g, s); - int ok = 0; - int i; - for (i = 0; i < 64; i++) { - if (s[i]) { - ok = 1; - break; - } - } - if (!ok) { return -1; } - ok = 0; - for (i = 0; i < 64; i++) { - if (s[255 - i]) { - ok = 1; - break; - } - } - if (!ok) { return -1; } - ok = 0; - for (i = 0; i < 64; i++) { - if (s[i] < p[i]) { - ok = 1; - break; - } else if (s[i] > p[i]) { - debug ("i = %d (%d %d)\n", i, (int)s[i], (int)p[i]); - return -1; - } - } - if (!ok) { return -1; } - return 0; -} - -int check_g_bn (BIGNUM *p, BIGNUM *g) { - static unsigned char s[256]; - memset (s, 0, 256); - assert (BN_num_bytes (p) <= 256); - BN_bn2bin (p, s); - return check_g (s, g); -} - -int process_dh_answer (struct connection *c, char *packet, int len) { - debug ( "process_dh_answer(), len=%d\n", len); - struct mtproto_connection *self = c->mtconnection; - if (len < 116) { - debug ( "%u * %u = %llu", self->p1, self->p2, self->what); - } - assert (len >= 116); - assert (!*(long long *) packet); - assert (*(int *) (packet + 16) == len - 20); - assert (!(len & 3)); - assert (*(int *) (packet + 20) == (int)CODE_server_DH_params_ok); - assert (!memcmp (packet + 24, self->nonce, 16)); - assert (!memcmp (packet + 40, self->server_nonce, 16)); - init_aes_unauth (self, self->server_nonce, self->new_nonce, AES_DECRYPT); - self->in_ptr = (int *)(packet + 56); - self->in_end = (int *)(packet + len); - int l = prefetch_strlen (self); - assert (l > 0); - l = pad_aes_decrypt (self, fetch_str (self, l), l, (char *) self->decrypt_buffer, DECRYPT_BUFFER_INTS * 4 - 16); - assert (self->in_ptr == self->in_end); - assert (l >= 60); - assert (self->decrypt_buffer[5] == (int)CODE_server_DH_inner_data); - assert (!memcmp (self->decrypt_buffer + 6, self->nonce, 16)); - assert (!memcmp (self->decrypt_buffer + 10, self->server_nonce, 16)); - int g = self->decrypt_buffer[14]; - self->in_ptr = self->decrypt_buffer + 15; - self->in_end = self->decrypt_buffer + (l >> 2); - BN_init (&self->dh_prime); - BN_init (&self->g_a); - assert (fetch_bignum (self, &self->dh_prime) > 0); - assert (fetch_bignum (self, &self->g_a) > 0); - assert (check_g_bn (&self->dh_prime, &self->g_a) >= 0); - int server_time = *self->in_ptr++; - assert (self->in_ptr <= self->in_end); - - assert (check_DH_params (self, &self->dh_prime, g) >= 0); - - static char sha1_buffer[20]; - sha1 ((unsigned char *) self->decrypt_buffer + 20, (self->in_ptr - self->decrypt_buffer - 5) * 4, (unsigned char *) sha1_buffer); - assert (!memcmp (self->decrypt_buffer, sha1_buffer, 20)); - assert ((char *) self->in_end - (char *) self->in_ptr < 16); - - GET_DC(c)->server_time_delta = server_time - time (0); - GET_DC(c)->server_time_udelta = server_time - get_utime (CLOCK_MONOTONIC); - //debug ( "server time is %d, delta = %d\n", server_time, server_time_delta); - - // Build set_client_DH_params answer - clear_packet (self); - self->packet_ptr += 5; - out_int (self, CODE_client_DH_inner_data); - out_ints (self, (int *) self->nonce, 4); - out_ints (self, (int *) self->server_nonce, 4); - out_long (self, 0LL); - - BN_init (&self->dh_g); - ensure (BN_set_word (&self->dh_g, g)); - - secure_random (self->s_power, 256); - BIGNUM *dh_power = BN_bin2bn ((unsigned char *)self->s_power, 256, 0); - ensure_ptr (dh_power); - - BIGNUM *y = BN_new (); - ensure_ptr (y); - ensure (BN_mod_exp (y, &self->dh_g, dh_power, &self->dh_prime, self->BN_ctx)); - out_bignum (self, y); - BN_free (y); - - BN_init (&self->auth_key_num); - ensure (BN_mod_exp (&self->auth_key_num, &self->g_a, dh_power, &self->dh_prime, self->BN_ctx)); - l = BN_num_bytes (&self->auth_key_num); - assert (l >= 250 && l <= 256); - assert (BN_bn2bin (&self->auth_key_num, (unsigned char *)GET_DC(c)->auth_key)); - memset (GET_DC(c)->auth_key + l, 0, 256 - l); - BN_free (dh_power); - BN_free (&self->auth_key_num); - BN_free (&self->dh_g); - BN_free (&self->g_a); - BN_free (&self->dh_prime); - - //hexdump (auth_key, auth_key + 256); - - sha1 ((unsigned char *) (self->packet_buffer + 5), (self->packet_ptr - self->packet_buffer - 5) * 4, (unsigned char *) self->packet_buffer); - - //hexdump ((char *)packet_buffer, (char *)packet_ptr); - - l = encrypt_packet_buffer_aes_unauth (self, self->server_nonce, self->new_nonce); - - clear_packet (self); - out_int (self, CODE_set_client_DH_params); - out_ints (self, (int *) self->nonce, 4); - out_ints (self, (int *) self->server_nonce, 4); - out_cstring (self, (char *) self->encrypt_buffer, l); - - self->c_state = st_client_dh_sent; - - return rpc_send_packet (c); -} - - -int process_auth_complete (struct connection *c, char *packet, int len) { - debug ( "process_auth_complete(), len=%d\n", len); - struct mtproto_connection *self = c->mtconnection; - assert (len == 72); - assert (!*(long long *) packet); - assert (*(int *) (packet + 16) == len - 20); - assert (!(len & 3)); - assert (*(int *) (packet + 20) == CODE_dh_gen_ok); - assert (!memcmp (packet + 24, self->nonce, 16)); - assert (!memcmp (packet + 40, self->server_nonce, 16)); - static unsigned char tmp[44], sha1_buffer[20]; - memcpy (tmp, self->new_nonce, 32); - tmp[32] = 1; - //GET_DC(c)->auth_key_id = *(long long *)(sha1_buffer + 12); - - bl_do_set_auth_key_id (c->instance, GET_DC(c)->id, (unsigned char *)GET_DC(c)->auth_key); - sha1 ((unsigned char *)GET_DC(c)->auth_key, 256, sha1_buffer); - - memcpy (tmp + 33, sha1_buffer, 8); - sha1 (tmp, 41, sha1_buffer); - assert (!memcmp (packet + 56, sha1_buffer + 4, 16)); - GET_DC(c)->server_salt = *(long long *)self->server_nonce ^ *(long long *)self->new_nonce; - - debug ( "auth_key_id=%016llx\n", GET_DC(c)->auth_key_id); - //kprintf ("OK\n"); - - //c->status = conn_error; - //sleep (1); - - self->c_state = st_authorized; - //return 1; - debug ( "Auth success\n"); - self->auth_success ++; - GET_DC(c)->flags |= 1; - - return 1; -} - -/* - * - * AUTHORIZED (MAIN) PROTOCOL PART - * - */ - -double get_server_time (struct dc *DC) { - if (!DC->server_time_udelta) { - DC->server_time_udelta = get_utime (CLOCK_REALTIME) - get_utime (CLOCK_MONOTONIC); - } - return get_utime (CLOCK_MONOTONIC) + DC->server_time_udelta; -} - -long long generate_next_msg_id (struct mtproto_connection *self, struct dc *DC) { - long long next_id = (long long) (get_server_time (DC) * (1LL << 32)) & -4; - if (next_id <= self->client_last_msg_id) { - next_id = self->client_last_msg_id += 4; - } else { - self->client_last_msg_id = next_id; - } - return next_id; -} - -void init_enc_msg (struct mtproto_connection *self, struct session *S, int useful) { - struct dc *DC = S->dc; - assert (DC->auth_key_id); - self->enc_msg.auth_key_id = DC->auth_key_id; -// assert (DC->server_salt); - self->enc_msg.server_salt = DC->server_salt; - if (!S->session_id) { - secure_random (&S->session_id, 8); - } - self->enc_msg.session_id = S->session_id; - //enc_msg.auth_key_id2 = auth_key_id; - self->enc_msg.msg_id = generate_next_msg_id (self, DC); - //enc_msg.msg_id -= 0x10000000LL * (lrand48 () & 15); - //kprintf ("message id %016llx\n", enc_msg.msg_id); - self->enc_msg.seq_no = S->seq_no; - if (useful) { - self->enc_msg.seq_no |= 1; - } - S->seq_no += 2; -}; - -int aes_encrypt_message (struct mtproto_connection *self, struct dc *DC, struct encrypted_message *enc) { - unsigned char sha1_buffer[20]; - const int MINSZ = offsetof (struct encrypted_message, message); - const int UNENCSZ = offsetof (struct encrypted_message, server_salt); - int enc_len = (MINSZ - UNENCSZ) + enc->msg_len; - assert (enc->msg_len >= 0 && enc->msg_len <= MAX_MESSAGE_INTS * 4 - 16 && !(enc->msg_len & 3)); - sha1 ((unsigned char *) &enc->server_salt, enc_len, sha1_buffer); - //printf ("enc_len is %d\n", enc_len); - if (verbosity >= 2) { - debug ( "sending message with sha1 %08x\n", *(int *)sha1_buffer); - } - memcpy (enc->msg_key, sha1_buffer + 4, 16); - init_aes_auth (self, DC->auth_key, enc->msg_key, AES_ENCRYPT); - //hexdump ((char *)enc, (char *)enc + enc_len + 24); - return pad_aes_encrypt (self, (char *) &enc->server_salt, enc_len, (char *) &enc->server_salt, MAX_MESSAGE_INTS * 4 + (MINSZ - UNENCSZ)); -} - -long long encrypt_send_message (struct mtproto_connection *self, int *msg, int msg_ints, int useful) { - struct connection *c = self->connection; - - //debug("encrypt_send_message(...)\n"); - struct dc *DC = GET_DC(c); - struct session *S = c->session; - assert (S); - const int UNENCSZ = offsetof (struct encrypted_message, server_salt); - if (msg_ints <= 0 || msg_ints > MAX_MESSAGE_INTS - 4) { - return -1; - } - if (msg) { - memcpy (self->enc_msg.message, msg, msg_ints * 4); - self->enc_msg.msg_len = msg_ints * 4; - } else { - if ((self->enc_msg.msg_len & 0x80000003) || self->enc_msg.msg_len > MAX_MESSAGE_INTS * 4 - 16) { - return -1; - } - } - init_enc_msg (self, S, useful); - - //hexdump ((char *)msg, (char *)msg + (msg_ints * 4)); - int l = aes_encrypt_message (self, DC, &self->enc_msg); - //hexdump ((char *)&enc_msg, (char *)&enc_msg + l + 24); - assert (l > 0); - rpc_send_message (c, &self->enc_msg, l + UNENCSZ); - - return self->client_last_msg_id; -} - - -int auth_work_start (struct connection *c UU) { - return 1; -} - -void rpc_execute_answer (struct connection *c, long long msg_id UU); - -void fetch_pts (struct mtproto_connection *self) { - int p = fetch_int (self); - if (p <= self->pts) { return; } - if (p != self->pts + 1) { - if (self->pts) { - //debug ("Hole in pts p = %d, pts = %d\n", p, pts); - - // get difference should be here - self->pts = p; - } else { - self->pts = p; - } - } else { - self->pts ++; - } - bl_do_set_pts (self->bl, self, self->pts); -} - -void fetch_qts (struct mtproto_connection *self) { - int p = fetch_int (self); - if (p <= self->qts) { return; } - if (p != self->qts + 1) { - if (self->qts) { - //debug ("Hole in qts\n"); - // get difference should be here - self->qts = p; - } else { - self->qts = p; - } - } else { - self->qts ++; - } - bl_do_set_qts (self->bl, self, self->qts); -} - -void fetch_date (struct mtproto_connection *self) { - int p = fetch_int (self); - if (p > self->last_date) { - self->last_date = p; - bl_do_set_date (self->bl, self, self->last_date); - } -} - -void fetch_seq (struct mtproto_connection *self) { - int x = fetch_int (self); - if (x > self->seq + 1) { - debug ("Hole in seq: seq = %d, x = %d\n", self->seq, x); - //do_get_difference (); - //seq = x; - } else if (x == self->seq + 1) { - self->seq = x; - bl_do_set_seq (self->bl, self, self->seq); - } -} - -void work_update_binlog (struct mtproto_connection *self) { - struct binlog *bl = self->bl; - - unsigned op = fetch_int (self); - switch (op) { - case CODE_update_user_name: - { - peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *UC = user_chat_get (bl, user_id); - if (UC) { - struct tgl_user *U = &UC->user; - if (U->first_name) { tfree_str (U->first_name); } - if (U->last_name) { tfree_str (U->last_name); } - if (U->print_name) { - peer_delete_name (bl, UC); - tfree_str (U->print_name); - } - U->first_name = fetch_str_dup (self); - U->last_name = fetch_str_dup (self); - U->print_name = create_print_name (bl, U->id, U->first_name, U->last_name, 0, 0); - peer_insert_name (bl, (void *)U); - } else { - fetch_skip_str (self); - fetch_skip_str (self); - } - } - break; - case CODE_update_user_photo: - { - peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *UC = user_chat_get (bl, user_id); - fetch_date (self); - if (UC) { - struct tgl_user *U = &UC->user; - - unsigned y = fetch_int (self); - if (y == CODE_user_profile_photo_empty) { - U->photo_id = 0; - U->photo_big.dc = -2; - U->photo_small.dc = -2; - } else { - assert (y == CODE_user_profile_photo); - U->photo_id = fetch_long (self); - fetch_file_location (self, &U->photo_small); - fetch_file_location (self, &U->photo_big); - } - } else { - struct file_location t; - unsigned y = fetch_int (self); - if (y == CODE_user_profile_photo_empty) { - } else { - assert (y == CODE_user_profile_photo); - fetch_long (self); // photo_id - fetch_file_location (self, &t); - fetch_file_location (self, &t); - } - } - fetch_bool (self); - } - break; - default: - assert (0); - } -} - -void work_update (struct mtproto_connection *self, long long msg_id UU) { - struct connection *c = self->connection; - struct telegram *tg = c->instance; - struct binlog *bl = self->bl; - - unsigned op = fetch_int (self); - debug("work_update(): OP:%d\n", op); - switch (op) { - case CODE_update_new_message: - { - debug ("CODE_update_new_message\n"); - struct message *M UU = fetch_alloc_message (self, tg); - assert (M); - fetch_pts (self); - self->unread_messages ++; - event_update_new_message (tg, M); - //print_message (M); - //update_prompt (); - break; - }; - case CODE_update_message_i_d: - { - debug ("CODE_update_message\n"); - int id = fetch_int (self); // id - int new = fetch_long (self); // random_id - struct message *M = message_get (bl, new); - if (M) { - bl_do_set_msg_id (self->bl, self, M, id); - } - } - break; - case CODE_update_read_messages: - { - debug ("CODE_update_read_message\n"); - assert (fetch_int (self) == (int)CODE_vector); - int n = fetch_int (self); - int i; - for (i = 0; i < n; i++) { - int id = fetch_int (self); - struct message *M = message_get (bl, id); - if (M) { - bl_do_set_unread (self->bl, self, M, 0); - } - } - fetch_pts (self); - } - break; - case CODE_update_user_typing: - { - debug ("CODE_update_user_typing\n"); - peer_id_t id = MK_USER (fetch_int (self)); - peer_t *U UU = user_chat_get (bl, id); - event_update_user_typing (tg, U); - } - break; - case CODE_update_chat_user_typing: - { - peer_id_t chat_id = MK_CHAT (fetch_int (self)); - peer_id_t id = MK_USER (fetch_int (self)); - peer_t *C = user_chat_get (bl, chat_id); - peer_t *U = user_chat_get (bl, id); - event_update_chat_user_typing(tg, C, U, 0); - } - break; - case CODE_update_user_status: - { - peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *U = user_chat_get (bl, user_id); - if (U) { - fetch_user_status (self, &U->user.status); - event_update_user_status(tg, U); - } else { - struct user_status t; - fetch_user_status (self, &t); - } - } - break; - case CODE_update_user_name: - { - peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *UC = user_chat_get (bl, user_id); - if (UC && (UC->flags & FLAG_CREATED)) { - int l1 = prefetch_strlen (self); - char *f = fetch_str (self, l1); - int l2 = prefetch_strlen (self); - char *l = fetch_str (self, l2); - struct tgl_user *U = &UC->user; - bl_do_set_user_real_name (self->bl, self, U, f, l1, l, l2); - } else { - fetch_skip_str (self); - fetch_skip_str (self); - } - event_update_user_name (tg, UC); - } - break; - case CODE_update_user_photo: - { - peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *UC = user_chat_get (bl, user_id); - fetch_date (self); - if (UC && (UC->flags & FLAG_CREATED)) { - struct tgl_user *U = &UC->user; - unsigned y = fetch_int (self); - long long photo_id; - struct file_location big; - struct file_location small; - memset (&big, 0, sizeof (big)); - memset (&small, 0, sizeof (small)); - if (y == CODE_user_profile_photo_empty) { - photo_id = 0; - big.dc = -2; - small.dc = -2; - } else { - assert (y == CODE_user_profile_photo); - photo_id = fetch_long (self); - fetch_file_location (self, &small); - fetch_file_location (self, &big); - } - bl_do_set_user_profile_photo (self->bl, self, U, photo_id, &big, &small); - } else { - struct file_location t; - unsigned y = fetch_int (self); - if (y == CODE_user_profile_photo_empty) { - } else { - assert (y == CODE_user_profile_photo); - fetch_long (self); // photo_id - fetch_file_location (self, &t); - fetch_file_location (self, &t); - } - } - event_update_user_photo(tg, UC); - fetch_bool (self); - } - break; - case CODE_update_restore_messages: - { - assert (fetch_int (self) == CODE_vector); - int n = fetch_int (self); - fetch_skip (self, n); - fetch_pts (self); - } - break; - case CODE_update_delete_messages: - { - assert (fetch_int (self) == CODE_vector); - int n = fetch_int (self); - fetch_skip (self, n); - fetch_pts (self); - } - break; - case CODE_update_chat_participants: - { - unsigned x = fetch_int (self); - assert (x == CODE_chat_participants || x == CODE_chat_participants_forbidden); - peer_id_t chat_id = MK_CHAT (fetch_int (self)); - int n = 0; - peer_t *C = user_chat_get (bl, chat_id); - if (C && (C->flags & FLAG_CREATED)) { - if (x == CODE_chat_participants) { - bl_do_set_chat_admin (self->bl, self, &C->chat, fetch_int (self)); - assert (fetch_int (self) == CODE_vector); - n = fetch_int (self); - struct chat_user *users = talloc (12 * n); - int i; - for (i = 0; i < n; i++) { - assert (fetch_int (self) == (int)CODE_chat_participant); - users[i].user_id = fetch_int (self); - users[i].inviter_id = fetch_int (self); - users[i].date = fetch_int (self); - } - int version = fetch_int (self); - bl_do_set_chat_participants (self->bl, self, &C->chat, version, n, users); - } - } else { - if (x == CODE_chat_participants) { - fetch_int (self); // admin_id - assert (fetch_int (self) == CODE_vector); - n = fetch_int (self); - fetch_skip (self, n * 4); - fetch_int (self); // version - } - } - if (C) { - event_update_chat_participants(tg, C); - } - } - break; - case CODE_update_contact_registered: - { - peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *U = user_chat_get (bl, user_id); - fetch_int (self); // date - event_update_user_registered(tg, U); - } - break; - case CODE_update_contact_link: - { - peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *U UU = user_chat_get (bl, user_id); - unsigned t = fetch_int (self); - assert (t == CODE_contacts_my_link_empty || t == CODE_contacts_my_link_requested || t == CODE_contacts_my_link_contact); - if (t == CODE_contacts_my_link_requested) { - fetch_bool (self); // has_phone - } - t = fetch_int (self); - assert (t == CODE_contacts_foreign_link_unknown || t == CODE_contacts_foreign_link_requested || t == CODE_contacts_foreign_link_mutual); - if (t == CODE_contacts_foreign_link_requested) { - fetch_bool (self); // has_phone - } - } - break; - case CODE_update_activation: - { - peer_id_t user_id = MK_USER (fetch_int (self)); - peer_t *U UU = user_chat_get (bl, user_id); - } - break; - case CODE_update_new_authorization: - { - fetch_long (self); // auth_key_id - fetch_int (self); // date - char *s = fetch_str_dup (self); - char *location = fetch_str_dup (self); - event_update_auth_new(tg, location); - tfree_str (s); - tfree_str (location); - } - break; - case CODE_update_new_geo_chat_message: - { - struct message *M = fetch_alloc_geo_message (self, tg); - self->unread_messages ++; - event_update_new_message (self->instance, M); - } - break; - case CODE_update_new_encrypted_message: - { - struct message *M UU = fetch_alloc_encrypted_message (self, tg); - self->unread_messages ++; - event_update_new_message (self->instance, M); - fetch_qts (self); - } - break; - case CODE_update_encryption: - { - struct secret_chat *E = fetch_alloc_encrypted_chat (self); - debug ("Secret chat state = %d\n", E->state); - if (E->state == sc_request && !disable_auto_accept) { - do_accept_encr_chat_request (tg, E); - } - fetch_int (self); // date - } - break; - case CODE_update_encrypted_chat_typing: - { - peer_id_t id = MK_ENCR_CHAT (fetch_int (self)); - peer_t *P = user_chat_get (bl, id); - event_update_user_typing(tg, P); - } - break; - case CODE_update_encrypted_messages_read: - { - peer_id_t id = MK_ENCR_CHAT (fetch_int (self)); // chat_id - fetch_int (self); // max_date - fetch_int (self); // date - peer_t *P = user_chat_get (bl, id); - int x = -1; - if (P && P->last) { - x = 0; - struct message *M = P->last; - while (M && (!M->out || M->unread)) { - if (M->out) { - M->unread = 0; - x ++; - } - M = M->next; - } - } - if (log_level >= 1) { - } - } - break; - case CODE_update_chat_participant_add: - { - peer_id_t chat_id = MK_CHAT (fetch_int (self)); - peer_id_t user_id = MK_USER (fetch_int (self)); - peer_id_t inviter_id = MK_USER (fetch_int (self)); - int version = fetch_int (self); - - peer_t *C = user_chat_get (bl, chat_id); - if (C && (C->flags & FLAG_CREATED)) { - bl_do_chat_add_user (self->bl, self, &C->chat, version, get_peer_id (user_id), get_peer_id (inviter_id), time (0)); - } - event_update_chat_add_participant(tg, C, user_id, inviter_id); - } - break; - case CODE_update_chat_participant_delete: - { - peer_id_t chat_id = MK_CHAT (fetch_int (self)); - peer_id_t user_id = MK_USER (fetch_int (self)); - int version = fetch_int (self); - - peer_t *C = user_chat_get (bl, chat_id); - if (C && (C->flags & FLAG_CREATED)) { - bl_do_chat_del_user (self->bl, self, &C->chat, version, get_peer_id (user_id)); - } - event_update_chat_del_participant(tg, C, user_id, 0); - } - break; - case CODE_update_dc_options: - { - assert (fetch_int (self) == CODE_vector); - int n = fetch_int (self); - assert (n >= 0); - int i; - for (i = 0; i < n; i++) { - fetch_dc_option (tg); - } - } - break; - default: - debug ("Unknown update type %08x\n", op); - ; - } -} - -void work_update_short (struct connection *c, long long msg_id) { - debug ("work_update_short\n"); - struct mtproto_connection *self = c->mtconnection; - - assert (fetch_int (self) == CODE_update_short); - work_update (self, msg_id); - fetch_date (self); -} - -void work_updates (struct connection *c, long long msg_id) { - debug ("work_updates(\n)"); - struct mtproto_connection *self = c->mtconnection; - - assert (fetch_int (c->mtconnection) == CODE_updates); - assert (fetch_int (c->mtconnection) == CODE_vector); - int n = fetch_int (c->mtconnection); - int i; - for (i = 0; i < n; i++) { - work_update (c->mtconnection, msg_id); - } - assert (fetch_int (c->mtconnection) == CODE_vector); - n = fetch_int (c->mtconnection); - for (i = 0; i < n; i++) { - fetch_alloc_user (self); - } - assert (fetch_int (c->mtconnection) == CODE_vector); - n = fetch_int (c->mtconnection); - for (i = 0; i < n; i++) { - fetch_alloc_chat (self); - } - bl_do_set_date (self->bl, self, fetch_int (c->mtconnection)); - bl_do_set_seq (self->bl, self, fetch_int (c->mtconnection)); -} - -void work_update_short_message (struct connection *c UU, long long msg_id UU) { - debug ("work_update_short_message(\n)"); - struct mtproto_connection *self = c->mtconnection; - - assert (fetch_int (c->mtconnection) == (int)CODE_update_short_message); - struct message *M = fetch_alloc_message_short (self, c->instance); - c->mtconnection->unread_messages ++; - event_update_new_message (self->instance, M); - if (M->date > c->mtconnection->last_date) { - c->mtconnection->last_date = M->date; - } -} - -void work_update_short_chat_message (struct connection *c, long long msg_id UU) { - debug ("work_update_chat_message(\n)"); - struct mtproto_connection *self = c->mtconnection; - - assert (fetch_int (self) == CODE_update_short_chat_message); - struct message *M = fetch_alloc_message_short_chat (self, c->instance); - c->mtconnection->unread_messages ++; - event_update_new_message (self->instance, M); - if (M->date > c->mtconnection->last_date) { - c->mtconnection->last_date = M->date; - } -} - -void work_container (struct connection *c, long long msg_id UU) { - debug ( "work_container: msg_id = %lld\n", msg_id); - assert (fetch_int (c->mtconnection) == CODE_msg_container); - int n = fetch_int (c->mtconnection); - int i; - for (i = 0; i < n; i++) { - long long id = fetch_long (c->mtconnection); - //int seqno = fetch_int (); - fetch_int (c->mtconnection); // seq_no - if (id & 1) { - insert_msg_id (c->session, id); - } - int bytes = fetch_int (c->mtconnection); - int *t = c->mtconnection->in_end; - c->mtconnection->in_end = c->mtconnection->in_ptr + (bytes / 4); - rpc_execute_answer (c, id); - assert (c->mtconnection->in_ptr == c->mtconnection->in_end); - c->mtconnection->in_end = t; - } -} - -void work_new_session_created (struct connection *c, long long msg_id UU) { - debug ( "work_new_session_created: msg_id = %lld\n", msg_id); - assert (fetch_int (c->mtconnection) == (int)CODE_new_session_created); - fetch_long (c->mtconnection); // first message id - //DC->session_id = fetch_long (); - fetch_long (c->mtconnection); // unique_id - GET_DC(c)->server_salt = fetch_long (c->mtconnection); - debug ("new server_salt = %lld\n", GET_DC(c)->server_salt); -} - -void work_msgs_ack (struct connection *c UU, long long msg_id UU) { - debug ( "work_msgs_ack: msg_id = %lld\n", msg_id); - assert (fetch_int (c->mtconnection) == CODE_msgs_ack); - assert (fetch_int (c->mtconnection) == CODE_vector); - int n = fetch_int (c->mtconnection); - int i; - for (i = 0; i < n; i++) { - long long id = fetch_long (c->mtconnection); - debug ("ack for %lld\n", id); - query_ack (c->instance, id); - } -} - -void work_rpc_result (struct connection *c UU, long long msg_id UU) { - debug ( "work_rpc_result: msg_id = %lld\n", msg_id); - assert (fetch_int (c->mtconnection) == (int)CODE_rpc_result); - long long id = fetch_long (c->mtconnection); - int op = prefetch_int (c->mtconnection); - if (op == CODE_rpc_error) { - query_error (c->instance, id); - } else { - query_result (c->instance, id); - } -} - -#define MAX_PACKED_SIZE (1 << 24) -void work_packed (struct connection *c, long long msg_id) { - debug ("work_packet()\n"); - assert (fetch_int (c->mtconnection) == CODE_gzip_packed); - static int in_gzip; - static int buf[MAX_PACKED_SIZE >> 2]; - assert (!in_gzip); - in_gzip = 1; - - int l = prefetch_strlen (c->mtconnection); - char *s = fetch_str (c->mtconnection, l); - - int total_out = tinflate (s, l, buf, MAX_PACKED_SIZE); - int *end = c->mtconnection->in_ptr; - int *eend = c->mtconnection->in_end; - //assert (total_out % 4 == 0); - c->mtconnection->in_ptr = buf; - c->mtconnection->in_end = c->mtconnection->in_ptr + total_out / 4; - if (verbosity >= 4) { - debug ( "Unzipped data: "); - hexdump_in (c->mtconnection); - } - rpc_execute_answer (c, msg_id); - c->mtconnection->in_ptr = end; - c->mtconnection->in_end = eend; - in_gzip = 0; -} - -void work_bad_server_salt (struct connection *c UU, long long msg_id UU) { - debug ("work_bad_server_salt()\n"); - assert (fetch_int (c->mtconnection) == (int)CODE_bad_server_salt); - long long id = fetch_long (c->mtconnection); - query_restart (c->instance, id); - fetch_int (c->mtconnection); // seq_no - fetch_int (c->mtconnection); // error_code - long long new_server_salt = fetch_long (c->mtconnection); - GET_DC(c)->server_salt = new_server_salt; -} - -void work_pong (struct connection *c UU, long long msg_id UU) { - debug ("work_pong()\n"); - assert (fetch_int (c->mtconnection) == CODE_pong); - fetch_long (c->mtconnection); // msg_id - fetch_long (c->mtconnection); // ping_id -} - -void work_detailed_info (struct connection *c UU, long long msg_id UU) { - debug ("work_detailed_info()\n"); - assert (fetch_int (c->mtconnection) == CODE_msg_detailed_info); - fetch_long (c->mtconnection); // msg_id - fetch_long (c->mtconnection); // answer_msg_id - fetch_int (c->mtconnection); // bytes - fetch_int (c->mtconnection); // status -} - -void work_new_detailed_info (struct connection *c UU, long long msg_id UU) { - debug ("work_new_detailed_info()\n"); - assert (fetch_int (c->mtconnection) == (int)CODE_msg_new_detailed_info); - fetch_long (c->mtconnection); // answer_msg_id - fetch_int (c->mtconnection); // bytes - fetch_int (c->mtconnection); // status -} - -void work_updates_to_long (struct connection *c UU, long long msg_id UU) { - assert (fetch_int (c->mtconnection) == (int)CODE_updates_too_long); - debug ("updates to long... Getting difference\n"); - do_get_difference (c->instance, 0); -} - -void work_bad_msg_notification (struct connection *c UU, long long msg_id UU) { - assert (fetch_int (c->mtconnection) == (int)CODE_bad_msg_notification); - long long m1 = fetch_long (c->mtconnection); - int s = fetch_int (c->mtconnection); - int e = fetch_int (c->mtconnection); - debug ("bad_msg_notification: msg_id = %lld, seq = %d, error = %d\n", m1, s, e); -} - -void rpc_execute_answer (struct connection *c, long long msg_id UU) { - if (verbosity >= 5) { - debug ("rpc_execute_answer: fd=%d\n", c->fd); - hexdump_in (c->mtconnection); - } - int op = prefetch_int (c->mtconnection); - switch (op) { - case CODE_msg_container: - work_container (c, msg_id); - return; - case CODE_new_session_created: - work_new_session_created (c, msg_id); - return; - case CODE_msgs_ack: - work_msgs_ack (c, msg_id); - return; - case CODE_rpc_result: - work_rpc_result (c, msg_id); - return; - case CODE_update_short: - work_update_short (c, msg_id); - return; - case CODE_updates: - work_updates (c, msg_id); - return; - case CODE_update_short_message: - work_update_short_message (c, msg_id); - return; - case CODE_update_short_chat_message: - work_update_short_chat_message (c, msg_id); - return; - case CODE_gzip_packed: - work_packed (c, msg_id); - return; - case CODE_bad_server_salt: - work_bad_server_salt (c, msg_id); - return; - case CODE_pong: - work_pong (c, msg_id); - return; - case CODE_msg_detailed_info: - work_detailed_info (c, msg_id); - return; - case CODE_msg_new_detailed_info: - work_new_detailed_info (c, msg_id); - return; - case CODE_updates_too_long: - work_updates_to_long (c, msg_id); - return; - case CODE_bad_msg_notification: - work_bad_msg_notification (c, msg_id); - return; - } - debug ( "Unknown message: \n"); - hexdump_in (c->mtconnection); - c->mtconnection->in_ptr = c->mtconnection->in_end; // Will not fail due to assertion in_ptr == in_end -} - -int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, int len) { - const int MINSZ = offsetof (struct encrypted_message, message); - const int UNENCSZ = offsetof (struct encrypted_message, server_salt); - debug ( "process_rpc_message(), len=%d\n", len); - assert (len >= MINSZ && (len & 15) == (UNENCSZ & 15)); - struct dc *DC = GET_DC(c); - assert (enc->auth_key_id == DC->auth_key_id); - assert (DC->auth_key_id); - init_aes_auth (c->mtconnection, DC->auth_key + 8, enc->msg_key, AES_DECRYPT); - int l = pad_aes_decrypt (c->mtconnection, (char *)&enc->server_salt, len - UNENCSZ, (char *)&enc->server_salt, len - UNENCSZ); - assert (l == len - UNENCSZ); - //assert (enc->auth_key_id2 == enc->auth_key_id); - assert (!(enc->msg_len & 3) && enc->msg_len > 0 && enc->msg_len <= len - MINSZ && len - MINSZ - enc->msg_len <= 12); - static unsigned char sha1_buffer[20]; - sha1 ((void *)&enc->server_salt, enc->msg_len + (MINSZ - UNENCSZ), sha1_buffer); - assert (!memcmp (&enc->msg_key, sha1_buffer + 4, 16)); - //assert (enc->server_salt == server_salt); //in fact server salt can change - if (DC->server_salt != enc->server_salt) { - DC->server_salt = enc->server_salt; - //write_auth_file (); - } - - int this_server_time = enc->msg_id >> 32LL; - if (!DC->server_time_delta) { - DC->server_time_delta = this_server_time - get_utime (CLOCK_REALTIME); - DC->server_time_udelta = this_server_time - get_utime (CLOCK_MONOTONIC); - } - double st = get_server_time (DC); - if (this_server_time < st - 300 || this_server_time > st + 30) { - debug ("salt = %lld, session_id = %lld, msg_id = %lld, seq_no = %d, st = %lf, now = %lf\n", - enc->server_salt, enc->session_id, enc->msg_id, enc->seq_no, st, get_utime (CLOCK_REALTIME)); - c->mtconnection->in_ptr = enc->message; - c->mtconnection->in_end = c->mtconnection->in_ptr + (enc->msg_len / 4); - hexdump_in (c->mtconnection); - } - - assert (this_server_time >= st - 300 && this_server_time <= st + 30); - //assert (enc->msg_id > server_last_msg_id && (enc->msg_id & 3) == 1); - debug ( "received mesage id %016llx\n", enc->msg_id); - hexdump_in (c->mtconnection); - c->mtconnection->server_last_msg_id = enc->msg_id; - - //*(long long *)(longpoll_query + 3) = *(long long *)((char *)(&enc->msg_id) + 0x3c); - //*(long long *)(longpoll_query + 5) = *(long long *)((char *)(&enc->msg_id) + 0x3c); - - assert (l >= (MINSZ - UNENCSZ) + 8); - //assert (enc->message[0] == CODE_rpc_result && *(long long *)(enc->message + 1) == client_last_msg_id); - ++c->mtconnection->good_messages; - - c->mtconnection->in_ptr = enc->message; - c->mtconnection->in_end = c->mtconnection->in_ptr + (enc->msg_len / 4); - - if (enc->msg_id & 1) { - insert_msg_id (c->session, enc->msg_id); - } - assert (c->session->session_id == enc->session_id); - rpc_execute_answer (c, enc->msg_id); - assert (c->mtconnection->in_ptr == c->mtconnection->in_end); - return 0; -} - - -int rpc_execute (struct connection *c, int op, int len) { - debug ("outbound rpc connection #%d : received rpc answer %d with %d content bytes\n", c->fd, op, len); - struct mtproto_connection *self = c->mtconnection; - struct telegram *instance = c->instance; - - /* - if (op < 0) { - assert (read_in (c, Response, Response_len) == Response_len); - return 0; - } - */ - - if (len >= MAX_RESPONSE_SIZE/* - 12*/ || len < 0/*12*/) { - debug ( "answer too long (%d bytes), skipping\n", len); - return 0; - } - - int Response_len = len; - - if (verbosity >= 2) { - debug ("Response_len = %d\n", Response_len); - } - assert (read_in (c, Response, Response_len) == Response_len); - Response[Response_len] = 0; - if (verbosity >= 2) { - debug ( "have %d Response bytes\n", Response_len); - } - - int o = c->mtconnection->c_state; - if (GET_DC(c)->flags & 1) { o = st_authorized;} - switch (o) { - case st_reqpq_sent: - process_respq_answer (c, Response/* + 8*/, Response_len/* - 12*/); - return 0; - case st_reqdh_sent: - process_dh_answer (c, Response/* + 8*/, Response_len/* - 12*/); - return 0; - case st_client_dh_sent: - process_auth_complete (c, Response/* + 8*/, Response_len/* - 12*/); - self->queries_num --; - debug ("queries_num=%d\n", c->mtconnection->queries_num); - if (self->on_ready) { - self->on_ready(self, self->on_ready_data); - } - return 0; - case st_authorized: - if (op < 0 && op >= -999) { - debug ("Server error %d\n", op); - char code[12] = {0}; - snprintf (code, 12, "%d", op); - c->mtconnection->c_state = st_error; - telegram_change_state (instance, STATE_ERROR, code); - } else { - process_rpc_message (c, (void *)(Response/* + 8*/), Response_len/* - 12*/); - } - return 0; - default: - debug ( "fatal: cannot receive answer in state %d\n", c->mtconnection->c_state); - exit (2); - } - - return 0; -} - - -int tc_close (struct connection *c, int who) { - debug ( "outbound http connection #%d : closing by %d\n", c->fd, who); - return 0; -} - -int tc_becomes_ready (struct connection *c) { - debug ( "outbound connection #%d becomes ready\n", c->fd); - char byte = 0xef; - assert (write_out (c, &byte, 1) == 1); - flush_out (c); - - int o = c->mtconnection->c_state; - if (GET_DC(c)->flags & 1) { - o = st_authorized; - } - switch (o) { - case st_init: - c->mtconnection->queries_num ++; - debug ("queries_num=%d\n", c->mtconnection->queries_num); - send_req_pq_packet (c); - break; - case st_authorized: - c->mtconnection->on_ready(c->mtconnection, c->mtconnection->on_ready_data); - //telegram_change_state (c->instance, STATE_AUTHORIZED, NULL); - break; - default: - debug ( "c_state = %d\n", c->mtconnection->c_state); - assert (0); - } - return 0; -} - -int rpc_becomes_ready (struct connection *c) { - return tc_becomes_ready (c); -} - -int rpc_close (struct connection *c) { - return tc_close (c, 0); -} - -int auth_is_success (struct mtproto_connection *m) { - return m->auth_success; -} - - -#define RANDSEED_PASSWORD_FILENAME NULL -#define RANDSEED_PASSWORD_LENGTH 0 -void on_start (struct mtproto_connection *self) { - prng_seed (self, RANDSEED_PASSWORD_FILENAME, RANDSEED_PASSWORD_LENGTH); - - if (rsa_public_key_name) { - if (rsa_load_public_key (rsa_public_key_name) < 0) { - perror ("rsa_load_public_key"); - exit (1); - } - } else { - if (rsa_load_public_key (TG_SERVER_PUBKEY_FILENAME) < 0 - && rsa_load_public_key ("/etc/" PROG_NAME "/server.pub") < 0) { - perror ("rsa_load_public_key"); - exit (1); - } - } - pk_fingerprint = compute_rsa_key_fingerprint (pubKey); -} - - -struct connection_methods mtproto_methods = { - .execute = rpc_execute, - .ready = rpc_becomes_ready, - .close = rpc_close -}; - -/** - * Create a new struct mtproto_connection connection using the giving datacenter for authorization and - * session handling - */ -struct mtproto_connection *mtproto_new(struct dc *DC, int fd, struct telegram *tg) -{ - struct mtproto_connection *mtp = talloc0(sizeof(struct mtproto_connection)); - tg->Cs[tg->cs++] = mtp; - mtp->instance = tg; - mtp->packet_buffer = mtp->__packet_buffer + 16; - mtp->connection = fd_create_connection(DC, fd, tg, &mtproto_methods, mtp); - assert (tg->bl); - mtp->bl = tg->bl; - return mtp; -} - -/** - * Connect to the network - */ -void mtproto_connect(struct mtproto_connection *c) -{ - on_start(c); - start_ping_timer (c->connection); - c->connection->methods->ready(c->connection); -} - -/** - * Mark the connection for destruction, stop all timers and initiate - * cleanup tasks - */ -void mtproto_close(struct mtproto_connection *mtp) { - debug ("closing mtproto_connection...\n"); - mtp->destroy = 1; - - // send all pending acks on this connection so the server won't - // resend messages. We might not be able to send the acknowledgements later - // in case the session is switched and this DC is not reachable anymore - if (mtp->connection) { - if (mtp->connection->session && mtp->connection->session->ack_tree) { - struct session *S = mtp->connection->session; - send_all_acks (S); - mtp->instance->config->on_output(mtp->handle); - S->c = 0; - } - stop_ping_timer (mtp->connection); - } -} - -/** - * Close the underlying file descriptor - */ -void mtproto_destroy (struct mtproto_connection *self) { - debug("destroying mtproto_connection: %p\n", self); - self->instance->config->proxy_close_cb(self->handle); - fd_close_connection(self->connection); - tfree(self, sizeof(struct mtproto_connection)); -} - -void mtproto_close_foreign (struct telegram *instance) -{ - int i; - for (i = 0; i < 100; i++) { - struct mtproto_connection * c = instance->Cs[i]; - if (c && - !c->destroy && - c->connection->session->dc->id != instance->auth.dc_working_num) { - debug ("closing connection for working_dc=%d, dc=%d\n", - instance->auth.dc_working_num, c->connection->session->dc->id); - mtproto_close (c); - } - } -} - -/** - * Free all destroyed connections - */ -void mtproto_free_closed (struct telegram *tg, int force) { - int i; - for (i = 0; i < 100; i++) { - if (tg->Cs[i] == NULL) continue; - struct mtproto_connection *c = tg->Cs[i]; - debug ("checking mtproto_connection %d: c_state:%d destroy:%d, quries_num:%d\n", - i, c->c_state, c->destroy, c->queries_num); - if (c->destroy == 0) continue; - if (!force && c->connection->out_bytes > 0) { - debug ("still %d bytes ouput left, skipping connection...\n", c->connection->out_bytes); - continue; - } - mtproto_destroy (c); - if (tg->connection == c) { - tg->connection = NULL; - } - tg->Cs[i] = NULL; - } -} - diff --git a/mtproto-client.h b/mtproto-client.h deleted file mode 100644 index 073e353..0000000 --- a/mtproto-client.h +++ /dev/null @@ -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 . - -Copyright Nikolay Durov, Andrey Lopatin 2012-2013 - Copyright Vitaly Valtman 2013 -*/ -#ifndef __MTPROTO_CLIENT_H__ -#define __MTPROTO_CLIENT_H__ - - -/* - * COMMON - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "include.h" -#include "tools.h" -#include "constants.h" -#include "msglog.h" -#include "net.h" - -#ifdef __MACH__ -#include -#include -#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 - diff --git a/mtproto-common.c b/mtproto-common.c deleted file mode 100644 index e2db1a5..0000000 --- a/mtproto-common.c +++ /dev/null @@ -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 diff --git a/net.c b/net.c deleted file mode 100644 index 97763cc..0000000 --- a/net.c +++ /dev/null @@ -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 . - - Copyright Vitaly Valtman 2013 -*/ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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)); -} - diff --git a/net.h b/net.h deleted file mode 100644 index e6ddd63..0000000 --- a/net.h +++ /dev/null @@ -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 . - - Copyright Vitaly Valtman 2013 -*/ -#ifndef __NET_H__ -#define __NET_H__ - -#pragma once - -#include -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 diff --git a/no-preview.h b/no-preview.h deleted file mode 100644 index ee6bc7e..0000000 --- a/no-preview.h +++ /dev/null @@ -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 . - - 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}; diff --git a/purple-plugin/telegram.svg b/purple-plugin/telegram.svg deleted file mode 100644 index 1331624..0000000 --- a/purple-plugin/telegram.svg +++ /dev/null @@ -1,177 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/queries.c b/queries.c deleted file mode 100644 index 633ca26..0000000 --- a/queries.c +++ /dev/null @@ -1,3095 +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 . - - Copyright Vitaly Valtman 2013 -*/ - -#define _FILE_OFFSET_BITS 64 -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef PATH_MAX -#define PATH_MAX 4096 -#endif - -#include "include.h" -#include "mtproto-client.h" -#include "queries.h" -#include "tree.h" -#include "loop.h" -#include "structures.h" -#include "net.h" -#include -#include -#include -#include -#include - -#include "no-preview.h" -#include "binlog.h" -#include "telegram.h" -#include "msglog.h" -#include "purple-plugin/telegram-purple.h" - -#define sha1 SHA1 - -#ifdef __APPLE__ -#define OPEN_BIN "open %s" -#else -#define OPEN_BIN "xdg-open %s" -#endif - -char *get_downloads_directory (void); -int verbosity; -int offline_mode = 0; - -#define memcmp8(a,b) memcmp ((a), (b), 8) -DEFINE_TREE (query, struct query *, memcmp8, 0) ; - -#define event_timer_cmp(a,b) ((a)->timeout > (b)->timeout ? 1 : ((a)->timeout < (b)->timeout ? -1 : (memcmp (a, b, sizeof (struct event_timer))))) -DEFINE_TREE (timer, struct event_timer *, event_timer_cmp, 0) - -void out_peer_id (struct mtproto_connection *self, peer_id_t id); -#define QUERY_TIMEOUT 6.0 - -/** - * Get the struct mtproto_connection connection this connection was attached to - */ -struct mtproto_connection *query_get_mtproto(struct query *q) { - return q->DC->sessions[0]->c->mtconnection; -} - -double get_double_time (void) { - struct timespec tv; - my_clock_gettime (CLOCK_REALTIME, &tv); - return tv.tv_sec + 1e-9 * tv.tv_nsec; -} - -struct query *query_get (struct telegram *instance, long long id) { - return tree_lookup_query (instance->queries_tree, (void *)&id); -} - -int alarm_query (struct query *q) { - assert (q); - struct mtproto_connection *mtp = query_get_mtproto(q); - debug ("Alarm query %lld\n", q->msg_id); - q->ev.timeout = get_double_time () + QUERY_TIMEOUT; - insert_event_timer (mtp->connection->instance, &q->ev); - - if (q->session->c->out_bytes >= 100000) { - return 0; - } - - clear_packet (mtp); - out_int (mtp, CODE_msg_container); - out_int (mtp, 1); - out_long (mtp, q->msg_id); - out_int (mtp, q->seq_no); - out_int (mtp, 4 * q->data_len); - out_ints (mtp, q->data, q->data_len); - - encrypt_send_message (mtp, mtp->packet_buffer, mtp->packet_ptr - mtp->packet_buffer, 0); - return 0; -} - -void query_restart (struct telegram *instance, long long id) { - struct query *q = query_get (instance, id); - if (q) { - remove_event_timer (instance, &q->ev); - alarm_query (q); - } -} - -struct query *send_query (struct telegram *instance, struct dc *DC, int ints, void *data, struct query_methods *methods, void *extra) { - info ("SEND_QUERY() size %d to DC %d(%s:%d)\n", 4 * ints, DC->id, DC->ip, DC->port); - struct query *q = talloc0 (sizeof (*q)); - q->data_len = ints; - q->data = talloc (4 * ints); - memcpy (q->data, data, 4 * ints); - q->msg_id = encrypt_send_message (DC->sessions[0]->c->mtconnection, data, ints, 1); - q->session = DC->sessions[0]; - q->seq_no = DC->sessions[0]->seq_no - 1; - //debug ( "Msg_id is %lld %p\n", q->msg_id, q); - q->methods = methods; - q->DC = DC; - if (instance->queries_tree) { - if (verbosity >= 2) { - debug ( "%lld %lld\n", q->msg_id, instance->queries_tree->x->msg_id); - } - } - - instance->queries_tree = tree_insert_query (instance->queries_tree, q, lrand48 ()); - struct mtproto_connection *mtp = query_get_mtproto(q); - ++ mtp->queries_num; - - q->ev.alarm = (void *)alarm_query; - q->ev.timeout = get_double_time () + QUERY_TIMEOUT; - q->ev.self = (void *)q; - insert_event_timer (instance, &q->ev); - - q->extra = extra; - return q; -} - -void query_ack (struct telegram *instance, long long id) { - struct query *q = query_get (instance, id); - if (q && !(q->flags & QUERY_ACK_RECEIVED)) { - assert (q->msg_id == id); - q->flags |= QUERY_ACK_RECEIVED; - remove_event_timer (instance, &q->ev); - } -} - -void query_error (struct telegram *instance, long long id) { - struct query *q = query_get (instance, id); - struct mtproto_connection *mtp = query_get_mtproto(q); - - assert (fetch_int (mtp) == CODE_rpc_error); - int error_code = fetch_int (mtp); - int error_len = prefetch_strlen (mtp); - char *err = fetch_str (mtp, error_len); - failure ( "error for query #%lld: #%d :%.*s\n", id, error_code, error_len, err); - if (!q) { - failure ( "No such query\n"); - } else { - if (!(q->flags & QUERY_ACK_RECEIVED)) { - remove_event_timer (instance, &q->ev); - } - instance->queries_tree = tree_delete_query (instance->queries_tree, q); - -- mtp->queries_num; - - if (q->methods && q->methods->on_error) { - q->methods->on_error (q, error_code, error_len, err); - } else { - failure ( "error for query #%lld: #%d :%.*s\n", id, error_code, error_len, err); - } - tfree (q->data, q->data_len * 4); - tfree (q, sizeof (*q)); - return; - } - -} - -void query_result (struct telegram *instance, long long id UU) { - struct query *q = query_get (instance, id); - struct mtproto_connection *mtp = query_get_mtproto(q); - - debug ( "result for query #%lld\n", id); - if (verbosity >= 4) { - debug ( "result: "); - hexdump_in (mtp); - } - - int op = prefetch_int (mtp); - int *end = 0; - int *eend = 0; - if (op == CODE_gzip_packed) { - fetch_int (mtp); - int l = prefetch_strlen (mtp); - char *s = fetch_str (mtp, l); - int total_out = tinflate (s, l, instance->packed_buffer, MAX_PACKED_SIZE); - end = mtp->in_ptr; - eend = mtp->in_end; - //assert (total_out % 4 == 0); - mtp->in_ptr = instance->packed_buffer; - mtp->in_end = mtp->in_ptr + total_out / 4; - if (verbosity >= 4) { - debug ( "Unzipped data: "); - hexdump_in (mtp); - } - } - if (!q) { - warning ( "No such query\n"); - mtp->in_ptr = mtp->in_end; - } else { - if (!(q->flags & QUERY_ACK_RECEIVED)) { - remove_event_timer (instance, &q->ev); - } - instance->queries_tree = tree_delete_query (instance->queries_tree, q); - debug("queries_num: %d\n", -- mtp->queries_num); - - if (q->methods && q->methods->on_answer) { - q->methods->on_answer (q); - assert (mtp->in_ptr == mtp->in_end); - } - tfree (q->data, 4 * q->data_len); - tfree (q, sizeof (*q)); - } - if (end) { - mtp->in_ptr = end; - mtp->in_end = eend; - } -} - - -void insert_event_timer (struct telegram *instance, struct event_timer *ev) { - // debug ( "INSERT: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); - instance->timer_tree = tree_insert_timer (instance->timer_tree, ev, lrand48 ()); -} - -void remove_event_timer (struct telegram *instance, struct event_timer *ev) { - // debug ( "REMOVE: %lf %p %p\n", ev->timeout, ev->self, ev->alarm); - instance->timer_tree = tree_delete_timer (instance->timer_tree, ev); -} - -double next_timer_in (struct telegram *instance) { - if (!instance->timer_tree) { return 1e100; } - return tree_get_min_timer (instance->timer_tree)->timeout; -} - -void work_timers (struct telegram *instance) { - debug ("work_timers ()\n"); - double t = get_double_time (); - while (instance->timer_tree) { - struct event_timer *ev = tree_get_min_timer (instance->timer_tree); - assert (ev); - if (ev->timeout > t) { break; } - remove_event_timer (instance, ev); - assert (ev->alarm); - debug ("Alarm\n"); - ev->alarm (ev->self); - } -} - -void free_timers (struct telegram *instance) -{ - while (instance->timer_tree) { - struct event_timer *ev = tree_get_min_timer (instance->timer_tree); - assert (ev); - debug ("freeing event timer with timeout: %d\n", ev->timeout); - remove_event_timer (instance, ev); - //tfree (ev, sizeof(struct event_timer)); - } -} - -void free_queries (struct telegram *instance) -{ - while (instance->queries_tree) { - struct query *q = tree_get_min_query (instance->queries_tree); - assert (q); - debug ("freeing query with msg_id %d and len\n", q->msg_id, q->data_len); - tfree (q->data, 4 * q->data_len); - instance->queries_tree = tree_delete_query (instance->queries_tree, q); - //tfree (q, sizeof (struct query)); - } -} - -//extern struct dc *DC_list[]; -//extern struct dc *DC_working; - -void out_random (struct mtproto_connection *mtp, int n) { - assert (n <= 32); - static char buf[32]; - secure_random (buf, n); - out_cstring (mtp, buf, n); -} - -int allow_send_linux_version; -void do_insert_header (struct mtproto_connection *mtp) { - out_int (mtp, CODE_invoke_with_layer12); - out_int (mtp, CODE_init_connection); - out_int (mtp, TG_APP_ID); - if (allow_send_linux_version) { - struct utsname st; - uname (&st); - out_string (mtp, st.machine); - static char buf[4096]; - tsnprintf (buf, sizeof (buf), "%.999s %.999s %.999s\n", st.sysname, st.release, st.version); - out_string (mtp, buf); - out_string (mtp, TG_VERSION " (build " TG_BUILD ")"); - out_string (mtp, "En"); - } else { - out_string (mtp, "x86"); - out_string (mtp, "Linux"); - out_string (mtp, TG_VERSION); - out_string (mtp, "en"); - } -} - -/* {{{ Get config */ - -void fetch_dc_option (struct telegram *instance) { - info ("fetch_dc_option()\n"); - struct mtproto_connection *mtp = instance->connection; - - assert (fetch_int (mtp) == CODE_dc_option); - int id = fetch_int (mtp); - int l1 = prefetch_strlen (mtp); - char *name = fetch_str (mtp, l1); - int l2 = prefetch_strlen (mtp); - char *ip = fetch_str (mtp, l2); - int port = fetch_int (mtp); - debug ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port); - - bl_do_dc_option (mtp->bl, mtp, id, l1, name, l2, ip, port, instance); -} - -int help_get_config_on_answer (struct query *q UU) { - struct telegram *instance = q->extra; - struct mtproto_connection *mtp = query_get_mtproto(q); - - unsigned op = fetch_int (mtp); - assert (op == CODE_config || op == CODE_config_old); - fetch_int (mtp); - - unsigned test_mode = fetch_int (mtp); - assert (test_mode == CODE_bool_true || test_mode == CODE_bool_false); - assert (test_mode == CODE_bool_false || test_mode == CODE_bool_true); - int this_dc = fetch_int (mtp); - debug ( "this_dc = %d\n", this_dc); - assert (fetch_int (mtp) == CODE_vector); - int n = fetch_int (mtp); - assert (n <= 10); - int i; - for (i = 0; i < n; i++) { - fetch_dc_option (instance); - } - instance->max_chat_size = fetch_int (mtp); - if (op == CODE_config) { - instance->max_bcast_size = fetch_int (mtp); - } - debug ( "max_chat_size = %d\n", instance->max_chat_size); - - telegram_change_state(instance, STATE_CONFIG_RECEIVED, NULL); - return 0; -} - -struct query_methods help_get_config_methods = { - .on_answer = help_get_config_on_answer -}; - -void do_help_get_config (struct telegram *instance) { - info ("do_help_get_config()\n"); - struct mtproto_connection *mtp = instance->connection; - - debug ("mtp: %p:%p\n", mtp->packet_ptr, mtp->packet_buffer); - clear_packet (mtp); - out_int (mtp, CODE_help_get_config); - struct dc *DC_working = telegram_get_working_dc(instance); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, - mtp->packet_buffer, &help_get_config_methods, instance); -} -/* }}} */ - -/* {{{ Send code */ -int send_code_on_answer (struct query *q UU) { - struct telegram *instance = q->extra; - struct mtproto_connection *mtp = query_get_mtproto(q); - - assert (fetch_int (mtp) == (int)CODE_auth_sent_code); - fetch_bool (mtp); - int l = prefetch_strlen (mtp); - char *phone_code_hash = tstrndup (fetch_str (mtp, l), l); - instance->phone_code_hash = phone_code_hash; - debug("telegram: phone_code_hash: %s\n", phone_code_hash); - fetch_int (mtp); - fetch_bool (mtp); - instance->want_dc_num = -1; - if (instance->session_state == STATE_PHONE_CODE_REQUESTED) { - telegram_change_state(instance, STATE_PHONE_CODE_NOT_ENTERED, NULL); - } else if (instance->session_state == STATE_CLIENT_CODE_REQUESTED) { - telegram_change_state(instance, STATE_CLIENT_CODE_NOT_ENTERED, NULL); - } else { - debug("send_code_on_answer(): Invalid State %d ", instance->session_state); - telegram_change_state(instance, STATE_ERROR, NULL); - } - return 0; -} - -int send_code_on_error (struct query *q UU, int error_code, int l, char *error) { - struct telegram *tg = q->extra; - - int s = strlen ("PHONE_MIGRATE_"); - int s2 = strlen ("NETWORK_MIGRATE_"); - if (l >= s && !memcmp (error, "PHONE_MIGRATE_", s)) { - int want_dc_num = error[s] - '0'; - tg->auth.dc_working_num = want_dc_num; - telegram_change_state(tg, STATE_DISCONNECTED_SWITCH_DC, error); - } else if (l >= s2 && !memcmp (error, "NETWORK_MIGRATE_", s2)) { - int want_dc_num = error[s2] - '0'; - tg->auth.dc_working_num = want_dc_num; - telegram_change_state(tg, STATE_DISCONNECTED_SWITCH_DC, error); - } else { - fatal ( "error_code = %d, error = %.*s\n", error_code, l, error); - telegram_change_state(tg, STATE_ERROR, error); - } - return 0; -} - -struct query_methods send_code_methods = { - .on_answer = send_code_on_answer, - .on_error = send_code_on_error -}; - -void do_send_code (struct telegram *instance, const char *user) { - info ("do_send_code()\n"); - struct mtproto_connection *mtp = instance->connection; - - instance->suser = tstrdup (user); - instance->want_dc_num = 0; - clear_packet (mtp); - do_insert_header (mtp); - out_int (mtp, CODE_auth_send_code); - out_string (mtp, user); - out_int (mtp, 0); - out_int (mtp, TG_APP_ID); - out_string (mtp, TG_APP_HASH); - out_string (mtp, "en"); - - debug ("send_code: dc_num = %d\n", instance->auth.dc_working_num); - send_query (instance, telegram_get_working_dc(instance), mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_code_methods, instance); - if (instance->session_state == STATE_PHONE_NOT_REGISTERED) { - telegram_change_state(instance, STATE_PHONE_CODE_REQUESTED, NULL); - } else if (instance->session_state == STATE_CLIENT_NOT_REGISTERED) { - telegram_change_state(instance, STATE_CLIENT_CODE_REQUESTED, NULL); - } else { - fatal ("do_send_code() Invalid State %d, erroring\n", instance->session_state); - telegram_change_state(instance, STATE_ERROR, NULL); - } -} - - -int phone_call_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - fetch_bool (mtp); - return 0; -} - -int phone_call_on_error (struct query *q UU, int error_code, int l, char *error) { - fatal ( "error_code = %d, error = %.*s\n", error_code, l, error); - telegram_change_state(q->data, STATE_ERROR, error); - return 0; -} - -struct query_methods phone_call_methods = { - .on_answer = phone_call_on_answer, - .on_error = phone_call_on_error -}; - -void do_phone_call (struct telegram *instance, const char *user) { - struct mtproto_connection *mtp = instance->connection; - - debug ("calling user\n"); - instance->suser = tstrdup (user); - instance->want_dc_num = 0; - clear_packet (mtp); - do_insert_header (mtp); - out_int (mtp, CODE_auth_send_call); - out_string (mtp, user); - out_string (mtp, instance->phone_code_hash); - - info ("do_phone_call: dc_num = %d\n", instance->auth.dc_working_num); - send_query (instance, telegram_get_working_dc(instance), mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &phone_call_methods, instance); -} -/* }}} */ - -/* {{{ Check phone */ -int check_phone_result; -int cr_f (void) { - return check_phone_result >= 0; -} - -int check_phone_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - assert (fetch_int (mtp) == (int)CODE_auth_checked_phone); - check_phone_result = fetch_bool (mtp); - fetch_bool (mtp); - - assert (mtp->connection->instance->session_state == STATE_CONFIG_RECEIVED); - debug ("check_phone_result=%d\n", check_phone_result); - telegram_change_state (mtp->connection->instance, - check_phone_result ? STATE_CLIENT_NOT_REGISTERED : STATE_PHONE_NOT_REGISTERED, NULL); - return 0; -} - -int check_phone_on_error (struct query *q UU, int error_code, int l, char *error) { - int s = strlen ("PHONE_MIGRATE_"); - int s2 = strlen ("NETWORK_MIGRATE_"); - struct telegram* instance = q->extra; - - if (l >= s && !memcmp (error, "PHONE_MIGRATE_", s)) { - // update used data centre - int i = error[s] - '0'; - instance->auth.dc_working_num = i; - - //bl_do_set_working_dc (i); - //check_phone_result = 1; - } else if (l >= s2 && !memcmp (error, "NETWORK_MIGRATE_", s2)) { - // update used data centre - int i = error[s2] - '0'; - instance->auth.dc_working_num = i; - //bl_do_set_working_dc (i); - - //check_phone_result = 1; - } else { - failure ( "error_code = %d, error = %.*s\n", error_code, l, error); - telegram_change_state(instance, STATE_ERROR, error); - return -1; - } - telegram_change_state(instance, - STATE_DISCONNECTED_SWITCH_DC, &instance->auth.dc_working_num); - return 0; -} - -struct query_methods check_phone_methods = { - .on_answer = check_phone_on_answer, - .on_error = check_phone_on_error -}; - -void do_auth_check_phone (struct telegram *instance, const char *user) { - struct mtproto_connection *mtp = instance->connection; - - instance->suser = tstrdup (user); - clear_packet (mtp); - out_int (mtp, CODE_auth_check_phone); - out_string (mtp, user); - check_phone_result = -1; - struct dc *DC_working = telegram_get_working_dc(instance); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, - &check_phone_methods, instance); -} -/* }}} */ - -/* {{{ Nearest DC */ - -int nearest_dc_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - struct telegram *instance = mtp->connection->instance; - - assert (fetch_int (mtp) == (int)CODE_nearest_dc); - char *country = fetch_str_dup (mtp); - debug ("Server thinks that you are in %s\n", country); - fetch_int (mtp); // this_dc - instance->nearest_dc_num = fetch_int (mtp); - assert (instance->nearest_dc_num >= 0); - return 0; -} - -int fail_on_error (struct query *q UU, int error_code UU, int l UU, char *error UU) { - fatal ("error #%d: %.*s\n", error_code, l, error); - telegram_change_state(q->data, STATE_ERROR, error); - return 0; -} - -struct query_methods nearest_dc_methods = { - .on_answer = nearest_dc_on_answer, - .on_error = fail_on_error -}; - -void do_get_nearest_dc (struct telegram *instance) { - struct mtproto_connection *mtp = instance->connection; - struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (mtp); - out_int (mtp, CODE_help_get_nearest_dc); - instance->nearest_dc_num = -1; - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &nearest_dc_methods, instance); - //net_loop (0, nr_f); - //return nearest_dc_num; -} -/* }}} */ - -/* {{{ Sign in / Sign up */ - -int sign_in_on_answer (struct query *q) { - info ("sign_in_on_answer()\n"); - struct mtproto_connection *mtp = query_get_mtproto(q); - struct telegram *instance = mtp->connection->instance; - - struct dc *DC_working = telegram_get_working_dc(mtp->connection->instance); - assert (fetch_int (mtp) == (int)CODE_auth_authorization); - int expires = fetch_int (mtp); - fetch_user (mtp, &instance->User); - if (!instance->our_id) { - instance->our_id = get_peer_id (instance->User.id); - bl_do_set_our_id (mtp->bl, mtp, instance->our_id); - } - debug ( "telegram: authorized successfully: name = '%s %s', phone = '%s', expires = %d\n", - instance->User.first_name, instance->User.last_name, instance->User.phone, (int)(expires - get_double_time ())); - DC_working->has_auth = 1; - - bl_do_dc_signed (mtp->bl, mtp, DC_working->id); - telegram_change_state (mtp->connection->instance, STATE_READY, NULL); - return 0; -} - -int sign_in_on_error (struct query *q UU, int error_code, int l, char *error) { - info ("sign_in_on_error()\n"); - struct mtproto_connection *mtp = query_get_mtproto(q); - failure ( "error_code = %d, error = %.*s\n", error_code, l, error); - int state = STATE_CLIENT_CODE_NOT_ENTERED; - if (mtp->instance->session_state == STATE_PHONE_CODE_NOT_ENTERED) { - state = STATE_PHONE_CODE_NOT_ENTERED; - } - telegram_change_state (mtp->connection->instance, state, NULL); - return 0; -} - -struct query_methods sign_in_methods = { - .on_answer = sign_in_on_answer, - .on_error = sign_in_on_error -}; - -void do_send_code_result (struct telegram *instance, const char *code) { - info ("do_send_code_result()\n"); - struct mtproto_connection *mtp = instance->connection; - assert (instance->session_state == STATE_CLIENT_CODE_NOT_ENTERED); - - struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (mtp); - out_int (mtp, CODE_auth_sign_in); - out_string (mtp, instance->suser); - out_string(mtp, instance->phone_code_hash); - out_string (mtp, code); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, - &sign_in_methods, instance); -} - -void do_send_code_result_auth (struct telegram *instance, const char *code, const char *first_name, const char *last_name) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - - clear_packet (mtp); - out_int (mtp, CODE_auth_sign_up); - out_string (mtp, instance->suser); - out_string (mtp, instance->phone_code_hash); - out_string (mtp, code); - out_string (mtp, first_name); - out_string (mtp, last_name); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &sign_in_methods, instance); -} -/* }}} */ - -/* {{{ Get contacts */ -extern char *user_list[]; - -int get_contacts_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - int i; - assert (fetch_int (mtp) == (int)CODE_contacts_contacts); - assert (fetch_int (mtp) == CODE_vector); - int n = fetch_int (mtp); - for (i = 0; i < n; i++) { - assert (fetch_int (mtp) == (int)CODE_contact); - fetch_int (mtp); // id - fetch_int (mtp); // mutual - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_user (mtp); - } - return 0; -} - -struct query_methods get_contacts_methods = { - .on_answer = get_contacts_on_answer, -}; - -void do_update_contact_list (struct telegram *instance) { - struct mtproto_connection *mtp = instance->connection; - struct dc *DC_working = telegram_get_working_dc(instance); - - clear_packet (mtp); - out_int (mtp, CODE_contacts_get_contacts); - out_string (mtp, ""); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_contacts_methods, instance); -} - - -/* }}} */ - -/* {{{ Encrypt decrypted */ - -char *encrypt_decrypted_message (struct mtproto_connection *mtp, struct secret_chat *E) { - static int msg_key[4]; - static unsigned char sha1a_buffer[20]; - static unsigned char sha1b_buffer[20]; - static unsigned char sha1c_buffer[20]; - static unsigned char sha1d_buffer[20]; - int x = *(mtp->encr_ptr); - assert (x >= 0 && !(x & 3)); - sha1 ((void *)mtp->encr_ptr, 4 + x, sha1a_buffer); - memcpy (msg_key, sha1a_buffer + 4, 16); - - static unsigned char buf[64]; - memcpy (buf, msg_key, 16); - memcpy (buf + 16, E->key, 32); - sha1 (buf, 48, sha1a_buffer); - - memcpy (buf, E->key + 8, 16); - memcpy (buf + 16, msg_key, 16); - memcpy (buf + 32, E->key + 12, 16); - sha1 (buf, 48, sha1b_buffer); - - memcpy (buf, E->key + 16, 32); - memcpy (buf + 32, msg_key, 16); - sha1 (buf, 48, sha1c_buffer); - - memcpy (buf, msg_key, 16); - memcpy (buf + 16, E->key + 24, 32); - sha1 (buf, 48, sha1d_buffer); - - static unsigned char key[32]; - memcpy (key, sha1a_buffer + 0, 8); - memcpy (key + 8, sha1b_buffer + 8, 12); - memcpy (key + 20, sha1c_buffer + 4, 12); - - static unsigned char iv[32]; - memcpy (iv, sha1a_buffer + 8, 12); - memcpy (iv + 12, sha1b_buffer + 0, 8); - memcpy (iv + 20, sha1c_buffer + 16, 4); - memcpy (iv + 24, sha1d_buffer + 0, 8); - - AES_KEY aes_key; - AES_set_encrypt_key (key, 256, &aes_key); - AES_ige_encrypt ((void *)mtp->encr_ptr, (void *)mtp->encr_ptr, 4 * (mtp->encr_end - mtp->encr_ptr), &aes_key, iv, 1); - memset (&aes_key, 0, sizeof (aes_key)); - - return (void *)msg_key; -} - -void encr_start (struct mtproto_connection *mtp) { - mtp->encr_extra = mtp->packet_ptr; - mtp->packet_ptr += 1; // str len - mtp->packet_ptr += 2; // fingerprint - mtp->packet_ptr += 4; // msg_key - mtp->packet_ptr += 1; // len -} - - -void encr_finish (struct mtproto_connection *mtp, struct secret_chat *E) { - int l = mtp->packet_ptr - (mtp->encr_extra + 8); - while (((mtp->packet_ptr - mtp->encr_extra) - 3) & 3) { - int t; - secure_random (&t, 4); - out_int (mtp, t); - } - - *mtp->encr_extra = ((mtp->packet_ptr - mtp->encr_extra) - 1) * 4 * 256 + 0xfe; - mtp->encr_extra ++; - *(long long *)mtp->encr_extra = E->key_fingerprint; - mtp->encr_extra += 2; - mtp->encr_extra[4] = l * 4; - mtp->encr_ptr = mtp->encr_extra + 4; - mtp->encr_end = mtp->packet_ptr; - memcpy (mtp->encr_extra, encrypt_decrypted_message (mtp, E), 16); -} -/* }}} */ - -/* {{{ Seng msg (plain text) */ -int msg_send_encr_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - assert (fetch_int (mtp) == CODE_messages_sent_encrypted_message); - debug ("Sent\n"); - struct message *M = q->extra; - //M->date = fetch_int (mtp); - fetch_int (mtp); - bl_do_set_message_sent (mtp->bl, mtp, M); - return 0; -} - -int msg_send_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - unsigned x = fetch_int (mtp); - assert (x == CODE_messages_sent_message || x == CODE_messages_sent_message_link); - int id = fetch_int (mtp); // id - struct message *M = q->extra; - bl_do_set_msg_id (mtp->bl, mtp, M, id); - fetch_date (mtp); - fetch_pts (mtp); - fetch_seq (mtp); - if (x == CODE_messages_sent_message_link) { - assert (fetch_int (mtp) == CODE_vector); - int n = fetch_int (mtp); - int i; - unsigned a, b; - for (i = 0; i < n; i++) { - assert (fetch_int (mtp) == (int)CODE_contacts_link); - a = fetch_int (mtp); - assert (a == CODE_contacts_my_link_empty || a == CODE_contacts_my_link_requested || a == CODE_contacts_my_link_contact); - if (a == CODE_contacts_my_link_requested) { - fetch_bool (mtp); - } - b = fetch_int (mtp); - assert (b == CODE_contacts_foreign_link_unknown || b == CODE_contacts_foreign_link_requested || b == CODE_contacts_foreign_link_mutual); - if (b == CODE_contacts_foreign_link_requested) { - fetch_bool (mtp); - } - struct tgl_user *U = fetch_alloc_user (mtp); - - U->flags &= ~(FLAG_USER_IN_CONTACT | FLAG_USER_OUT_CONTACT); - if (a == CODE_contacts_my_link_contact) { - U->flags |= FLAG_USER_IN_CONTACT; - } - U->flags &= ~(FLAG_USER_IN_CONTACT | FLAG_USER_OUT_CONTACT); - if (b == CODE_contacts_foreign_link_mutual) { - U->flags |= FLAG_USER_IN_CONTACT | FLAG_USER_OUT_CONTACT; - } - if (b == CODE_contacts_foreign_link_requested) { - U->flags |= FLAG_USER_OUT_CONTACT; - } - //print_start (); - //push_color (COLOR_YELLOW); - debug ("Link with user "); - //print_user_name (U->id, (void *)U); - debug (" changed\n"); - //pop_color (); - //print_end (); - } - } - debug ("Sent: id = %d\n", id); - bl_do_set_message_sent (mtp->bl, mtp, M); - return 0; -} - -int msg_send_on_error (struct query *q, int error_code, int error_len, char *error) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - debug ( "error for query #%lld: #%d :%.*s\n", q->msg_id, error_code, error_len, error); - struct message *M = q->extra; - bl_do_delete_msg (mtp->bl, mtp, M); - return 0; -} - -struct query_methods msg_send_methods = { - .on_answer = msg_send_on_answer, - .on_error = msg_send_on_error -}; - -struct query_methods msg_send_encr_methods = { - .on_answer = msg_send_encr_on_answer -}; - -void do_send_encr_msg (struct telegram *instance, struct message *M) { - struct mtproto_connection *mtp = instance->connection; - struct dc *DC_working = telegram_get_working_dc(instance); - - peer_t *P = user_chat_get (mtp->bl, M->to_id); - if (!P || P->encr_chat.state != sc_ok) { return; } - - clear_packet (mtp); - out_int (mtp, CODE_messages_send_encrypted); - out_int (mtp, CODE_input_encrypted_chat); - out_int (mtp, get_peer_id (M->to_id)); - out_long (mtp, P->encr_chat.access_hash); - out_long (mtp, M->id); - encr_start (mtp); - out_int (mtp, CODE_decrypted_message); - out_long (mtp, M->id); - static int buf[4]; - secure_random (buf, 16); - out_cstring (mtp, (void *)buf, 16); - out_cstring (mtp, (void *)M->message, M->message_len); - out_int (mtp, CODE_decrypted_message_media_empty); - encr_finish (mtp, &P->encr_chat); - - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, - &msg_send_encr_methods, M); -} - -void do_send_msg (struct telegram *instance, struct message *M) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - - if (get_peer_type (M->to_id) == PEER_ENCR_CHAT) { - do_send_encr_msg (instance ,M); - return; - } - clear_packet (mtp); - out_int (mtp, CODE_messages_send_message); - out_peer_id (mtp, M->to_id); - out_cstring (mtp, M->message, M->message_len); - out_long (mtp, M->id); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &msg_send_methods, M); -} - -void do_send_message (struct telegram *instance, peer_id_t id, const char *msg, int len) { - struct mtproto_connection *mtp = instance->connection; - if (get_peer_type (id) == PEER_ENCR_CHAT) { - peer_t *P = user_chat_get (mtp->bl, id); - if (!P) { - warning ("Can not send to unknown encrypted chat\n"); - return; - } - if (P->encr_chat.state != sc_ok) { - warning ("Chat is not yet initialized\n"); - return; - } - } - long long t; - secure_random (&t, 8); - debug ("t = %lld, len = %d\n", t, len); - bl_do_send_message_text (mtp->bl, mtp, t, instance->our_id, get_peer_type (id), get_peer_id (id), time (0), len, msg); - struct message *M = message_get (mtp->bl, t); - assert (M); - do_send_msg (instance, M); - //print_message (M); -} -/* }}} */ - -/* {{{ Send text file */ -void do_send_text (struct telegram *instance, peer_id_t id, char *file_name) { - int fd = open (file_name, O_RDONLY); - if (fd < 0) { - warning ("No such file '%s'\n", file_name); - tfree_str (file_name); - return; - } - static char buf[(1 << 20) + 1]; - int x = read (fd, buf, (1 << 20) + 1); - assert (x >= 0); - if (x == (1 << 20) + 1) { - warning ("Too big file '%s'\n", file_name); - tfree_str (file_name); - close (fd); - } else { - buf[x] = 0; - do_send_message (instance, id, buf, x); - tfree_str (file_name); - close (fd); - } -} -/* }}} */ - -/* {{{ Mark read */ -int mark_read_on_receive (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - assert (fetch_int (mtp) == (int)CODE_messages_affected_history); - fetch_pts (mtp); - fetch_seq (mtp); - fetch_int (mtp); // offset - return 0; -} - -int mark_read_encr_on_receive (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - fetch_bool (mtp); - return 0; -} - -struct query_methods mark_read_methods = { - .on_answer = mark_read_on_receive -}; - -struct query_methods mark_read_encr_methods = { - .on_answer = mark_read_encr_on_receive -}; - -void do_messages_mark_read (struct telegram *instance, peer_id_t id, int max_id) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - - clear_packet (mtp); - out_int (mtp, CODE_messages_read_history); - out_peer_id (mtp, id); - out_int (mtp, max_id); - out_int (mtp, 0); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &mark_read_methods, 0); -} - -void do_messages_mark_read_encr (struct telegram *instance, peer_id_t id, long long access_hash, int last_time) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - - clear_packet (mtp); - out_int (mtp, CODE_messages_read_encrypted_history); - out_int (mtp, CODE_input_encrypted_chat); - out_int (mtp, get_peer_id (id)); - out_long (mtp, access_hash); - out_int (mtp, last_time); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &mark_read_encr_methods, 0); -} - -void do_mark_read (struct telegram *instance, peer_id_t id) { - struct mtproto_connection *mtp = instance->connection; - - peer_t *P = user_chat_get (mtp->bl, id); - if (!P) { - debug ("Unknown peer\n"); - return; - } - if (get_peer_type (id) == PEER_USER || get_peer_type (id) == PEER_CHAT) { - if (!P->last) { - debug ("Unknown last peer message\n"); - return; - } - do_messages_mark_read (instance, id, P->last->id); - return; - } - assert (get_peer_type (id) == PEER_ENCR_CHAT); - if (P->last) { - do_messages_mark_read_encr (instance, id, P->encr_chat.access_hash, P->last->date); - } else { - do_messages_mark_read_encr (instance, id, P->encr_chat.access_hash, time (0) - 10); - - } -} -/* }}} */ - -struct get_hist_extra { - struct telegram *instance; - peer_id_t peer_id; -}; - -/* {{{ Get history */ -int get_history_on_answer (struct query *q UU) { - struct get_hist_extra *extra = q->extra; - struct telegram *instance = extra->instance; - struct mtproto_connection *mtp = query_get_mtproto(q); - peer_id_t peer_id = extra->peer_id; - - static struct message *ML[10000]; - int i; - int x = fetch_int (mtp); - if (x == (int)CODE_messages_messages_slice) { - fetch_int (mtp); - debug ("...\n"); - } else { - assert (x == (int)CODE_messages_messages); - } - assert (fetch_int (mtp) == CODE_vector); - int n = fetch_int (mtp); - for (i = 0; i < n; i++) { - struct message *M = fetch_alloc_message (mtp, instance); - if (i <= 9999) { - ML[i] = M; - } - } - if (n > 10000) { n = 10000; } - int sn = n; - for (i = n - 1; i >= 0; i--) { - //print_message (ML[i]); - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_chat (mtp); - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_user (mtp); - } - - if (sn > 0 && q->extra) { - do_messages_mark_read (instance, peer_id, ML[0]->id); - } - free(extra); - return 0; -} - -struct query_methods get_history_methods = { - .on_answer = get_history_on_answer, -}; - -void do_get_local_history (struct telegram *instance, peer_id_t id, int limit) { - struct mtproto_connection *mtp = instance->connection; - peer_t *P = user_chat_get (mtp->bl, id); - if (!P || !P->last) { return; } - struct message *M = P->last; - int count = 1; - assert (!M->prev); - while (count < limit && M->next) { - M = M->next; - count ++; - } - while (M) { - //print_message (M); - M = M->prev; - } -} - -void do_get_history (struct telegram *instance, peer_id_t id, int limit) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - if (get_peer_type (id) == PEER_ENCR_CHAT || offline_mode) { - do_get_local_history (instance, id, limit); - do_mark_read (instance, id); - return; - } - clear_packet (mtp); - out_int (mtp, CODE_messages_get_history); - out_peer_id (mtp, id); - out_int (mtp, 0); - out_int (mtp, 0); - out_int (mtp, limit); - - struct get_hist_extra *extra = malloc(sizeof(struct get_hist_extra)); - extra->instance = instance; - extra->peer_id = id; - - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_history_methods, extra); -} -/* }}} */ - -/* {{{ Get dialogs */ -int dialog_list_got; -int get_dialogs_on_answer (struct query *q UU) { - struct telegram *instance = q->extra; - struct mtproto_connection *mtp = query_get_mtproto(q); - unsigned x = fetch_int (mtp); - assert (x == CODE_messages_dialogs || x == CODE_messages_dialogs_slice); - if (x == CODE_messages_dialogs_slice) { - fetch_int (mtp); // total_count - } - assert (fetch_int (mtp) == CODE_vector); - int n, i; - n = fetch_int (mtp); - static int dlist[2 * 100]; - static peer_id_t plist[100]; - int dl_size = n; - for (i = 0; i < n; i++) { - assert (fetch_int (mtp) == CODE_dialog); - if (i < 100) { - plist[i] = fetch_peer_id (mtp); - dlist[2 * i + 0] = fetch_int (mtp); - dlist[2 * i + 1] = fetch_int (mtp); - } else { - fetch_peer_id (mtp); - fetch_int (mtp); - fetch_int (mtp); - } - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_message (mtp, instance); - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_chat (mtp); - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_user (mtp); - } - //print_start (); - //push_color (COLOR_YELLOW); - for (i = dl_size - 1; i >= 0; i--) { - - // TODO: use peer - peer_t *UC UU; - switch (get_peer_type (plist[i])) { - case PEER_USER: - UC = user_chat_get (mtp->bl, plist[i]); - debug ("User "); - //print_user_name (plist[i], UC); - debug (": %d unread\n", dlist[2 * i + 1]); - break; - case PEER_CHAT: - UC = user_chat_get (mtp->bl, plist[i]); - debug ("Chat "); - //print_chat_name (plist[i], UC); - debug (": %d unread\n", dlist[2 * i + 1]); - break; - } - } - //pop_color (); - //print_end (); - - dialog_list_got = 1; - return 0; -} - -struct query_methods get_dialogs_methods = { - .on_answer = get_dialogs_on_answer, -}; - - -void do_get_dialog_list (struct telegram *instance) { - struct mtproto_connection *mtp = instance->connection; - struct dc *DC_working = telegram_get_working_dc(instance); - clear_packet (mtp); - out_int (mtp, CODE_messages_get_dialogs); - out_int (mtp, 0); - out_int (mtp, 0); - out_int (mtp, 1000); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_dialogs_methods, instance); -} -/* }}} */ - -int allow_send_linux_version = 1; - -/* {{{ Send photo/video file */ -struct send_file { - int fd; - long long size; - long long offset; - int part_num; - int part_size; - long long id; - long long thumb_id; - peer_id_t to_id; - unsigned media_type; - char *file_name; - int encr; - unsigned char *iv; - unsigned char *init_iv; - unsigned char *key; -}; - -void out_peer_id (struct mtproto_connection *self, peer_id_t id) { - peer_t *U; - switch (get_peer_type (id)) { - case PEER_CHAT: - out_int (self, CODE_input_peer_chat); - out_int (self, get_peer_id (id)); - break; - case PEER_USER: - U = user_chat_get (self->bl, id); - if (U && U->user.access_hash) { - out_int (self, CODE_input_peer_foreign); - out_int (self, get_peer_id (id)); - out_long (self, U->user.access_hash); - } else { - out_int (self, CODE_input_peer_contact); - out_int (self, get_peer_id (id)); - } - break; - default: - assert (0); - } -} - -struct send_file_extra { - struct telegram *instance; - struct send_file *file; -}; - -void send_part (struct telegram *instance, struct send_file *f); - -int send_file_part_on_answer (struct query *q) { - struct mtproto_connection *mtp = query_get_mtproto (q); - struct send_file_extra *extra = q->extra; - assert (fetch_int (mtp) == (int)CODE_bool_true); - send_part (extra->instance, extra->file); - return 0; -} - -int send_file_on_answer (struct query *q UU) { - struct telegram *instance = q->extra; - struct mtproto_connection *mtp = query_get_mtproto(q); - assert (fetch_int (mtp) == (int)CODE_messages_stated_message); - - // TODO: use message - struct message *M UU = fetch_alloc_message (mtp, instance); - - assert (fetch_int (mtp) == CODE_vector); - int n, i; - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_chat (mtp); - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_user (mtp); - } - fetch_pts (mtp); - fetch_seq (mtp); - //print_message (M); - return 0; -} - -int send_encr_file_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - if (prefetch_int (mtp) != (int)CODE_messages_sent_encrypted_file) { - hexdump_in (mtp); - } - assert (fetch_int (mtp) == (int)CODE_messages_sent_encrypted_file); - struct message *M = q->extra; - M->date = fetch_int (mtp); - assert (fetch_int (mtp) == CODE_encrypted_file); - M->media.encr_photo.id = fetch_long (mtp); - M->media.encr_photo.access_hash = fetch_long (mtp); - //M->media.encr_photo.size = fetch_int (mtp); - fetch_int (mtp); - M->media.encr_photo.dc_id = fetch_int (mtp); - assert (fetch_int (mtp) == M->media.encr_photo.key_fingerprint); - //print_message (M); - message_insert (M); - return 0; -} - -struct query_methods send_file_part_methods = { - .on_answer = send_file_part_on_answer -}; - -struct query_methods send_file_methods = { - .on_answer = send_file_on_answer -}; - -struct query_methods send_encr_file_methods = { - .on_answer = send_encr_file_on_answer -}; - -void send_part (struct telegram *instance, struct send_file *f) { - struct mtproto_connection *mtp = instance->connection; - struct dc *DC_working = telegram_get_working_dc(instance); - if (f->fd >= 0) { - if (!f->part_num) { - instance->cur_uploading_bytes += f->size; - } - clear_packet (mtp); - if (f->size < (16 << 20)) { - out_int (mtp, CODE_upload_save_file_part); - out_long (mtp, f->id); - out_int (mtp, f->part_num ++); - } else { - out_int (mtp, CODE_upload_save_big_file_part); - out_long (mtp, f->id); - out_int (mtp, f->part_num ++); - out_int (mtp, (f->size + f->part_size - 1) / f->part_size); - } - static char buf[512 << 10]; - int x = read (f->fd, buf, f->part_size); - assert (x > 0); - f->offset += x; - instance->cur_uploaded_bytes += x; - - if (f->encr) { - if (x & 15) { - assert (f->offset == f->size); - secure_random (buf + x, (-x) & 15); - x = (x + 15) & ~15; - } - - AES_KEY aes_key; - AES_set_encrypt_key (f->key, 256, &aes_key); - AES_ige_encrypt ((void *)buf, (void *)buf, x, &aes_key, f->iv, 1); - memset (&aes_key, 0, sizeof (aes_key)); - } - out_cstring (mtp, buf, x); - if (verbosity >= 2) { - debug ("offset=%lld size=%lld\n", f->offset, f->size); - } - if (f->offset == f->size) { - close (f->fd); - f->fd = -1; - } else { - assert (f->part_size == x); - } - //update_prompt (); - - struct send_file_extra *extra = malloc(sizeof(struct send_file_extra)); - extra->instance = instance; - extra->file = f; - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_file_part_methods, extra); - } else { - instance->cur_uploaded_bytes -= f->size; - instance->cur_uploading_bytes -= f->size; - //update_prompt (); - clear_packet (mtp); - assert (f->media_type == CODE_input_media_uploaded_photo || f->media_type == CODE_input_media_uploaded_video || f->media_type == CODE_input_media_uploaded_thumb_video || f->media_type == CODE_input_media_uploaded_audio || f->media_type == CODE_input_media_uploaded_document || f->media_type == CODE_input_media_uploaded_thumb_document); - if (!f->encr) { - out_int (mtp, CODE_messages_send_media); - out_peer_id (mtp, f->to_id); - out_int (mtp, f->media_type); - if (f->size < (16 << 20)) { - out_int (mtp, CODE_input_file); - } else { - out_int (mtp, CODE_input_file_big); - } - out_long (mtp, f->id); - out_int (mtp, f->part_num); - char *s = f->file_name + strlen (f->file_name); - while (s >= f->file_name && *s != '/') { s --;} - out_string (mtp, s + 1); - if (f->size < (16 << 20)) { - out_string (mtp, ""); - } - if (f->media_type == CODE_input_media_uploaded_thumb_video || f->media_type == CODE_input_media_uploaded_thumb_document) { - out_int (mtp, CODE_input_file); - out_long (mtp, f->thumb_id); - out_int (mtp, 1); - out_string (mtp, "thumb.jpg"); - out_string (mtp, ""); - } - if (f->media_type == CODE_input_media_uploaded_video || f->media_type == CODE_input_media_uploaded_thumb_video) { - out_int (mtp, 100); - out_int (mtp, 100); - out_int (mtp, 100); - } - if (f->media_type == CODE_input_media_uploaded_document || f->media_type == CODE_input_media_uploaded_thumb_document) { - out_string (mtp, s + 1); - out_string (mtp, "text"); - } - if (f->media_type == CODE_input_media_uploaded_audio) { - out_int (mtp, 60); - } - - out_long (mtp, -lrand48 () * (1ll << 32) - lrand48 ()); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_file_methods, instance); - } else { - struct message *M = talloc0 (sizeof (*M)); - - out_int (mtp, CODE_messages_send_encrypted_file); - out_int (mtp, CODE_input_encrypted_chat); - out_int (mtp, get_peer_id (f->to_id)); - peer_t *P = user_chat_get (mtp->bl, f->to_id); - assert (P); - out_long (mtp, P->encr_chat.access_hash); - long long r = -lrand48 () * (1ll << 32) - lrand48 (); - out_long (mtp, r); - encr_start (mtp); - out_int (mtp, CODE_decrypted_message); - out_long (mtp, r); - out_random (mtp, 15 + 4 * (lrand48 () % 3)); - out_string (mtp, ""); - if (f->media_type == CODE_input_media_uploaded_photo) { - out_int (mtp, CODE_decrypted_message_media_photo); - M->media.type = CODE_decrypted_message_media_photo; - } else if (f->media_type == CODE_input_media_uploaded_video) { - out_int (mtp, CODE_decrypted_message_media_video); - M->media.type = CODE_decrypted_message_media_video; - } else if (f->media_type == CODE_input_media_uploaded_audio) { - out_int (mtp, CODE_decrypted_message_media_audio); - M->media.type = CODE_decrypted_message_media_audio; - } else if (f->media_type == CODE_input_media_uploaded_document) { - out_int (mtp, CODE_decrypted_message_media_document); - M->media.type = CODE_decrypted_message_media_document;; - } else { - assert (0); - } - if (f->media_type != CODE_input_media_uploaded_audio) { - out_cstring (mtp, (void *)thumb_file, thumb_file_size); - out_int (mtp, 90); - out_int (mtp, 90); - } - if (f->media_type == CODE_input_media_uploaded_video) { - out_int (mtp, 0); - } - if (f->media_type == CODE_input_media_uploaded_document) { - out_string (mtp, f->file_name); - out_string (mtp, "text"); - } - if (f->media_type == CODE_input_media_uploaded_audio) { - out_int (mtp, 60); - } - if (f->media_type == CODE_input_media_uploaded_video || f->media_type == CODE_input_media_uploaded_photo) { - out_int (mtp, 100); - out_int (mtp, 100); - } - out_int (mtp, f->size); - out_cstring (mtp, (void *)f->key, 32); - out_cstring (mtp, (void *)f->init_iv, 32); - encr_finish (mtp, &P->encr_chat); - if (f->size < (16 << 20)) { - out_int (mtp, CODE_input_encrypted_file_uploaded); - } else { - out_int (mtp, CODE_input_encrypted_file_big_uploaded); - } - out_long (mtp, f->id); - out_int (mtp, f->part_num); - if (f->size < (16 << 20)) { - out_string (mtp, ""); - } - - unsigned char md5[16]; - unsigned char str[64]; - memcpy (str, f->key, 32); - memcpy (str + 32, f->init_iv, 32); - MD5 (str, 64, md5); - out_int (mtp, (*(int *)md5) ^ (*(int *)(md5 + 4))); - - tfree_secure (f->iv, 32); - - M->media.encr_photo.key = f->key; - M->media.encr_photo.iv = f->init_iv; - M->media.encr_photo.key_fingerprint = (*(int *)md5) ^ (*(int *)(md5 + 4)); - M->media.encr_photo.size = f->size; - - M->flags = FLAG_ENCRYPTED; - M->from_id = MK_USER (instance->our_id); - M->to_id = f->to_id; - M->unread = 1; - M->message = tstrdup (""); - M->out = 1; - M->id = r; - M->date = time (0); - - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_encr_file_methods, M); - } - tfree_str (f->file_name); - tfree (f, sizeof (*f)); - } -} - -void send_file_thumb (struct telegram *instance, struct send_file *f) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - f->thumb_id = lrand48 () * (1ll << 32) + lrand48 (); - out_int (mtp, CODE_upload_save_file_part); - out_long (mtp, f->thumb_id); - out_int (mtp, 0); - out_cstring (mtp, (void *)thumb_file, thumb_file_size); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_file_part_methods, f); -} - -void do_send_photo (struct telegram *instance, int type, peer_id_t to_id, char *file_name) { - int fd = open (file_name, O_RDONLY); - if (fd < 0) { - warning ("No such file '%s'\n", file_name); - tfree_str (file_name); - return; - } - struct stat buf; - fstat (fd, &buf); - long long size = buf.st_size; - if (size <= 0) { - debug ("File has zero length\n"); - tfree_str (file_name); - close (fd); - return; - } - struct send_file *f = talloc0 (sizeof (*f)); - f->fd = fd; - f->size = size; - f->offset = 0; - f->part_num = 0; - int tmp = ((size + 2999) / 3000); - f->part_size = (1 << 10); - while (f->part_size < tmp) { - f->part_size *= 2; - } - - if (f->part_size > (512 << 10)) { - close (fd); - failure ("Too big file. Maximal supported size is %d.\n", (512 << 10) * 1000); - tfree (f, sizeof (*f)); - tfree_str (file_name); - return; - } - - f->id = lrand48 () * (1ll << 32) + lrand48 (); - f->to_id = to_id; - f->media_type = type; - f->file_name = file_name; - if (get_peer_type (f->to_id) == PEER_ENCR_CHAT) { - f->encr = 1; - f->iv = talloc (32); - secure_random (f->iv, 32); - f->init_iv = talloc (32); - memcpy (f->init_iv, f->iv, 32); - f->key = talloc (32); - secure_random (f->key, 32); - } - if (f->media_type == CODE_input_media_uploaded_video && !f->encr) { - f->media_type = CODE_input_media_uploaded_thumb_video; - send_file_thumb (instance, f); - } else if (f->media_type == CODE_input_media_uploaded_document && !f->encr) { - f->media_type = CODE_input_media_uploaded_thumb_document; - send_file_thumb (instance, f); - } else { - send_part (instance, f); - } -} -/* }}} */ - -/* {{{ Forward */ -int fwd_msg_on_answer (struct query *q UU) { - struct telegram *instance = q->extra; - struct mtproto_connection *mtp = query_get_mtproto(q); - - assert (fetch_int (mtp) == (int)CODE_messages_stated_message); - - // TODO: use message - struct message *M UU = fetch_alloc_message (mtp, instance); - assert (fetch_int (mtp) == CODE_vector); - int n, i; - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_chat (mtp); - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_user (mtp); - } - fetch_pts (mtp); - fetch_seq (mtp); - //print_message (M); - return 0; -} - -struct query_methods fwd_msg_methods = { - .on_answer = fwd_msg_on_answer -}; - -void do_forward_message (struct telegram *instance, peer_id_t id, int n) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - if (get_peer_type (id) == PEER_ENCR_CHAT) { - warning ("Can not forward messages from secret chat\n"); - return; - } - clear_packet (mtp); - out_int (mtp, CODE_messages_forward_message); - out_peer_id (mtp, id); - out_int (mtp, n); - out_long (mtp, lrand48 () * (1ll << 32) + lrand48 ()); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &fwd_msg_methods, instance); -} -/* }}} */ - -/* {{{ Rename chat */ -int rename_chat_on_answer (struct query *q UU) { - struct telegram *instance = q->extra; - struct mtproto_connection *mtp = query_get_mtproto(q); - - assert (fetch_int (mtp) == (int)CODE_messages_stated_message); - - // TODO: use message - struct message *M UU = fetch_alloc_message (mtp, instance); - assert (fetch_int (mtp) == CODE_vector); - int n, i; - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_chat (mtp); - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_user (mtp); - } - fetch_pts (mtp); - fetch_seq (mtp); - //print_message (M); - return 0; -} - -struct query_methods rename_chat_methods = { - .on_answer = rename_chat_on_answer -}; - -void do_rename_chat (struct telegram *instance, peer_id_t id, char *name UU) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - out_int (mtp, CODE_messages_edit_chat_title); - assert (get_peer_type (id) == PEER_CHAT); - out_int (mtp, get_peer_id (id)); - out_string (mtp, name); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &rename_chat_methods, instance); -} -/* }}} */ - -/* {{{ Chat info */ -void print_chat_info (struct chat *C) { - - // TODO: use peer_t - peer_t *U UU = (void *)C; - - //print_start (); - //push_color (COLOR_YELLOW); - debug ("Chat "); - //print_chat_name (U->id, U); - debug (" members:\n"); - int i; - for (i = 0; i < C->user_list_size; i++) { - debug ("\t\t"); - //print_user_name (MK_USER (C->user_list[i].user_id), user_chat_get (mtp->bl, MK_USER (C->user_list[i].user_id))); - debug (" invited by "); - //print_user_name (MK_USER (C->user_list[i].inviter_id), user_chat_get (mtp->bl, MK_USER (C->user_list[i].inviter_id))); - debug (" at "); - //print_date_full (C->user_list[i].date); - if (C->user_list[i].user_id == C->admin_id) { - debug (" admin"); - } - debug ("\n"); - } - //pop_color (); - //print_end (); -} - -int chat_info_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - struct chat *C = fetch_alloc_chat_full (mtp); - mtp->instance->config->on_chat_info_received (mtp->instance, C->id); - return 0; -} - -struct query_methods chat_info_methods = { - .on_answer = chat_info_on_answer -}; - -void do_get_chat_info (struct telegram *instance, peer_id_t id) { - debug ("do_get_chat_info (peer_id=%d)", id.id); - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - if (offline_mode) { - peer_t *C = user_chat_get (mtp->bl, id); - if (!C) { - warning ("No such chat\n"); - } else { - //print_chat_info (&C->chat); - } - return; - } - clear_packet (mtp); - out_int (mtp, CODE_messages_get_full_chat); - assert (get_peer_type (id) == PEER_CHAT); - out_int (mtp, get_peer_id (id)); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &chat_info_methods, 0); -} -/* }}} */ - -/* {{{ User info */ - -void print_user_info (struct tgl_user *U) { - // TODO: use peer - peer_t *C UU = (void *)U; - - //print_start (); - //push_color (COLOR_YELLOW); - debug ("User "); - //print_user_name (U->id, C); - debug (":\n"); - debug ("\treal name: %s %s\n", U->real_first_name, U->real_last_name); - debug ("\tphone: %s\n", U->phone); - if (U->status.online > 0) { - debug ("\tonline\n"); - } else { - debug ("\toffline (was online "); - //print_date_full (U->status.when); - debug (")\n"); - } - //pop_color (); - //print_end (); -} - -struct show_info_extra { - int show_info; -}; - -int user_info_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - struct show_info_extra *extra = q->extra; - - struct tgl_user *U = fetch_alloc_user_full (mtp); - event_user_info_received_handler (mtp->instance, U, extra->show_info); - tfree (extra, sizeof(struct show_info_extra)); - //print_user_info (U); - return 0; -} - -struct query_methods user_info_methods = { - .on_answer = user_info_on_answer -}; - -void do_get_user_info (struct telegram *instance, peer_id_t id, int showInfo) { - info ("do_get_user_info\n"); - struct show_info_extra *extra = talloc(sizeof(struct show_info_extra)); - extra->show_info = showInfo; - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - out_int (mtp, CODE_users_get_full_user); - assert (get_peer_type (id) == PEER_USER); - peer_t *U = user_chat_get (mtp->bl, id); - if (U && U->user.access_hash) { - out_int (mtp, CODE_input_user_foreign); - out_int (mtp, get_peer_id (id)); - out_long (mtp, U->user.access_hash); - } else { - out_int (mtp, CODE_input_user_contact); - out_int (mtp, get_peer_id (id)); - } - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &user_info_methods, extra); - debug ("do_get_user_info ready\n"); -} -/* }}} */ - -/* {{{ Get user info silently */ -int user_list_info_silent_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - assert (fetch_int (mtp) == CODE_vector); - int n = fetch_int (mtp); - int i; - for (i = 0; i < n; i++) { - fetch_alloc_user (mtp); - } - return 0; -} - -struct query_methods user_list_info_silent_methods = { - .on_answer = user_list_info_silent_on_answer -}; - -void do_get_user_list_info_silent (struct telegram *instance, int num, int *list) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - out_int (mtp, CODE_users_get_users); - out_int (mtp, CODE_vector); - out_int (mtp, num); - int i; - for (i = 0; i < num; i++) { - out_int (mtp, CODE_input_user_contact); - out_int (mtp, list[i]); - //out_long (0); - } - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &user_list_info_silent_methods, 0); -} -/* }}} */ - - -void end_load (struct telegram *instance, struct download *D) { - instance->cur_downloading_bytes -= D->size; - instance->cur_downloaded_bytes -= D->size; - //update_prompt (); - close (D->fd); - debug ("Done: %s\n", D->name); - event_download_finished (instance, D); - instance->dl_curr = 0; - if (D->dc != telegram_get_working_dc(instance)->id) { - debug ("%d Not the working dc %d, closing...\n", D->dc, - telegram_get_working_dc(instance)->id); - } - if (D->iv) { - tfree_secure (D->iv, 32); - } - tfree_str (D->name); - tfree (D, sizeof (*D)); - telegram_dl_next (instance); -} - -struct download_extra { - struct telegram *instance; - struct download *dl; -}; - -void load_next_part (struct telegram *instance, struct download *D); -int download_on_answer (struct query *q) { - struct download_extra *extra = q->extra; - struct telegram *instance = extra->instance; - struct mtproto_connection *mtp = query_get_mtproto(q); - - struct download *D = extra->dl; - free(extra); - - assert (fetch_int (mtp) == (int)CODE_upload_file); - unsigned x = fetch_int (mtp); - assert (x); - if (D->fd == -1) { - D->fd = open (D->name, O_CREAT | O_WRONLY, 0640); - } - fetch_int (mtp); // mtime - int len = prefetch_strlen (mtp); - assert (len >= 0); - instance->cur_downloaded_bytes += len; - //update_prompt (); - if (D->iv) { - unsigned char *ptr = (void *)fetch_str (mtp, len); - assert (!(len & 15)); - AES_KEY aes_key; - AES_set_decrypt_key (D->key, 256, &aes_key); - AES_ige_encrypt (ptr, ptr, len, &aes_key, D->iv, 0); - memset (&aes_key, 0, sizeof (aes_key)); - if (len > D->size - D->offset) { - len = D->size - D->offset; - } - assert (write (D->fd, ptr, len) == len); - } else { - assert (write (D->fd, fetch_str (mtp, len), len) == len); - } - D->offset += len; - if (D->offset < D->size) { - load_next_part (instance, D); - return 0; - } else { - end_load (instance, D); - return 0; - } -} - -struct query_methods download_methods = { - .on_answer = download_on_answer -}; - -void load_next_part (struct telegram *instance, struct download *D) { - struct mtproto_connection *mtp = instance->connection; - if (!D->offset) { - static char buf[PATH_MAX]; - int l; - - if (!D->id) { - l = tsnprintf (buf, sizeof (buf), "%s/download_%lld_%d", instance->download_path, D->volume, D->local_id); - } else { - l = tsnprintf (buf, sizeof (buf), "%s/download_%lld", instance->download_path, D->id); - } - if (l >= (int) sizeof (buf)) { - fatal ("Download filename is too long"); - exit (1); - } - D->name = tstrdup (buf); - struct stat st; - if (stat (buf, &st) >= 0) { - D->offset = st.st_size; - if (D->offset >= D->size) { - instance->cur_downloading_bytes += D->size; - instance->cur_downloaded_bytes += D->offset; - info ("Already downloaded\n"); - end_load (instance, D); - return; - } - } - - instance->cur_downloading_bytes += D->size; - instance->cur_downloaded_bytes += D->offset; - //update_prompt (); - } - info ("do_upload_get_file()\n"); - clear_packet (mtp); - out_int (mtp, CODE_upload_get_file); - if (!D->id) { - out_int (mtp, CODE_input_file_location); - out_long (mtp, D->volume); - out_int (mtp, D->local_id); - out_long (mtp, D->secret); - } else { - if (D->iv) { - out_int (mtp, CODE_input_encrypted_file_location); - } else { - out_int (mtp, D->type); - } - out_long (mtp, D->id); - out_long (mtp, D->access_hash); - } - out_int (mtp, D->offset); - out_int (mtp, 1 << 14); - - struct download_extra *extra = malloc(sizeof(struct download_extra)); - extra->instance = instance; - extra->dl = D; - - send_query (instance, instance->auth.DC_list[D->dc], mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &download_methods, extra); - //send_query (instance, DC_working, packet_ptr - packet_buffer, packet_buffer, &download_methods, D); -} - -void do_load_photo_size (struct telegram *instance, struct photo_size *P, void *extra) { - if (!P->loc.dc) { - failure ("Bad video thumb\n"); - return; - } - assert (P); - struct download *D = talloc0 (sizeof (*D)); - D->id = 0; - D->offset = 0; - D->size = P->size; - D->volume = P->loc.volume; - D->dc = P->loc.dc; - D->local_id = P->loc.local_id; - D->secret = P->loc.secret; - D->extra = extra; - D->name = 0; - D->fd = -1; - - telegram_dl_add (instance, D); - telegram_dl_next (instance); -} - -void do_load_photo (struct telegram *instance, struct photo *photo, int photoBig, void *extra) { - if (!photo->sizes_num) { return; } - int size = -1; - int sizei = 0; - int i; - for (i = 0; i < photo->sizes_num; i++) { - if (photoBig == 0) - { - if (photo->sizes[i].w + photo->sizes[i].h < size) { - size = photo->sizes[i].w + photo->sizes[i].h; - sizei = i; - } - } else { - if (photo->sizes[i].w + photo->sizes[i].h > size) { - size = photo->sizes[i].w + photo->sizes[i].h; - sizei = i; - } - } - } - do_load_photo_size (instance, &photo->sizes[sizei], extra); -} - -void do_load_video_thumb (struct telegram *instance, struct video *video, void *extra) { - do_load_photo_size (instance, &video->thumb, extra); -} - -void do_load_document_thumb (struct telegram *instance, struct document *video, void *extra) { - do_load_photo_size (instance, &video->thumb, extra); -} - -void do_load_video (struct telegram *instance, struct video *V, void *extra) { - assert (V); - struct download *D = talloc0 (sizeof (*D)); - D->offset = 0; - D->size = V->size; - D->id = V->id; - D->access_hash = V->access_hash; - D->dc = V->dc_id; - D->extra = extra; - D->name = 0; - D->fd = -1; - D->type = CODE_input_video_file_location; - load_next_part (instance, D); -} - -void do_load_audio (struct telegram *instance, struct video *V, void *extra) { - assert (V); - struct download *D = talloc0 (sizeof (*D)); - D->offset = 0; - D->size = V->size; - D->id = V->id; - D->access_hash = V->access_hash; - D->dc = V->dc_id; - D->extra = extra; - D->name = 0; - D->fd = -1; - D->type = CODE_input_audio_file_location; - load_next_part (instance, D); -} - -void do_load_document (struct telegram *instance, struct document *V, void *extra) { - assert (V); - struct download *D = talloc0 (sizeof (*D)); - D->offset = 0; - D->size = V->size; - D->id = V->id; - D->access_hash = V->access_hash; - D->dc = V->dc_id; - D->extra = extra; - D->name = 0; - D->fd = -1; - D->type = CODE_input_document_file_location; - load_next_part (instance, D); -} - -void do_load_encr_video (struct telegram *instance, struct encr_video *V, void *extra) { - assert (V); - struct download *D = talloc0 (sizeof (*D)); - D->offset = 0; - D->size = V->size; - D->id = V->id; - D->access_hash = V->access_hash; - D->dc = V->dc_id; - D->extra = extra; - D->name = 0; - D->fd = -1; - D->key = V->key; - D->iv = talloc (32); - memcpy (D->iv, V->iv, 32); - load_next_part (instance, D); - - unsigned char md5[16]; - unsigned char str[64]; - memcpy (str, V->key, 32); - memcpy (str + 32, V->iv, 32); - MD5 (str, 64, md5); - assert (V->key_fingerprint == ((*(int *)md5) ^ (*(int *)(md5 + 4)))); -} -/* }}} */ - -/* {{{ Export auth */ - -struct export_info { - void *extra; - void (*cb)(char *export_auth_str, int len, void *extra); -}; - -int export_auth_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - struct telegram *instance = mtp->connection->instance; - - assert (fetch_int (mtp) == (int)CODE_auth_exported_authorization); - int l = fetch_int (mtp); - if (!instance->our_id) { - instance->our_id = l; - } else { - assert (instance->our_id == l); - } - l = prefetch_strlen (mtp); - char *s = talloc (l); - memcpy (s, fetch_str (mtp, l), l); - instance->export_auth_str_len = l; - instance->export_auth_str = s; - - struct export_info *info = q->extra; - info->cb(instance->export_auth_str, instance->export_auth_str_len, info->extra); - tfree(info, sizeof(struct export_info)); - return 0; -} - -struct query_methods export_auth_methods = { - .on_answer = export_auth_on_answer, - .on_error = fail_on_error -}; - -void do_export_auth (struct telegram *instance, int num, void (*cb)(char *export_auth_str, int len, void *extra), void *extra) { - info ("do_export_auth(num=%d)\n", num); - instance->export_auth_str = 0; - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - out_int (mtp, CODE_auth_export_authorization); - out_int (mtp, num); - - struct export_info *info = talloc0(sizeof(struct export_info)); - info->cb = cb; - info->extra = extra; - - send_query (instance, telegram_get_working_dc(instance), - mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &export_auth_methods, info); -} -/* }}} */ - -struct import_info { - void *extra; - void (*cb)(void* extra); -}; - -/* {{{ Import auth */ -int import_auth_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - struct telegram *instance = mtp->connection->instance; - struct import_info *info = q->extra; - - assert (fetch_int (mtp) == (int)CODE_auth_authorization); - fetch_int (mtp); // expires - fetch_alloc_user (mtp); - tfree_str (instance->export_auth_str); - instance->export_auth_str = 0; - info->cb(info->extra); - tfree (info, sizeof(struct import_info)); - return 0; -} - -struct query_methods import_auth_methods = { - .on_answer = import_auth_on_answer, - .on_error = fail_on_error -}; - -void do_import_auth (struct telegram *instance, int num, void (*cb)(void *extra), void *extra) { - info ("do_import_auth(num=%d, our_id=%d, export_auth_str=)\n", num, instance->our_id); - struct import_info *info = talloc0(sizeof (struct import_info)); - info->cb = cb; - info->extra = extra; - - struct dc *target_dc = instance->auth.DC_list[num]; - assert (target_dc); - struct mtproto_connection *dc_conn = target_dc->sessions[0]->c->mtconnection; - assert (dc_conn); - - clear_packet (dc_conn); - out_int (dc_conn, CODE_auth_import_authorization); - out_int (dc_conn, instance->our_id); - out_cstring (dc_conn, instance->export_auth_str, instance->export_auth_str_len); - - send_query (instance, target_dc, dc_conn->packet_ptr - dc_conn->packet_buffer, - dc_conn->packet_buffer, &import_auth_methods, info); -} -/* }}} */ - -/* {{{ Add contact */ -int add_contact_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - assert (fetch_int (mtp) == (int)CODE_contacts_imported_contacts); - assert (fetch_int (mtp) == CODE_vector); - int n = fetch_int (mtp); - if (n > 0) { - debug ("Added successfully"); - } else { - debug ("Not added"); - } - int i; - for (i = 0; i < n ; i++) { - assert (fetch_int (mtp) == (int)CODE_imported_contact); - fetch_int (mtp); // uid - fetch_long (mtp); // client_id - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n ; i++) { - struct tgl_user *U = fetch_alloc_user (mtp); - //print_start (); - //push_color (COLOR_YELLOW); - debug ("User #%d: ", get_peer_id (U->id)); - //print_user_name (U->id, (peer_t *)U); - //push_color (COLOR_GREEN); - debug (" ("); - debug ("%s", U->print_name); - if (U->phone) { - debug (" "); - debug ("%s", U->phone); - } - debug (") "); - //pop_color (); - if (U->status.online > 0) { - debug ("online\n"); - } else { - if (U->status.online < 0) { - debug ("offline. Was online "); - //print_date_full (U->status.when); - } else { - debug ("offline permanent"); - } - debug ("\n"); - } - //pop_color (); - //print_end (); - - } - return 0; -} - -struct query_methods add_contact_methods = { - .on_answer = add_contact_on_answer, -}; - -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) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - out_int (mtp, CODE_contacts_import_contacts); - out_int (mtp, CODE_vector); - out_int (mtp, 1); - out_int (mtp, CODE_input_phone_contact); - out_long (mtp, lrand48 () * (1ll << 32) + lrand48 ()); - out_cstring (mtp, phone, phone_len); - out_cstring (mtp, first_name, first_name_len); - out_cstring (mtp, last_name, last_name_len); - out_int (mtp, force ? CODE_bool_true : CODE_bool_false); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &add_contact_methods, 0); -} -/* }}} */ - -/* {{{ Msg search */ -int msg_search_on_answer (struct query *q UU) { - return get_history_on_answer (q); -} - -struct query_methods msg_search_methods = { - .on_answer = msg_search_on_answer -}; - -void do_msg_search (struct telegram *instance, peer_id_t id, int from, int to, int limit, const char *s) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - if (get_peer_type (id) == PEER_ENCR_CHAT) { - warning ("Can not search in secure chat\n"); - return; - } - clear_packet (mtp); - out_int (mtp, CODE_messages_search); - if (get_peer_type (id) == PEER_UNKNOWN) { - out_int (mtp, CODE_input_peer_empty); - } else { - out_peer_id (mtp, id); - } - out_string (mtp, s); - out_int (mtp, CODE_input_messages_filter_empty); - out_int (mtp, from); - out_int (mtp, to); - out_int (mtp, 0); // offset - out_int (mtp, 0); // max_id - out_int (mtp, limit); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &msg_search_methods, 0); -} -/* }}} */ - -/* {{{ Contacts search */ -int contacts_search_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - assert (fetch_int (mtp) == CODE_contacts_found); - assert (fetch_int (mtp) == CODE_vector); - int n = fetch_int (mtp); - int i; - for (i = 0; i < n; i++) { - assert (fetch_int (mtp) == (int)CODE_contact_found); - fetch_int (mtp); - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - //print_start (); - //push_color (COLOR_YELLOW); - for (i = 0; i < n; i++) { - struct tgl_user *U = fetch_alloc_user (mtp); - debug ("User "); - //push_color (COLOR_RED); - debug ("%s %s", U->first_name, U->last_name); - //pop_color (); - debug (". Phone %s\n", U->phone); - } - //pop_color (); - //print_end (); - return 0; -} - -struct query_methods contacts_search_methods = { - .on_answer = contacts_search_on_answer -}; - -void do_contacts_search (struct telegram *instance, int limit, const char *s) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - - clear_packet (mtp); - out_int (mtp, CODE_contacts_search); - out_string (mtp, s); - out_int (mtp, limit); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &contacts_search_methods, 0); -} -/* }}} */ - -/* {{{ Encr accept */ -int send_encr_accept_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - struct secret_chat *E = fetch_alloc_encrypted_chat (mtp); - - if (E->state == sc_ok) { - //print_start (); - //push_color (COLOR_YELLOW); - debug ("Encrypted connection with "); - ////print_encr_chat_name (E->id, (void *)E); - debug (" established\n"); - //pop_color (); - //print_end (); - } else { - //print_start (); - //push_color (COLOR_YELLOW); - debug ("Encrypted connection with "); - ////print_encr_chat_name (E->id, (void *)E); - debug (" failed\n"); - //pop_color (); - //print_end (); - } - return 0; -} - -int send_encr_request_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - struct secret_chat *E = fetch_alloc_encrypted_chat (mtp); - if (E->state == sc_deleted) { - //print_start (); - //push_color (COLOR_YELLOW); - debug ("Encrypted connection with "); - //print_encr_chat_name (E->id, (void *)E); - debug (" can not be established\n"); - //pop_color (); - //print_end (); - } else { - //print_start (); - //push_color (COLOR_YELLOW); - debug ("Establishing connection with "); - //print_encr_chat_name (E->id, (void *)E); - debug ("\n"); - //pop_color (); - //print_end (); - - assert (E->state == sc_waiting); - } - return 0; -} - -struct query_methods send_encr_accept_methods = { - .on_answer = send_encr_accept_on_answer -}; - -struct query_methods send_encr_request_methods = { - .on_answer = send_encr_request_on_answer -}; - -void do_send_accept_encr_chat (struct telegram *instance, struct secret_chat *E, unsigned char *random) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - int i; - int ok = 0; - for (i = 0; i < 64; i++) { - if (E->key[i]) { - ok = 1; - break; - } - } - if (ok) { return; } // Already generated key for this chat - unsigned char random_here[256]; - secure_random (random_here, 256); - for (i = 0; i < 256; i++) { - random[i] ^= random_here[i]; - } - BIGNUM *b = BN_bin2bn (random, 256, 0); - ensure_ptr (b); - BIGNUM *g_a = BN_bin2bn (E->g_key, 256, 0); - ensure_ptr (g_a); - assert (check_g (instance->encr_prime, g_a) >= 0); - if (!instance->ctx) { - instance->ctx = BN_CTX_new (); - ensure_ptr (instance->ctx); - } - BIGNUM *p = BN_bin2bn (instance->encr_prime, 256, 0); - ensure_ptr (p); - BIGNUM *r = BN_new (); - ensure_ptr (r); - ensure (BN_mod_exp (r, g_a, b, p, instance->ctx)); - static unsigned char kk[256]; - memset (kk, 0, sizeof (kk)); - BN_bn2bin (r, kk); - for (i = 0; i < 256; i++) { - kk[i] ^= E->nonce[i]; - } - static unsigned char sha_buffer[20]; - sha1 (kk, 256, sha_buffer); - - bl_do_set_encr_chat_key (mtp->bl, mtp, E, kk, *(long long *)(sha_buffer + 12)); - - clear_packet (mtp); - out_int (mtp, CODE_messages_accept_encryption); - out_int (mtp, CODE_input_encrypted_chat); - out_int (mtp, get_peer_id (E->id)); - out_long (mtp, E->access_hash); - - ensure (BN_set_word (g_a, instance->encr_root)); - ensure (BN_mod_exp (r, g_a, b, p, instance->ctx)); - static unsigned char buf[256]; - memset (buf, 0, sizeof (buf)); - BN_bn2bin (r, buf); - out_cstring (mtp, (void *)buf, 256); - - out_long (mtp, E->key_fingerprint); - BN_clear_free (b); - BN_clear_free (g_a); - BN_clear_free (p); - BN_clear_free (r); - - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_encr_accept_methods, E); -} - -void do_create_keys_end (struct telegram *instance, struct secret_chat *U) { - assert (instance->encr_prime); - BIGNUM *g_b = BN_bin2bn (U->g_key, 256, 0); - ensure_ptr (g_b); - assert (check_g (instance->encr_prime, g_b) >= 0); - if (!instance->ctx) { - instance->ctx = BN_CTX_new (); - ensure_ptr (instance->ctx); - } - BIGNUM *p = BN_bin2bn (instance->encr_prime, 256, 0); - ensure_ptr (p); - BIGNUM *r = BN_new (); - ensure_ptr (r); - BIGNUM *a = BN_bin2bn ((void *)U->key, 256, 0); - ensure_ptr (a); - ensure (BN_mod_exp (r, g_b, a, p, instance->ctx)); - - unsigned char *t = talloc (256); - memcpy (t, U->key, 256); - - memset (U->key, 0, sizeof (U->key)); - BN_bn2bin (r, (void *)U->key); - int i; - for (i = 0; i < 64; i++) { - U->key[i] ^= *(((int *)U->nonce) + i); - } - - static unsigned char sha_buffer[20]; - sha1 ((void *)U->key, 256, sha_buffer); - long long k = *(long long *)(sha_buffer + 12); - if (k != U->key_fingerprint) { - debug ("version = %d\n", instance->encr_param_version); - hexdump ((void *)U->nonce, (void *)(U->nonce + 256)); - hexdump ((void *)U->g_key, (void *)(U->g_key + 256)); - hexdump ((void *)U->key, (void *)(U->key + 64)); - hexdump ((void *)t, (void *)(t + 256)); - hexdump ((void *)sha_buffer, (void *)(sha_buffer + 20)); - failure ("!!Key fingerprint mismatch (my 0x%llx 0x%llx)\n", (unsigned long long)k, (unsigned long long)U->key_fingerprint); - U->state = sc_deleted; - } - - tfree_secure (t, 256); - - BN_clear_free (p); - BN_clear_free (g_b); - BN_clear_free (r); - BN_clear_free (a); -} - -void do_send_create_encr_chat (struct telegram *instance, void *x, unsigned char *random) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - - int user_id = (long)x; - int i; - unsigned char random_here[256]; - secure_random (random_here, 256); - for (i = 0; i < 256; i++) { - random[i] ^= random_here[i]; - } - if (!instance->ctx) { - instance->ctx = BN_CTX_new (); - ensure_ptr (instance->ctx); - } - BIGNUM *a = BN_bin2bn (random, 256, 0); - ensure_ptr (a); - BIGNUM *p = BN_bin2bn (instance->encr_prime, 256, 0); - ensure_ptr (p); - - BIGNUM *g = BN_new (); - ensure_ptr (g); - - ensure (BN_set_word (g, instance->encr_root)); - - BIGNUM *r = BN_new (); - ensure_ptr (r); - - ensure (BN_mod_exp (r, g, a, p, instance->ctx)); - - BN_clear_free (a); - - memset (instance->g_a, 0, 256); - - BN_bn2bin (r, (void *)instance->g_a); - - int t = lrand48 (); - while (user_chat_get (mtp->bl, MK_ENCR_CHAT (t))) { - t = lrand48 (); - } - - bl_do_encr_chat_init (mtp->bl, mtp, t, user_id, (void *)random, (void *)instance->g_a); - peer_t *_E = user_chat_get (mtp->bl, MK_ENCR_CHAT (t)); - assert (_E); - struct secret_chat *E = &_E->encr_chat; - - clear_packet (mtp); - out_int (mtp, CODE_messages_request_encryption); - peer_t *U = user_chat_get (mtp->bl, MK_USER (E->user_id)); - assert (U); - if (U && U->user.access_hash) { - out_int (mtp, CODE_input_user_foreign); - out_int (mtp, E->user_id); - out_long (mtp, U->user.access_hash); - } else { - out_int (mtp, CODE_input_user_contact); - out_int (mtp, E->user_id); - } - out_int (mtp, get_peer_id (E->id)); - out_cstring (mtp, instance->g_a, 256); - write_secret_chat_file (instance, instance->secret_path); - - BN_clear_free (g); - BN_clear_free (p); - BN_clear_free (r); - - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &send_encr_request_methods, E); -} - -struct create_encr_chat_extra { - void (*callback) (struct telegram *instance, struct secret_chat *E, unsigned char *random); - void *data; - struct telegram *instance; -}; - -int get_dh_config_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - unsigned x = fetch_int (mtp); - assert (x == CODE_messages_dh_config || x == CODE_messages_dh_config_not_modified || LOG_DH_CONFIG); - if (x == CODE_messages_dh_config || x == LOG_DH_CONFIG) { - int a = fetch_int (mtp); - int l = prefetch_strlen (mtp); - assert (l == 256); - char *s = fetch_str (mtp, l); - int v = fetch_int (mtp); - bl_do_set_dh_params (mtp->bl, mtp, a, (void *)s, v); - - BIGNUM *p = BN_bin2bn ((void *)s, 256, 0); - ensure_ptr (p); - assert (check_DH_params (mtp, p, a) >= 0); - BN_free (p); - } - if (x == LOG_DH_CONFIG) { return 0; } - int l = prefetch_strlen (mtp); - assert (l == 256); - unsigned char *random = talloc (256); - memcpy (random, fetch_str (mtp, 256), 256); - if (q->extra) { - //((void (*)(void *, void *))(*x))(x[1], random); - - struct create_encr_chat_extra *extra = q->extra; - extra->callback(extra->instance, extra->data, random); - free(extra); - //tfree (x, 2 * sizeof (void *)); - - tfree_secure (random, 256); - } else { - tfree_secure (random, 256); - } - return 0; -} - -struct query_methods get_dh_config_methods = { - .on_answer = get_dh_config_on_answer -}; - -void do_accept_encr_chat_request (struct telegram *instance, struct secret_chat *E) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - assert (E->state == sc_request); - - clear_packet (mtp); - out_int (mtp, CODE_messages_get_dh_config); - out_int (mtp, instance->encr_param_version); - out_int (mtp, 256); - - struct create_encr_chat_extra *extra = malloc(sizeof(struct create_encr_chat_extra)); - extra->callback = do_send_accept_encr_chat; - extra->instance = instance; - extra->data = (void*)E; - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_dh_config_methods, extra); -} - -void do_create_encr_chat_request (struct telegram *instance, int user_id) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - - clear_packet (mtp); - out_int (mtp, CODE_messages_get_dh_config); - out_int (mtp, instance->encr_param_version); - out_int (mtp, 256); - - struct create_encr_chat_extra *extra = malloc(sizeof(struct create_encr_chat_extra)); - extra->callback = do_send_accept_encr_chat; - extra->instance = instance; - extra->data = (void *)(long)user_id; - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_dh_config_methods, extra); -} -/* }}} */ - -/* {{{ Get difference */ -//int difference_got; -//int seq, pts, qts, last_date; -int get_state_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - struct telegram *instance = q->extra; - - debug("get_state_on_answer()\n"); - assert (fetch_int (mtp) == (int)CODE_updates_state); - bl_do_set_pts (mtp->bl, mtp, fetch_int (mtp)); - bl_do_set_qts (mtp->bl, mtp, fetch_int (mtp)); - bl_do_set_date (mtp->bl, mtp, fetch_int (mtp)); - bl_do_set_seq (mtp->bl, mtp, fetch_int (mtp)); - instance->unread_messages = fetch_int (mtp); - //write_state_file (); - telegram_store_session (instance); - return 0; -} - -int get_difference_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - struct telegram *instance = q->extra; - - debug("get_difference_on_answer()\n"); - instance->get_difference_active = 0; - unsigned x = fetch_int (mtp); - if (x == CODE_updates_difference_empty) { - bl_do_set_date (mtp->bl, mtp, fetch_int (mtp)); - bl_do_set_seq (mtp->bl, mtp, fetch_int (mtp)); - } else if (x == CODE_updates_difference || x == CODE_updates_difference_slice) { - int n, i; - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - int ml_pos = 0; - for (i = 0; i < n; i++) { - if (ml_pos < 10000) { - instance->ML[ml_pos ++] = fetch_alloc_message (mtp, instance); - } else { - fetch_alloc_message (mtp, instance); - } - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - if (ml_pos < 10000) { - instance->ML[ml_pos ++] = fetch_alloc_encrypted_message (mtp, instance); - } else { - fetch_alloc_encrypted_message (mtp, instance); - } - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - work_update (mtp, 0); - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - debug("Found %d chats\n", n); - for (i = 0; i < n; i++) { - fetch_alloc_chat (mtp); - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - debug("Found %d users\n", n); - for (i = 0; i < n; i++) { - fetch_alloc_user (mtp); - } - assert (fetch_int (mtp) == (int)CODE_updates_state); - bl_do_set_pts (mtp->bl, mtp, fetch_int (mtp)); - bl_do_set_qts (mtp->bl, mtp, fetch_int (mtp)); - bl_do_set_date (mtp->bl, mtp, fetch_int (mtp)); - bl_do_set_seq (mtp->bl, mtp, fetch_int (mtp)); - instance->unread_messages = fetch_int (mtp); - debug ("UNREAD MESSAGES: %d\n", ml_pos); - //write_state_file (); - for (i = 0; i < ml_pos; i++) { - event_update_new_message (instance, instance->ML[i]); - ////print_message (ML[i]); - } - if (x == CODE_updates_difference_slice) { - do_get_difference (instance, 0); - } else { - //difference_got = 1; - } - } else { - assert (0); - } - telegram_store_session (instance); - return 0; -} - -struct query_methods get_state_methods = { - .on_answer = get_state_on_answer -}; - -struct query_methods get_difference_methods = { - .on_answer = get_difference_on_answer -}; - -void do_get_difference (struct telegram *instance, int sync_from_start) { - info ("do_get_difference()\n"); - struct mtproto_connection *mtp = instance->connection; - struct dc *DC_working = telegram_get_working_dc(instance); - - instance->get_difference_active = 1; - //difference_got = 0; - clear_packet (mtp); - do_insert_header (mtp); - debug("do_get_difference(pts:%d, last_date:%d, qts: %d)\n", instance->proto.pts, instance->proto.last_date, instance->proto.qts); - if (instance->proto.seq > 0 || sync_from_start) { - if (instance->proto.pts == 0) { instance->proto.pts = 1; } - if (instance->proto.qts == 0) { instance->proto.qts = 1; } - if (instance->proto.last_date == 0) { instance->proto.last_date = 1; } - - out_int (mtp, CODE_updates_get_difference); - out_int (mtp, instance->proto.pts); - out_int (mtp, instance->proto.last_date); - out_int (mtp, instance->proto.qts); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_difference_methods, instance); - } else { - debug("do_updates_get_state()\n", - instance->proto.pts, instance->proto.last_date, instance->proto.qts); - out_int (mtp, CODE_updates_get_state); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_state_methods, instance); - } -} -/* }}} */ - -/* {{{ Visualize key */ -//char *colors[4] = {COLOR_GREY, COLOR_CYAN, COLOR_BLUE, COLOR_GREEN}; - -void do_visualize_key (struct binlog *bl, peer_id_t id) { - assert (get_peer_type (id) == PEER_ENCR_CHAT); - peer_t *P = user_chat_get (bl, id); - assert (P); - if (P->encr_chat.state != sc_ok) { - warning ("Chat is not initialized yet\n"); - return; - } - unsigned char buf[20]; - SHA1 ((void *)P->encr_chat.key, 256, buf); - //print_start (); - int i; - for (i = 0; i < 16; i++) { - int x = buf[i]; - int j; - for (j = 0; j < 4; j ++) { - ////push_color (colors[x & 3]); - ////push_color (COLOR_INVERSE); - //debug (" "); - ////pop_color (); - ////pop_color (); - x = x >> 2; - } - if (i & 1) { debug ("\n"); } - } - //print_end (); -} -/* }}} */ - -/* {{{ Get suggested */ -int get_suggested_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - assert (fetch_int (mtp) == CODE_contacts_suggested); - assert (fetch_int (mtp) == CODE_vector); - int n = fetch_int (mtp); - debug ("n = %d\n", n); - assert (n <= 200); - int l[400]; - int i; - for (i = 0; i < n; i++) { - assert (fetch_int (mtp) == CODE_contact_suggested); - l[2 * i] = fetch_int (mtp); - l[2 * i + 1] = fetch_int (mtp); - } - assert (fetch_int (mtp) == CODE_vector); - int m = fetch_int (mtp); - assert (n == m); - //print_start (); - //push_color (COLOR_YELLOW); - for (i = 0; i < m; i++) { - peer_t *U = (void *)fetch_alloc_user (mtp); - assert (get_peer_id (U->id) == l[2 * i]); - //print_user_name (U->id, U); - debug (" phone %s: %d mutual friends\n", U->user.phone, l[2 * i + 1]); - } - //pop_color (); - //print_end (); - return 0; -} - -struct query_methods get_suggested_methods = { - .on_answer = get_suggested_on_answer -}; - -void do_get_suggested (struct telegram *instance) { - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - out_int (mtp, CODE_contacts_get_suggested); - out_int (mtp, 100); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &get_suggested_methods, 0); -} -/* }}} */ - -/* {{{ Add user to chat */ - -struct query_methods add_user_to_chat_methods = { - .on_answer = fwd_msg_on_answer -}; - -void do_add_user_to_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id, int limit) { - info ("do_add_user_to_chat()\n"); - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - out_int (mtp, CODE_messages_add_chat_user); - out_int (mtp, get_peer_id (chat_id)); - - assert (get_peer_type (id) == PEER_USER); - peer_t *U = user_chat_get (mtp->bl, id); - if (U && U->user.access_hash) { - out_int (mtp, CODE_input_user_foreign); - out_int (mtp, get_peer_id (id)); - out_long (mtp, U->user.access_hash); - } else { - out_int (mtp, CODE_input_user_contact); - out_int (mtp, get_peer_id (id)); - } - out_int (mtp, limit); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &add_user_to_chat_methods, 0); -} - -void do_del_user_from_chat (struct telegram *instance, peer_id_t chat_id, peer_id_t id) { - info ("do_del_user_from_chat()\n"); - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - out_int (mtp, CODE_messages_delete_chat_user); - out_int (mtp, get_peer_id (chat_id)); - - assert (get_peer_type (id) == PEER_USER); - peer_t *U = user_chat_get (mtp->bl, id); - if (U && U->user.access_hash) { - out_int (mtp, CODE_input_user_foreign); - out_int (mtp, get_peer_id (id)); - out_long (mtp, U->user.access_hash); - } else { - out_int (mtp, CODE_input_user_contact); - out_int (mtp, get_peer_id (id)); - } - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &add_user_to_chat_methods, 0); -} -/* }}} */ - -/* {{{ Create secret chat */ -char *create_print_name (struct binlog *bl, peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4); - -void do_create_secret_chat (struct telegram *instance, peer_id_t id) { - info ("do_create_secret_chat()\n"); - struct mtproto_connection *mtp = instance->connection; - assert (get_peer_type (id) == PEER_USER); - peer_t *U = user_chat_get (mtp->bl, id); - if (!U) { - warning ("Can not create chat with unknown user\n"); - return; - } - - do_create_encr_chat_request (instance, get_peer_id (id)); -} -/* }}} */ - -/* {{{ Create group chat */ -struct query_methods create_group_chat_methods = { - .on_answer = fwd_msg_on_answer -}; - -void do_create_group_chat (struct telegram *instance, peer_id_t id, char *chat_topic) { - info ("do_create_group_chat()\n"); - struct mtproto_connection *mtp = instance->connection; - assert (get_peer_type (id) == PEER_USER); - peer_t *U = user_chat_get (mtp->bl, id); - if (!U) { - warning ("Can not create chat with unknown user\n"); - return; - } - clear_packet (mtp); - out_int (mtp, CODE_messages_create_chat); - out_int (mtp, CODE_vector); - out_int (mtp, 1); // Number of users, currently we support only 1 user. - if (U && U->user.access_hash) { - out_int (mtp, CODE_input_user_foreign); - out_int (mtp, get_peer_id (id)); - out_long (mtp, U->user.access_hash); - } else { - out_int (mtp, CODE_input_user_contact); - out_int (mtp, get_peer_id (id)); - } - out_string (mtp, chat_topic); - send_query (instance, telegram_get_working_dc(instance), mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &create_group_chat_methods, 0); -} -/* }}} */ - - -/* {{{ Delete msg */ - -int delete_msg_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - assert (fetch_int (mtp) == CODE_vector); - int n = fetch_int (mtp); - fetch_skip (mtp, n); - debug ("Deleted %d messages\n", n); - return 0; -} - -struct query_methods delete_msg_methods = { - .on_answer = delete_msg_on_answer -}; - -void do_delete_msg (struct telegram *instance, long long id) { - info ("do_delete_msg()\n"); - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - out_int (mtp, CODE_messages_delete_messages); - out_int (mtp, CODE_vector); - out_int (mtp, 1); - out_int (mtp, id); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &delete_msg_methods, 0); -} -/* }}} */ - -/* {{{ Restore msg */ - -int restore_msg_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - assert (fetch_int (mtp) == CODE_vector); - int n = fetch_int (mtp); - fetch_skip (mtp, n); - debug ("Restored %d messages\n", n); - return 0; -} - -struct query_methods restore_msg_methods = { - .on_answer = restore_msg_on_answer -}; - -void do_restore_msg (struct telegram *instance, long long id) { - info ("do_restore_msg()\n"); - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - out_int (mtp, CODE_messages_restore_messages); - out_int (mtp, CODE_vector); - out_int (mtp, 1); - out_int (mtp, id); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &restore_msg_methods, 0); -} -/* }}} */ -int update_status_on_answer (struct query *q UU) { - struct mtproto_connection *mtp = query_get_mtproto(q); - - fetch_bool (mtp); - return 0; -} - -struct query_methods update_status_methods = { - .on_answer = update_status_on_answer -}; - -void do_update_status (struct telegram *instance, int online UU) { - info ("do_update_status()\n"); - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - clear_packet (mtp); - out_int (mtp, CODE_account_update_status); - out_int (mtp, online ? CODE_bool_false : CODE_bool_true); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &update_status_methods, 0); -} - -int update_typing_on_answer (struct query *q UU) { - fetch_bool (query_get_mtproto (q)); - return 0; -} - -struct query_methods update_typing_methods = { - .on_answer = update_typing_on_answer -}; - -void do_update_typing (struct telegram *instance, peer_id_t id) { - info ("do_update_typing()\n"); - struct dc *DC_working = telegram_get_working_dc(instance); - struct mtproto_connection *mtp = instance->connection; - - clear_packet (mtp); - out_int (mtp, CODE_messages_set_typing); - out_peer_id (mtp, id); - out_int (mtp, CODE_bool_true); - send_query (instance, DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &update_typing_methods, 0); -} - diff --git a/queries.h b/queries.h deleted file mode 100644 index c8c93b7..0000000 --- a/queries.h +++ /dev/null @@ -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 . - - 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(); diff --git a/structures.c b/structures.c deleted file mode 100644 index 4073ae0..0000000 --- a/structures.c +++ /dev/null @@ -1,2090 +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 . - - Copyright Vitaly Valtman 2013 -*/ - -#include -#include -#include "constants.h" -#include "structures.h" -#include "telegram.h" -#include "tree.h" -#include "loop.h" -#include -#include -#include "queries.h" -#include "binlog.h" -#include "net.h" - -#define sha1 SHA1 - -static int id_cmp (struct message *M1, struct message *M2); -#define peer_cmp(a,b) (cmp_peer_id (a->id, b->id)) -#define peer_cmp_name(a,b) (strcmp (a->print_name, b->print_name)) -DEFINE_TREE(peer,peer_t *,peer_cmp,0) -DEFINE_TREE(peer_by_name,peer_t *,peer_cmp_name,0) -DEFINE_TREE(message,struct message *,id_cmp,0) - -struct message message_list = { - .next_use = &message_list, - .prev_use = &message_list -}; - -int verbosity; - -void fetch_skip_photo (struct mtproto_connection *mtp); - -#define code_assert(x) if (!(x)) { fatal ("Can not parse at line %d\n", __LINE__); assert (0); return -1; } -#define code_try(x) if ((x) == -1) { return -1; } - -/* - * - * Fetch simple structures (immediate fetch into buffer) - * - */ - -int fetch_file_location (struct mtproto_connection *mtp, struct file_location *loc) { - int x = fetch_int (mtp); - code_assert (x == CODE_file_location_unavailable || x == CODE_file_location); - - if (x == CODE_file_location_unavailable) { - loc->dc = -1; - loc->volume = fetch_long (mtp); - loc->local_id = fetch_int (mtp); - loc->secret = fetch_long (mtp); - } else { - loc->dc = fetch_int (mtp); - loc->volume = fetch_long (mtp); - loc->local_id = fetch_int (mtp); - loc->secret = fetch_long (mtp); - } - return 0; -} - -int fetch_user_status (struct mtproto_connection *mtp, struct user_status *S) { - unsigned x = fetch_int (mtp); - code_assert (x == CODE_user_status_empty || x == CODE_user_status_online || x == CODE_user_status_offline); - switch (x) { - case CODE_user_status_empty: - S->online = 0; - S->when = 0; - break; - case CODE_user_status_online: - S->online = 1; - S->when = fetch_int (mtp); - break; - case CODE_user_status_offline: - S->online = -1; - S->when = fetch_int (mtp); - break; - default: - assert (0); - } - return 0; -} - -/* - * - * Skip simple structures - * - */ - -int fetch_skip_file_location (struct mtproto_connection *mtp) { - int x = fetch_int (mtp); - code_assert (x == CODE_file_location_unavailable || x == CODE_file_location); - - if (x == CODE_file_location_unavailable) { - mtp->in_ptr += 5; - } else { - mtp->in_ptr += 6; - } - return 0; -} - -int fetch_skip_user_status (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - code_assert (x == CODE_user_status_empty || x == CODE_user_status_online || x == CODE_user_status_offline); - if (x != CODE_user_status_empty) { - fetch_int (mtp); - } - return 0; -} - -char *create_print_name (struct binlog *bl, peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4) { - const char *d[4]; - d[0] = a1; d[1] = a2; d[2] = a3; d[3] = a4; - static char buf[10000]; - buf[0] = 0; - int i; - int p = 0; - for (i = 0; i < 4; i++) { - if (d[i] && strlen (d[i])) { - p += tsnprintf (buf + p, 9999 - p, "%s%s", p ? "_" : "", d[i]); - assert (p < 9990); - } - } - char *s = buf; - while (*s) { - if (*s == ' ') { *s = '_'; } - s++; - } - s = buf; - int fl = strlen (s); - int cc = 0; - while (1) { - peer_t *P = peer_lookup_name (bl, s); - if (!P || !cmp_peer_id (P->id, id)) { - break; - } - cc ++; - assert (cc <= 9999); - tsnprintf (s + fl, 9999 - fl, "#%d", cc); - } - return tstrdup (s); -} - -/* - * - * Fetch with log event - * - */ - -long long fetch_user_photo (struct mtproto_connection *mtp, struct tgl_user *U) { - unsigned x = fetch_int (mtp); - code_assert (x == CODE_user_profile_photo || x == CODE_user_profile_photo_old || x == CODE_user_profile_photo_empty); - if (x == CODE_user_profile_photo_empty) { - bl_do_set_user_profile_photo (mtp->bl, mtp, U, 0, 0, 0); - return 0; - } - long long photo_id = 1; - if (x == CODE_user_profile_photo) { - photo_id = fetch_long (mtp); - } - struct file_location big; - struct file_location small; - code_try (fetch_file_location (mtp, &small)); - code_try (fetch_file_location (mtp, &big)); - - bl_do_set_user_profile_photo (mtp->bl, mtp, U, photo_id, &big, &small); - return 0; -} - -void sanitize_alias(char *buffer) -{ - size_t len = strlen(buffer); - gchar *curr; - while ((curr = g_utf8_strchr(buffer, len, '\n'))) { - *curr = 0x20; - } -} - -int user_get_alias(peer_t *user, char *buffer, int maxlen) -{ - char* last_name = (user->user.last_name && strlen(user->user.last_name)) ? user->user.last_name : ""; - char* first_name = (user->user.first_name && strlen(user->user.first_name)) ? user->user.first_name : ""; - sanitize_alias (last_name); - sanitize_alias(first_name); - if (strlen(first_name) && strlen(last_name)) { - return snprintf(buffer, maxlen, "%s %s", first_name, last_name); - } else if (strlen(first_name)) { - return snprintf(buffer, maxlen, "%s", first_name); - } else if (strlen(last_name)) { - return snprintf(buffer, maxlen, "%s", last_name); - } else { - return snprintf(buffer, maxlen, "%d", get_peer_id(user->id)); - } -} - -int fetch_user (struct mtproto_connection *mtp, struct tgl_user *U) { - struct telegram *instance = mtp->instance; - - unsigned x = fetch_int (mtp); - code_assert (x == CODE_user_empty || x == CODE_user_self || x == CODE_user_contact || x == CODE_user_request || x == CODE_user_foreign || x == CODE_user_deleted); - U->id = MK_USER (fetch_int (mtp)); - if (x == CODE_user_empty) { - return 0; - } - - if (x == CODE_user_self) { - assert (!instance->our_id || (instance->our_id == get_peer_id (U->id))); - if (!instance->our_id) { - bl_do_set_our_id (mtp->bl, mtp, get_peer_id (U->id)); - // TODO: What to do here? - //write_auth_file (); - } - } - - int new = 0; - if (!(U->flags & FLAG_CREATED)) { - new = 1; - } - if (new) { - int l1 = prefetch_strlen (mtp); - code_assert (l1 >= 0); - char *s1 = fetch_str (mtp, l1); - int l2 = prefetch_strlen (mtp); - code_assert (l2 >= 0); - char *s2 = fetch_str (mtp, l2); - - if (x == CODE_user_deleted && !(U->flags & FLAG_DELETED)) { - bl_do_new_user (mtp->bl, mtp, get_peer_id (U->id), s1, l1, s2, l2, 0, 0, 0, 0); - bl_do_user_delete (mtp->bl, mtp, U); - } - if (x != CODE_user_deleted) { - long long access_token = 0; - if (x != CODE_user_self) { - access_token = fetch_long (mtp); - } - int phone_len = 0; - char *phone = 0; - if (x != CODE_user_foreign) { - phone_len = prefetch_strlen (mtp); - code_assert (phone_len >= 0); - phone = fetch_str (mtp, phone_len); - } - bl_do_new_user (mtp->bl, mtp, get_peer_id (U->id), s1, l1, s2, l2, access_token, phone, phone_len, x == CODE_user_contact); - if (fetch_user_photo (mtp, U) < 0) { return -1; } - - if (fetch_user_status (mtp, &U->status) < 0) { return -1; } - if (x == CODE_user_self) { - fetch_bool (mtp); - } - } - } else { - int l1 = prefetch_strlen (mtp); - char *s1 = fetch_str (mtp, l1); - int l2 = prefetch_strlen (mtp); - char *s2 = fetch_str (mtp, l2); - - bl_do_set_user_name (mtp->bl, mtp, U, s1, l1, s2, l2); - - if (x == CODE_user_deleted && !(U->flags & FLAG_DELETED)) { - bl_do_user_delete (mtp->bl, mtp, U); - } - if (x != CODE_user_deleted) { - if (x != CODE_user_self) { - bl_do_set_user_access_token (mtp->bl, mtp, U, fetch_long (mtp)); - } - if (x != CODE_user_foreign) { - int l = prefetch_strlen (mtp); - char *s = fetch_str (mtp, l); - bl_do_set_user_phone (mtp->bl, mtp, U, s, l); - } - if (fetch_user_photo (mtp, U) < 0) { return -1; } - - fetch_user_status (mtp, &U->status); - if (x == CODE_user_self) { - fetch_bool (mtp); - } - - if (x == CODE_user_contact) { - bl_do_set_user_friend (mtp->bl, mtp, U, 1); - } else { - bl_do_set_user_friend (mtp->bl, mtp, U, 0); - } - } - } - return 0; -} - -void fetch_encrypted_chat (struct mtproto_connection *mtp, struct secret_chat *U) { - struct telegram *instance = mtp->instance; - - unsigned x = fetch_int (mtp); - assert (x == CODE_encrypted_chat_empty || x == CODE_encrypted_chat_waiting || x == CODE_encrypted_chat_requested || x == CODE_encrypted_chat || x == CODE_encrypted_chat_discarded); - U->id = MK_ENCR_CHAT (fetch_int (mtp)); - if (x == CODE_encrypted_chat_empty) { - return; - } - int new = !(U->flags & FLAG_CREATED); - - if (x == CODE_encrypted_chat_discarded) { - if (new) { - warning ("Unknown chat in deleted state. May be we forgot something...\n"); - return; - } - bl_do_encr_chat_delete (mtp->bl, mtp, U); - - write_secret_chat_file (instance, instance->secret_path); - return; - } - - static char g_key[256]; - static char nonce[256]; - if (new) { - long long access_hash = fetch_long (mtp); - int date = fetch_int (mtp); - int admin_id = fetch_int (mtp); - int user_id = fetch_int (mtp) + admin_id - instance->our_id; - - if (x == CODE_encrypted_chat_waiting) { - warning ("Unknown chat in waiting state. May be we forgot something...\n"); - return; - } - if (x == CODE_encrypted_chat_requested || x == CODE_encrypted_chat) { - memset (g_key, 0, sizeof (g_key)); - memset (nonce, 0, sizeof (nonce)); - } - - int l = prefetch_strlen (mtp); - char *s = fetch_str (mtp, l); - if (l != 256) { debug ("l = %d\n", l); } - if (l < 256) { - memcpy (g_key + 256 - l, s, l); - } else { - memcpy (g_key, s + (l - 256), 256); - } - - /*l = prefetch_strlen (mtp); - s = fetch_str (mtp, l); - if (l != 256) { debug ("l = %d\n", l); } - if (l < 256) { - memcpy (nonce + 256 - l, s, l); - } else { - memcpy (nonce, s + (l - 256), 256); - }*/ - - if (x == CODE_encrypted_chat) { - fetch_long (mtp); // fingerprint - } - - if (x == CODE_encrypted_chat) { - warning ("Unknown chat in ok state. May be we forgot something...\n"); - return; - } - - bl_do_encr_chat_requested (mtp->bl, mtp, U, access_hash, date, admin_id, user_id, (void *)g_key, (void *)nonce); - write_secret_chat_file (instance, instance->secret_path); - } else { - bl_do_set_encr_chat_access_hash (mtp->bl, mtp, U, fetch_long (mtp)); - bl_do_set_encr_chat_date (mtp->bl, mtp, U, fetch_int (mtp)); - if (fetch_int (mtp) != U->admin_id) { - failure ("Changed admin in secret chat. WTF?\n"); - return; - } - if (U->user_id != U->admin_id + fetch_int (mtp) - instance->our_id) { - failure ("Changed partner in secret chat. WTF?\n"); - return; - } - if (x == CODE_encrypted_chat_waiting) { - bl_do_set_encr_chat_state (mtp->bl, mtp, U, sc_waiting); - write_secret_chat_file (instance, instance->secret_path); - return; // We needed only access hash from here - } - - if (x == CODE_encrypted_chat_requested || x == CODE_encrypted_chat) { - memset (g_key, 0, sizeof (g_key)); - memset (nonce, 0, sizeof (nonce)); - } - - int l = prefetch_strlen (mtp); - char *s = fetch_str (mtp, l); - if (l != 256) { debug ("l = %d\n", l); } - if (l < 256) { - memcpy (g_key + 256 - l, s, l); - } else { - memcpy (g_key, s + (l - 256), 256); - } - - /*l = prefetch_strlen (mtp); - s = fetch_str (mtp, l); - if (l != 256) { debug ("l = %d\n", l); } - if (l < 256) { - memcpy (nonce + 256 - l, s, l); - } else { - memcpy (nonce, s + (l - 256), 256); - }*/ - - if (x == CODE_encrypted_chat_requested) { - return; // Duplicate? - } - bl_do_encr_chat_accepted (mtp->bl, mtp, U, (void *)g_key, (void *)nonce, fetch_long (mtp)); - } - write_secret_chat_file (instance, instance->secret_path); -} - -void fetch_notify_settings (struct mtproto_connection *mtp); -void fetch_user_full (struct mtproto_connection *mtp, struct tgl_user *U) { - assert (fetch_int (mtp) == CODE_user_full); - fetch_alloc_user (mtp); - unsigned x; - assert (fetch_int (mtp) == (int)CODE_contacts_link); - x = fetch_int (mtp); - assert (x == CODE_contacts_my_link_empty || x == CODE_contacts_my_link_requested || x == CODE_contacts_my_link_contact); - if (x == CODE_contacts_my_link_requested) { - fetch_bool (mtp); - } - x = fetch_int (mtp); - assert (x == CODE_contacts_foreign_link_unknown || x == CODE_contacts_foreign_link_requested || x == CODE_contacts_foreign_link_mutual); - if (x == CODE_contacts_foreign_link_requested) { - fetch_bool (mtp); - } - fetch_alloc_user (mtp); - - int *start = mtp->in_ptr; - fetch_photo (mtp, &U->photo); - bl_do_set_user_full_photo (mtp->bl, mtp, U, start, 4 * (mtp->in_ptr - start)); - - fetch_notify_settings (mtp); - - bl_do_set_user_blocked (mtp->bl, mtp, U, fetch_bool (mtp)); - int l1 = prefetch_strlen (mtp); - char *s1 = fetch_str (mtp, l1); - int l2 = prefetch_strlen (mtp); - char *s2 = fetch_str (mtp, l2); - bl_do_set_user_real_name (mtp->bl, mtp, U, s1, l1, s2, l2); -} - -void fetch_chat (struct mtproto_connection *mtp, struct chat *C) { - unsigned x = fetch_int (mtp); - assert (x == CODE_chat_empty || x == CODE_chat || x == CODE_chat_forbidden); - C->id = MK_CHAT (fetch_int (mtp)); - if (x == CODE_chat_empty) { - return; - } - int new = !(C->flags & FLAG_CREATED); - if (new) { - int y = 0; - if (x == CODE_chat_forbidden) { - y |= FLAG_FORBIDDEN; - } - int l = prefetch_strlen (mtp); - char *s = fetch_str (mtp, l); - - struct file_location small; - struct file_location big; - memset (&small, 0, sizeof (small)); - memset (&big, 0, sizeof (big)); - int users_num = -1; - int date = 0; - int version = -1; - - if (x == CODE_chat) { - unsigned z = fetch_int (mtp); - if (z == CODE_chat_photo_empty) { - small.dc = -2; - big.dc = -2; - } else { - assert (z == CODE_chat_photo); - fetch_file_location (mtp, &small); - fetch_file_location (mtp, &big); - } - users_num = fetch_int (mtp); - date = fetch_int (mtp); - if (fetch_bool (mtp)) { - y |= FLAG_CHAT_IN_CHAT; - } - version = fetch_int (mtp); - } else { - small.dc = -2; - big.dc = -2; - users_num = -1; - date = fetch_int (mtp); - version = -1; - } - - bl_do_create_chat (mtp->bl, mtp, C, y, s, l, users_num, date, version, &big, &small); - } else { - if (x == CODE_chat_forbidden) { - bl_do_chat_forbid (mtp->bl, mtp, C, 1); - } else { - bl_do_chat_forbid (mtp->bl, mtp, C, 0); - } - int l = prefetch_strlen (mtp); - char *s = fetch_str (mtp, l); - bl_do_set_chat_title (mtp->bl, mtp, C, s, l); - - struct file_location small; - struct file_location big; - memset (&small, 0, sizeof (small)); - memset (&big, 0, sizeof (big)); - - if (x == CODE_chat) { - unsigned y = fetch_int (mtp); - if (y == CODE_chat_photo_empty) { - small.dc = -2; - big.dc = -2; - } else { - assert (y == CODE_chat_photo); - fetch_file_location (mtp, &small); - fetch_file_location (mtp, &big); - } - bl_do_set_chat_photo (mtp->bl, mtp, C, &big, &small); - int users_num = fetch_int (mtp); - bl_do_set_chat_date (mtp->bl, mtp, C, fetch_int (mtp)); - bl_do_set_chat_set_in_chat (mtp->bl, mtp, C, fetch_bool (mtp)); - bl_do_set_chat_version (mtp->bl, mtp, C, users_num, fetch_int (mtp)); - } else { - bl_do_set_chat_date (mtp->bl, mtp, C, fetch_int (mtp)); - } - } -} - -void fetch_notify_settings (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - assert (x == CODE_peer_notify_settings || x == CODE_peer_notify_settings_empty || x == CODE_peer_notify_settings_old); - if (x == CODE_peer_notify_settings_old) { - fetch_int (mtp); // mute_until - int l = prefetch_strlen (mtp); - fetch_str (mtp, l); - fetch_bool (mtp); // show_previews - fetch_int (mtp); // peer notify events - } - if (x == CODE_peer_notify_settings) { - fetch_int (mtp); // mute_until - int l = prefetch_strlen (mtp); - fetch_str (mtp, l); - fetch_bool (mtp); // show_previews - fetch_int (mtp); // events_mask - } -} - -void fetch_chat_full (struct mtproto_connection *mtp, struct chat *C) { - unsigned x = fetch_int (mtp); - assert (x == CODE_messages_chat_full); - assert (fetch_int (mtp) == CODE_chat_full); - C->id = MK_CHAT (fetch_int (mtp)); - //C->flags &= ~(FLAG_DELETED | FLAG_FORBIDDEN | FLAG_CHAT_IN_CHAT); - //C->flags |= FLAG_CREATED; - x = fetch_int (mtp); - int version = 0; - struct chat_user *users = 0; - int users_num = 0; - int admin_id = 0; - - if (x == CODE_chat_participants) { - assert (fetch_int (mtp) == get_peer_id (C->id)); - admin_id = fetch_int (mtp); - assert (fetch_int (mtp) == CODE_vector); - users_num = fetch_int (mtp); - users = talloc (sizeof (struct chat_user) * users_num); - int i; - for (i = 0; i < users_num; i++) { - assert (fetch_int (mtp) == (int)CODE_chat_participant); - users[i].user_id = fetch_int (mtp); - users[i].inviter_id = fetch_int (mtp); - users[i].date = fetch_int (mtp); - } - version = fetch_int (mtp); - } - int *start = mtp->in_ptr; - fetch_skip_photo (mtp); - int *end = mtp->in_ptr; - fetch_notify_settings (mtp); - - int n, i; - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_chat (mtp); - } - assert (fetch_int (mtp) == CODE_vector); - n = fetch_int (mtp); - for (i = 0; i < n; i++) { - fetch_alloc_user (mtp); - } - if (admin_id) { - bl_do_set_chat_admin (mtp->bl, mtp, C, admin_id); - } - if (version > 0) { - bl_do_set_chat_participants (mtp->bl, mtp, C, version, users_num, users); - tfree (users, sizeof (struct chat_user) * users_num); - } - bl_do_set_chat_full_photo (mtp->bl, mtp, C, start, 4 * (end - start)); -} - -void fetch_photo_size (struct mtproto_connection *mtp, struct photo_size *S) { - memset (S, 0, sizeof (*S)); - unsigned x = fetch_int (mtp); - assert (x == CODE_photo_size || x == CODE_photo_cached_size || x == CODE_photo_size_empty); - S->type = fetch_str_dup (mtp); - debug("s->type %s\n", S->type); - if (x != CODE_photo_size_empty) { - fetch_file_location (mtp, &S->loc); - S->w = fetch_int (mtp); - S->h = fetch_int (mtp); - if (x == CODE_photo_size) { - S->size = fetch_int (mtp); - } else { - S->size = prefetch_strlen (mtp); -// S->data = talloc (S->size); - fetch_str (mtp, S->size); -// memcpy (S->data, fetch_str (mtp, S->size), S->size); - } - } -} - -void fetch_skip_photo_size (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - assert (x == CODE_photo_size || x == CODE_photo_cached_size || x == CODE_photo_size_empty); - int l = prefetch_strlen (mtp); - fetch_str (mtp, l); // type - if (x != CODE_photo_size_empty) { - fetch_skip_file_location (mtp); - mtp->in_ptr += 2; // w, h - if (x == CODE_photo_size) { - mtp->in_ptr ++; - } else { - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - } - } -} - -void fetch_geo (struct mtproto_connection *mtp, struct geo *G) { - unsigned x = fetch_int (mtp); - if (x == CODE_geo_point) { - G->longitude = fetch_double (mtp); - G->latitude = fetch_double (mtp); - } else { - assert (x == CODE_geo_point_empty); - G->longitude = 0; - G->latitude = 0; - } -} - -void fetch_skip_geo (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - assert (x == CODE_geo_point || x == CODE_geo_point_empty); - if (x == CODE_geo_point) { - mtp->in_ptr += 4; - } -} - -void fetch_photo (struct mtproto_connection *mtp, struct photo *P) { - memset (P, 0, sizeof (*P)); - unsigned x = fetch_int (mtp); - assert (x == CODE_photo_empty || x == CODE_photo); - P->id = fetch_long (mtp); - if (x == CODE_photo_empty) { return; } - P->access_hash = fetch_long (mtp); - P->user_id = fetch_int (mtp); - P->date = fetch_int (mtp); - P->caption = fetch_str_dup (mtp); - fetch_geo (mtp, &P->geo); - assert (fetch_int (mtp) == CODE_vector); - P->sizes_num = fetch_int (mtp); - debug("sizes_num %d \n", P->sizes_num); - P->sizes = talloc (sizeof (struct photo_size) * P->sizes_num); - int i; - for (i = 0; i < P->sizes_num; i++) { - fetch_photo_size (mtp, &P->sizes[i]); - } -} - -void fetch_skip_photo (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - assert (x == CODE_photo_empty || x == CODE_photo); - mtp->in_ptr += 2; // id - if (x == CODE_photo_empty) { return; } - mtp->in_ptr += 2 +1 + 1; // access_hash, user_id, date - int l = prefetch_strlen (mtp); - fetch_str (mtp, l); // caption - fetch_skip_geo (mtp); - assert (fetch_int (mtp) == CODE_vector); - int n = fetch_int (mtp); - int i; - for (i = 0; i < n; i++) { - fetch_skip_photo_size (mtp); - } -} - -void fetch_video (struct mtproto_connection *mtp, struct video *V) { - memset (V, 0, sizeof (*V)); - unsigned x = fetch_int (mtp); - V->id = fetch_long (mtp); - if (x == CODE_video_empty) { return; } - V->access_hash = fetch_long (mtp); - V->user_id = fetch_int (mtp); - V->date = fetch_int (mtp); - V->caption = fetch_str_dup (mtp); - V->duration = fetch_int (mtp); - V->size = fetch_int (mtp); - fetch_photo_size (mtp, &V->thumb); - V->dc_id = fetch_int (mtp); - V->w = fetch_int (mtp); - V->h = fetch_int (mtp); -} - -void fetch_skip_video (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - fetch_long (mtp); - if (x == CODE_video_empty) { return; } - fetch_skip (mtp, 4); - int l = prefetch_strlen (mtp); - fetch_str (mtp, l); - fetch_skip (mtp, 2); - fetch_skip_photo_size (mtp); - fetch_skip (mtp, 3); -} - -void fetch_audio (struct mtproto_connection *mtp, struct audio *V) { - memset (V, 0, sizeof (*V)); - unsigned x = fetch_int (mtp); - V->id = fetch_long (mtp); - if (x == CODE_audio_empty) { return; } - V->access_hash = fetch_long (mtp); - V->user_id = fetch_int (mtp); - V->date = fetch_int (mtp); - V->duration = fetch_int (mtp); - V->size = fetch_int (mtp); - V->dc_id = fetch_int (mtp); -} - -void fetch_skip_audio (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - fetch_skip (mtp, 2); - if (x == CODE_audio_empty) { return; } - fetch_skip (mtp, 7); -} - -void fetch_document (struct mtproto_connection *mtp, struct document *V) { - memset (V, 0, sizeof (*V)); - unsigned x = fetch_int (mtp); - V->id = fetch_long (mtp); - if (x == CODE_document_empty) { return; } - V->access_hash = fetch_long (mtp); - V->user_id = fetch_int (mtp); - V->date = fetch_int (mtp); - V->caption = fetch_str_dup (mtp); - V->mime_type = fetch_str_dup (mtp); - V->size = fetch_int (mtp); - fetch_photo_size (mtp, &V->thumb); - V->dc_id = fetch_int (mtp); -} - -void fetch_skip_document (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - fetch_skip (mtp, 2); - if (x == CODE_document_empty) { return; } - fetch_skip (mtp, 4); - int l = prefetch_strlen (mtp); - fetch_str (mtp, l); - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - fetch_skip (mtp, 1); - fetch_skip_photo_size (mtp); - fetch_skip (mtp, 1); -} - -void fetch_message_action (struct mtproto_connection *mtp, struct message_action *M) { - memset (M, 0, sizeof (*M)); - unsigned x = fetch_int (mtp); - M->type = x; - switch (x) { - case CODE_message_action_empty: - break; - case CODE_message_action_geo_chat_create: - { - int l = prefetch_strlen (mtp); // title - char *s = fetch_str (mtp, l); - int l2 = prefetch_strlen (mtp); // checkin - char *s2 = fetch_str (mtp, l2); - debug ("Message action: Created geochat %.*s in address %.*s\n", l, s, l2, s2); - } - break; - case CODE_message_action_geo_chat_checkin: - break; - case CODE_message_action_chat_create: - M->title = fetch_str_dup (mtp); - assert (fetch_int (mtp) == (int)CODE_vector); - M->user_num = fetch_int (mtp); - M->users = talloc (M->user_num * 4); - fetch_ints (mtp, M->users, M->user_num); - break; - case CODE_message_action_chat_edit_title: - M->new_title = fetch_str_dup (mtp); - break; - case CODE_message_action_chat_edit_photo: - fetch_photo (mtp, &M->photo); - break; - case CODE_message_action_chat_delete_photo: - break; - case CODE_message_action_chat_add_user: - M->user = fetch_int (mtp); - break; - case CODE_message_action_chat_delete_user: - M->user = fetch_int (mtp); - break; - default: - assert (0); - } -} - -void fetch_skip_message_action (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - int l; - switch (x) { - case CODE_message_action_empty: - break; - case CODE_message_action_geo_chat_create: - { - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - } - break; - case CODE_message_action_geo_chat_checkin: - break; - case CODE_message_action_chat_create: - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - assert (fetch_int (mtp) == (int)CODE_vector); - l = fetch_int (mtp); - fetch_skip (mtp, l); - break; - case CODE_message_action_chat_edit_title: - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - break; - case CODE_message_action_chat_edit_photo: - fetch_skip_photo (mtp); - break; - case CODE_message_action_chat_delete_photo: - break; - case CODE_message_action_chat_add_user: - fetch_int (mtp); - break; - case CODE_message_action_chat_delete_user: - fetch_int (mtp); - break; - default: - assert (0); - } -} - -void fetch_message_short (struct mtproto_connection *mtp, struct message *M) { - struct telegram *instance = mtp->instance; - - int new = !(M->flags & FLAG_CREATED); - - if (new) { - int id = fetch_int (mtp); - int from_id = fetch_int (mtp); - int to_id = instance->our_id; - int l = prefetch_strlen (mtp); - char *s = fetch_str (mtp, l); - - fetch_pts (mtp); - - int date = fetch_int (mtp); - fetch_seq (mtp); - - bl_do_create_message_text (mtp->bl, mtp, id, from_id, PEER_USER, to_id, date, l, s); - } else { - fetch_int (mtp); // id - fetch_int (mtp); // from_id - int l = prefetch_strlen (mtp); - fetch_str (mtp, l); // text - - fetch_pts (mtp); - fetch_int (mtp); - fetch_seq (mtp); - } -} - -void fetch_message_short_chat (struct mtproto_connection *mtp, struct message *M) { - int new = !(M->flags & FLAG_CREATED); - - if (new) { - int id = fetch_int (mtp); - int from_id = fetch_int (mtp); - int to_id = fetch_int (mtp); - int l = prefetch_strlen (mtp); - char *s = fetch_str (mtp, l); - - fetch_pts (mtp); - - int date = fetch_int (mtp); - fetch_seq (mtp); - - bl_do_create_message_text (mtp->bl, mtp, id, from_id, PEER_CHAT, to_id, date, l, s); - } else { - fetch_int (mtp); // id - fetch_int (mtp); // from_id - fetch_int (mtp); // to_id - int l = prefetch_strlen (mtp); - fetch_str (mtp, l); // text - - fetch_pts (mtp); - fetch_int (mtp); - fetch_seq (mtp); - } -} - - -void fetch_message_media (struct mtproto_connection *mtp, struct message_media *M) { - memset (M, 0, sizeof (*M)); - M->type = fetch_int (mtp); - switch (M->type) { - case CODE_message_media_empty: - break; - case CODE_message_media_photo: - fetch_photo (mtp, &M->photo); - break; - case CODE_message_media_video: - fetch_video (mtp, &M->video); - break; - case CODE_message_media_audio: - fetch_audio (mtp, &M->audio); - break; - case CODE_message_media_document: - fetch_document (mtp, &M->document); - break; - case CODE_message_media_geo: - fetch_geo (mtp, &M->geo); - break; - case CODE_message_media_contact: - M->phone = fetch_str_dup (mtp); - M->first_name = fetch_str_dup (mtp); - M->last_name = fetch_str_dup (mtp); - M->user_id = fetch_int (mtp); - break; - case CODE_message_media_unsupported: - M->data_size = prefetch_strlen (mtp); - M->data = talloc (M->data_size); - memcpy (M->data, fetch_str (mtp, M->data_size), M->data_size); - break; - default: - debug ("type = 0x%08x\n", M->type); - assert (0); - } -} - -void fetch_skip_message_media (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - switch (x) { - case CODE_message_media_empty: - break; - case CODE_message_media_photo: - fetch_skip_photo (mtp); - break; - case CODE_message_media_video: - fetch_skip_video (mtp); - break; - case CODE_message_media_audio: - fetch_skip_audio (mtp); - break; - case CODE_message_media_document: - fetch_skip_document (mtp); - break; - case CODE_message_media_geo: - fetch_skip_geo (mtp); - break; - case CODE_message_media_contact: - { - int l; - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - fetch_int (mtp); - } - break; - case CODE_message_media_unsupported: - { - int l = prefetch_strlen (mtp); - fetch_str (mtp, l); - } - break; - default: - debug ("type = 0x%08x\n", x); - assert (0); - } -} - -void fetch_skip_message_media_encrypted (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - int l; - switch (x) { - case CODE_decrypted_message_media_empty: - break; - case CODE_decrypted_message_media_photo: - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - fetch_skip (mtp, 5); - - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - break; - case CODE_decrypted_message_media_video: - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - - fetch_skip (mtp, 6); - - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - break; - case CODE_decrypted_message_media_audio: - fetch_skip (mtp, 2); - - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - break; - case CODE_decrypted_message_media_document: - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - - fetch_skip (mtp, 2); - - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - fetch_skip (mtp, 1); - - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - - l = prefetch_strlen (mtp); - fetch_str (mtp, l); - break; - case CODE_decrypted_message_media_geo_point: - fetch_skip (mtp, 4); - break; - case CODE_decrypted_message_media_contact: - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - fetch_skip (mtp, 1); - break; - default: - debug ("type = 0x%08x\n", x); - assert (0); - } -} - -void fetch_message_media_encrypted (struct mtproto_connection *mtp, struct message_media *M) { - memset (M, 0, sizeof (*M)); - unsigned x = fetch_int (mtp); - int l; - switch (x) { - case CODE_decrypted_message_media_empty: - M->type = CODE_message_media_empty; - break; - case CODE_decrypted_message_media_photo: - M->type = x; - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - fetch_int (mtp); // thumb_w - fetch_int (mtp); // thumb_h - M->encr_photo.w = fetch_int (mtp); - M->encr_photo.h = fetch_int (mtp); - M->encr_photo.size = fetch_int (mtp); - - l = prefetch_strlen (mtp); - assert (l > 0); - M->encr_photo.key = talloc (32); - memset (M->encr_photo.key, 0, 32); - if (l <= 32) { - memcpy (M->encr_photo.key + (32 - l), fetch_str (mtp, l), l); - } else { - memcpy (M->encr_photo.key, fetch_str (mtp, l) + (l - 32), 32); - } - M->encr_photo.iv = talloc (32); - l = prefetch_strlen (mtp); - assert (l > 0); - memset (M->encr_photo.iv, 0, 32); - if (l <= 32) { - memcpy (M->encr_photo.iv + (32 - l), fetch_str (mtp, l), l); - } else { - memcpy (M->encr_photo.iv, fetch_str (mtp, l) + (l - 32), 32); - } - break; - case CODE_decrypted_message_media_video: - M->type = x; - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - fetch_int (mtp); // thumb_w - fetch_int (mtp); // thumb_h - M->encr_video.duration = fetch_int (mtp); - M->encr_video.w = fetch_int (mtp); - M->encr_video.h = fetch_int (mtp); - M->encr_video.size = fetch_int (mtp); - - l = prefetch_strlen (mtp); - assert (l > 0); - M->encr_video.key = talloc0 (32); - if (l <= 32) { - memcpy (M->encr_video.key + (32 - l), fetch_str (mtp, l), l); - } else { - memcpy (M->encr_video.key, fetch_str (mtp, l) + (l - 32), 32); - } - M->encr_video.iv = talloc (32); - l = prefetch_strlen (mtp); - assert (l > 0); - memset (M->encr_video.iv, 0, 32); - if (l <= 32) { - memcpy (M->encr_video.iv + (32 - l), fetch_str (mtp, l), l); - } else { - memcpy (M->encr_video.iv, fetch_str (mtp, l) + (l - 32), 32); - } - break; - case CODE_decrypted_message_media_audio: - M->type = x; - M->encr_audio.duration = fetch_int (mtp); - M->encr_audio.size = fetch_int (mtp); - - l = prefetch_strlen (mtp); - assert (l > 0); - M->encr_video.key = talloc0 (32); - if (l <= 32) { - memcpy (M->encr_video.key + (32 - l), fetch_str (mtp, l), l); - } else { - memcpy (M->encr_video.key, fetch_str (mtp, l) + (l - 32), 32); - } - M->encr_video.iv = talloc0 (32); - l = prefetch_strlen (mtp); - assert (l > 0); - if (l <= 32) { - memcpy (M->encr_video.iv + (32 - l), fetch_str (mtp, l), l); - } else { - memcpy (M->encr_video.iv, fetch_str (mtp, l) + (l - 32), 32); - } - break; - case CODE_decrypted_message_media_document: - M->type = x; - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - fetch_int (mtp); // thumb_w - fetch_int (mtp); // thumb_h - M->encr_document.file_name = fetch_str_dup (mtp); - M->encr_document.mime_type = fetch_str_dup (mtp); - M->encr_video.size = fetch_int (mtp); - - l = prefetch_strlen (mtp); - assert (l > 0); - M->encr_video.key = talloc0 (32); - if (l <= 32) { - memcpy (M->encr_video.key + (32 - l), fetch_str (mtp, l), l); - } else { - memcpy (M->encr_video.key, fetch_str (mtp, l) + (l - 32), 32); - } - M->encr_video.iv = talloc0 (32); - l = prefetch_strlen (mtp); - assert (l > 0); - if (l <= 32) { - memcpy (M->encr_video.iv + (32 - l), fetch_str (mtp, l), l); - } else { - memcpy (M->encr_video.iv, fetch_str (mtp, l) + (l - 32), 32); - } - break; -/* case CODE_decrypted_message_media_file: - M->type = x; - M->encr_file.filename = fetch_str_dup (mtp); - l = prefetch_strlen (mtp); - fetch_str (mtp, l); // thumb - l = fetch_int (mtp); - assert (l > 0); - M->encr_file.key = talloc (l); - memcpy (M->encr_file.key, fetch_str (mtp, l), l); - - l = fetch_int (mtp); - assert (l > 0); - M->encr_file.iv = talloc (l); - memcpy (M->encr_file.iv, fetch_str (mtp, l), l); - break; - */ - case CODE_decrypted_message_media_geo_point: - M->geo.longitude = fetch_double (mtp); - M->geo.latitude = fetch_double (mtp); - M->type = CODE_message_media_geo; - break; - case CODE_decrypted_message_media_contact: - M->type = CODE_message_media_contact; - M->phone = fetch_str_dup (mtp); - M->first_name = fetch_str_dup (mtp); - M->last_name = fetch_str_dup (mtp); - M->user_id = fetch_int (mtp); - break; - default: - debug ("type = 0x%08x\n", x); - assert (0); - } -} - -void fetch_skip_message_action_encrypted (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - switch (x) { - case CODE_decrypted_message_action_set_message_t_t_l: - fetch_skip (mtp, 1); - break; - default: - debug ("x = 0x%08x\n", x); - assert (0); - } -} - -void fetch_message_action_encrypted (struct mtproto_connection *mtp, struct message_action *M) { - unsigned x = fetch_int (mtp); - switch (x) { - case CODE_decrypted_message_action_set_message_t_t_l: - M->type = x; - M->ttl = fetch_int (mtp); - break; - default: - debug ("x = 0x%08x\n", x); - assert (0); - } -} - -peer_id_t fetch_peer_id (struct mtproto_connection *mtp) { - unsigned x =fetch_int (mtp); - if (x == CODE_peer_user) { - return MK_USER (fetch_int (mtp)); - } else { - assert (CODE_peer_chat); - return MK_CHAT (fetch_int (mtp)); - } -} - -void fetch_message (struct mtproto_connection *mtp, struct message *M) { - unsigned x = fetch_int (mtp); - assert (x == CODE_message_empty || x == CODE_message || x == CODE_message_forwarded || x == CODE_message_service); - int id = fetch_int (mtp); - assert (M->id == id); - if (x == CODE_message_empty) { - return; - } - int fwd_from_id = 0; - int fwd_date = 0; - - if (x == CODE_message_forwarded) { - fwd_from_id = fetch_int (mtp); - fwd_date = fetch_int (mtp); - } - int from_id = fetch_int (mtp); - peer_id_t to_id = fetch_peer_id (mtp); - - fetch_bool (mtp); // out. - - int unread = fetch_bool (mtp); - int date = fetch_int (mtp); - - int new = !(M->flags & FLAG_CREATED); - - if (x == CODE_message_service) { - int *start = mtp->in_ptr; - fetch_skip_message_action (mtp); - if (new) { - if (fwd_from_id) { - bl_do_create_message_service_fwd (mtp->bl, mtp, id, from_id, get_peer_type (to_id), get_peer_id (to_id), - date, fwd_from_id, fwd_date, start, (mtp->in_ptr - start)); - } else { - bl_do_create_message_service (mtp->bl, mtp, id, from_id, get_peer_type (to_id), - get_peer_id (to_id), date, start, (mtp->in_ptr - start)); - } - } - } else { - int l = prefetch_strlen (mtp); - char *s = fetch_str (mtp, l); - int *start = mtp->in_ptr; - fetch_skip_message_media (mtp); - if (new) { - if (fwd_from_id) { - bl_do_create_message_media_fwd (mtp->bl, mtp, id, from_id, get_peer_type (to_id), - get_peer_id (to_id), date, fwd_from_id, fwd_date, l, s, start, mtp->in_ptr - start); - } else { - bl_do_create_message_media (mtp->bl, mtp, id, from_id, get_peer_type (to_id), - get_peer_id (to_id), date, l, s, start, mtp->in_ptr - start); - } - } - } - bl_do_set_unread (mtp->bl, mtp, M, unread); -} - -void fetch_geo_message (struct mtproto_connection *mtp, struct message *M) { - memset (M, 0, sizeof (*M)); - unsigned x = fetch_int (mtp); - assert (x == CODE_geo_chat_message_empty || x == CODE_geo_chat_message || x == CODE_geo_chat_message_service); - M->to_id = MK_GEO_CHAT (fetch_int (mtp)); - M->id = fetch_int (mtp); - if (x == CODE_geo_chat_message_empty) { - M->flags |= 1; - return; - } - M->from_id = MK_USER (fetch_int (mtp)); - M->date = fetch_int (mtp); - if (x == CODE_geo_chat_message_service) { - M->service = 1; - fetch_message_action (mtp, &M->action); - } else { - M->message = fetch_str_dup (mtp); - M->message_len = strlen (M->message); - fetch_message_media (mtp, &M->media); - } -} - -static int *decr_ptr; -static int *decr_end; - -int decrypt_encrypted_message (struct secret_chat *E) { - int *msg_key = decr_ptr; - decr_ptr += 4; - assert (decr_ptr < decr_end); - static unsigned char sha1a_buffer[20]; - static unsigned char sha1b_buffer[20]; - static unsigned char sha1c_buffer[20]; - static unsigned char sha1d_buffer[20]; - - static unsigned char buf[64]; - memcpy (buf, msg_key, 16); - memcpy (buf + 16, E->key, 32); - sha1 (buf, 48, sha1a_buffer); - - memcpy (buf, E->key + 8, 16); - memcpy (buf + 16, msg_key, 16); - memcpy (buf + 32, E->key + 12, 16); - sha1 (buf, 48, sha1b_buffer); - - memcpy (buf, E->key + 16, 32); - memcpy (buf + 32, msg_key, 16); - sha1 (buf, 48, sha1c_buffer); - - memcpy (buf, msg_key, 16); - memcpy (buf + 16, E->key + 24, 32); - sha1 (buf, 48, sha1d_buffer); - - static unsigned char key[32]; - memcpy (key, sha1a_buffer + 0, 8); - memcpy (key + 8, sha1b_buffer + 8, 12); - memcpy (key + 20, sha1c_buffer + 4, 12); - - static unsigned char iv[32]; - memcpy (iv, sha1a_buffer + 8, 12); - memcpy (iv + 12, sha1b_buffer + 0, 8); - memcpy (iv + 20, sha1c_buffer + 16, 4); - memcpy (iv + 24, sha1d_buffer + 0, 8); - - AES_KEY aes_key; - AES_set_decrypt_key (key, 256, &aes_key); - AES_ige_encrypt ((void *)decr_ptr, (void *)decr_ptr, 4 * (decr_end - decr_ptr), &aes_key, iv, 0); - memset (&aes_key, 0, sizeof (aes_key)); - - int x = *(decr_ptr); - if (x < 0 || (x & 3)) { - return -1; - } - assert (x >= 0 && !(x & 3)); - sha1 ((void *)decr_ptr, 4 + x, sha1a_buffer); - - if (memcmp (sha1a_buffer + 4, msg_key, 16)) { - failure ("Sha1 mismatch\n"); - return -1; - } - return 0; -} - -void fetch_encrypted_message (struct mtproto_connection *mtp, struct message *M) { - struct binlog *bl = mtp->bl; - - unsigned x = fetch_int (mtp); - assert (x == CODE_encrypted_message || x == CODE_encrypted_message_service); - unsigned sx = x; - int new = !(M->flags & FLAG_CREATED); - long long id = fetch_long (mtp); - int to_id = fetch_int (mtp); - peer_id_t chat = MK_ENCR_CHAT (to_id); - int date = fetch_int (mtp); - - peer_t *P = user_chat_get (bl, chat); - if (!P) { - warning ("Encrypted message to unknown chat. Dropping\n"); - M->flags |= FLAG_MESSAGE_EMPTY; - } - - - int len = prefetch_strlen (mtp); - assert ((len & 15) == 8); - decr_ptr = (void *)fetch_str (mtp, len); - decr_end = decr_ptr + (len / 4); - int ok = 0; - if (P) { - if (*(long long *)decr_ptr != P->encr_chat.key_fingerprint) { - warning ("Encrypted message with bad fingerprint to chat %s\n", P->print_name); - P = 0; - } - decr_ptr += 2; - } - int l = 0; - char *s = 0; - int *start = 0; - int *end = 0; - x = 0; - if (P && decrypt_encrypted_message (&P->encr_chat) >= 0 && new) { - ok = 1; - int *save_in_ptr = mtp->in_ptr; - int *save_in_end = mtp->in_end; - mtp->in_ptr = decr_ptr; - int ll = fetch_int (mtp); - mtp->in_end = mtp->in_ptr + ll; - x = fetch_int (mtp); - if (x == CODE_decrypted_message_layer) { - int layer = fetch_int (mtp); - assert (layer >= 0); - x = fetch_int (mtp); - } - assert (x == CODE_decrypted_message || x == CODE_decrypted_message_service); - //assert (id == fetch_long (mtp)); - fetch_long (mtp); - ll = prefetch_strlen (mtp); - fetch_str (mtp, ll); // random_bytes - if (x == CODE_decrypted_message) { - l = prefetch_strlen (mtp); - s = fetch_str (mtp, l); - start = mtp->in_ptr; - fetch_skip_message_media_encrypted (mtp); - end = mtp->in_ptr; - } else { - start = mtp->in_ptr; - fetch_skip_message_action_encrypted (mtp); - end = mtp->in_ptr; - } - mtp->in_ptr = save_in_ptr; - mtp->in_end = save_in_end; - } - - if (sx == CODE_encrypted_message) { - if (ok) { - int *start_file = mtp->in_ptr; - fetch_skip_encrypted_message_file (mtp); - if (x == CODE_decrypted_message) { - bl_do_create_message_media_encr (mtp->bl, mtp, id, P->encr_chat.user_id, PEER_ENCR_CHAT, to_id, date, l, s, start, end - start, start_file, mtp->in_ptr - start_file); - } - } else { - x = fetch_int (mtp); - if (x == CODE_encrypted_file) { - fetch_skip (mtp, 7); - } else { - assert (x == CODE_encrypted_file_empty); - } - M->media.type = CODE_message_media_empty; - } - } else { - if (ok && x == CODE_decrypted_message_service) { - bl_do_create_message_service_encr (mtp->bl, mtp, id, P->encr_chat.user_id, PEER_ENCR_CHAT, to_id, date, start, end - start); - } - } -} - -void fetch_encrypted_message_file (struct mtproto_connection *mtp, struct message_media *M) { - unsigned x = fetch_int (mtp); - assert (x == CODE_encrypted_file || x == CODE_encrypted_file_empty); - if (x == CODE_encrypted_file_empty) { - assert (M->type != CODE_decrypted_message_media_photo && M->type != CODE_decrypted_message_media_video); - } else { - assert (M->type == CODE_decrypted_message_media_document || M->type == CODE_decrypted_message_media_photo || M->type == CODE_decrypted_message_media_video || M->type == CODE_decrypted_message_media_audio); - - M->encr_photo.id = fetch_long(mtp); - M->encr_photo.access_hash = fetch_long(mtp); - if (!M->encr_photo.size) { - M->encr_photo.size = fetch_int (mtp); - } else { - fetch_int (mtp); - } - M->encr_photo.dc_id = fetch_int(mtp); - M->encr_photo.key_fingerprint = fetch_int(mtp); - } -} - -void fetch_skip_encrypted_message_file (struct mtproto_connection *mtp) { - unsigned x = fetch_int (mtp); - assert (x == CODE_encrypted_file || x == CODE_encrypted_file_empty); - if (x == CODE_encrypted_file_empty) { - } else { - fetch_skip (mtp, 7); - } -} - -static int id_cmp (struct message *M1, struct message *M2) { - if (M1->id < M2->id) { return -1; } - else if (M1->id > M2->id) { return 1; } - else { return 0; } -} - -struct tgl_user *fetch_alloc_user (struct mtproto_connection *mtp) { - struct binlog *bl = mtp->instance->bl; - - debug("fetch_alloc_user()\n"); - int data[2]; - prefetch_data (mtp, data, 8); - peer_t *U = user_chat_get (bl, MK_USER (data[1])); - if (!U) { - bl->users_allocated ++; - U = talloc0 (sizeof (*U)); - U->id = MK_USER (data[1]); - bl->peer_tree = tree_insert_peer (bl->peer_tree, U, lrand48 ()); - assert (bl->peer_num < MAX_PEER_NUM); - bl->Peers[bl->peer_num ++] = U; - fetch_user (mtp, &U->user); - event_update_user_status(mtp->connection->instance, U); - event_peer_allocated(mtp->connection->instance, U); - } else { - fetch_user (mtp, &U->user); - event_update_user_status(mtp->connection->instance, U); - } - return &U->user; -} - -struct secret_chat *fetch_alloc_encrypted_chat (struct mtproto_connection *mtp) { - struct binlog *bl = mtp->bl; - - debug("fetch_alloc_encrypted_chat()\n"); - int data[2]; - prefetch_data (mtp, data, 8); - peer_t *U = user_chat_get (bl, MK_ENCR_CHAT (data[1])); - if (!U) { - U = talloc0 (sizeof (*U)); - U->id = MK_ENCR_CHAT (data[1]); - bl->encr_chats_allocated ++; - bl->peer_tree = tree_insert_peer (bl->peer_tree, U, lrand48 ()); - assert (bl->peer_num < MAX_PEER_NUM); - bl->Peers[bl->peer_num ++] = U; - } - fetch_encrypted_chat (mtp, &U->encr_chat); - event_peer_allocated(mtp->connection->instance, U); - return &U->encr_chat; -} - -void insert_encrypted_chat (struct binlog *bl, peer_t *P) { - bl->encr_chats_allocated ++; - bl->peer_tree = tree_insert_peer (bl->peer_tree, P, lrand48 ()); - assert (bl->peer_num < MAX_PEER_NUM); - bl->Peers[bl->peer_num ++] = P; -} - -void insert_user (struct binlog *bl, peer_t *P) { - bl->users_allocated ++; - bl->peer_tree = tree_insert_peer (bl->peer_tree, P, lrand48 ()); - assert (bl->peer_num < MAX_PEER_NUM); - bl->Peers[bl->peer_num ++] = P; -} - -void insert_chat (struct binlog *bl, peer_t *P) { - bl->chats_allocated ++; - bl->peer_tree = tree_insert_peer (bl->peer_tree, P, lrand48 ()); - assert (bl->peer_num < MAX_PEER_NUM); - bl->Peers[bl->peer_num ++] = P; -} - -struct tgl_user *fetch_alloc_user_full (struct mtproto_connection *mtp) { - struct binlog *bl = mtp->bl; - int data[3]; - prefetch_data (mtp, data, 12); - peer_t *U = user_chat_get (bl, MK_USER (data[2])); - if (U) { - fetch_user_full (mtp, &U->user); - return &U->user; - } else { - bl->users_allocated ++; - U = talloc0 (sizeof (*U)); - U->id = MK_USER (data[2]); - bl->peer_tree = tree_insert_peer (bl->peer_tree, U, lrand48 ()); - fetch_user_full (mtp, &U->user); - assert (bl->peer_num < MAX_PEER_NUM); - bl->Peers[bl->peer_num ++] = U; - return &U->user; - } -} - -void free_user (struct tgl_user *U) { - if (U->first_name) { tfree_str (U->first_name); } - if (U->last_name) { tfree_str (U->last_name); } - if (U->print_name) { tfree_str (U->print_name); } - if (U->phone) { tfree_str (U->phone); } -} - -void free_photo_size (struct photo_size *S) { - tfree_str (S->type); - if (S->data) { - tfree (S->data, S->size); - } -} - -void free_photo (struct photo *P) { - if (!P->access_hash) { return; } - if (P->caption) { tfree_str (P->caption); } - if (P->sizes) { - int i; - for (i = 0; i < P->sizes_num; i++) { - free_photo_size (&P->sizes[i]); - } - tfree (P->sizes, sizeof (struct photo_size) * P->sizes_num); - } -} - -void free_video (struct video *V) { - if (!V->access_hash) { return; } - tfree_str (V->caption); - free_photo_size (&V->thumb); -} - -void free_document (struct document *D) { - if (!D->access_hash) { return; } - tfree_str (D->caption); - tfree_str (D->mime_type); - free_photo_size (&D->thumb); -} - -void free_message_media (struct message_media *M) { - switch (M->type) { - case CODE_message_media_empty: - case CODE_message_media_geo: - case CODE_message_media_audio: - return; - case CODE_message_media_photo: - free_photo (&M->photo); - return; - case CODE_message_media_video: - free_video (&M->video); - return; - case CODE_message_media_contact: - tfree_str (M->phone); - tfree_str (M->first_name); - tfree_str (M->last_name); - return; - case CODE_message_media_document: - free_document (&M->document); - return; - case CODE_message_media_unsupported: - tfree (M->data, M->data_size); - return; - case CODE_decrypted_message_media_photo: - case CODE_decrypted_message_media_video: - case CODE_decrypted_message_media_audio: - case CODE_decrypted_message_media_document: - tfree_secure (M->encr_photo.key, 32); - tfree_secure (M->encr_photo.iv, 32); - return; - case 0: - break; - default: - debug ("%08x\n", M->type); - assert (0); - } -} - -void free_message_action (struct message_action *M) { - switch (M->type) { - case CODE_message_action_empty: - break; - case CODE_message_action_chat_create: - tfree_str (M->title); - tfree (M->users, M->user_num * 4); - break; - case CODE_message_action_chat_edit_title: - tfree_str (M->new_title); - break; - case CODE_message_action_chat_edit_photo: - free_photo (&M->photo); - break; - case CODE_message_action_chat_delete_photo: - break; - case CODE_message_action_chat_add_user: - break; - case CODE_message_action_chat_delete_user: - break; - case 0: - break; - default: - assert (0); - } -} - -void free_message (struct message *M) { - if (!M->service) { - if (M->message) { tfree (M->message, M->message_len + 1); } - free_message_media (&M->media); - } else { - free_message_action (&M->action); - } -} - -void message_del_use (struct message *M) { - M->next_use->prev_use = M->prev_use; - M->prev_use->next_use = M->next_use; -} - -void message_add_use (struct message *M) { - M->next_use = message_list.next_use; - M->prev_use = &message_list; - M->next_use->prev_use = M; - M->prev_use->next_use = M; -} - -void message_add_peer (struct message *M) { - struct binlog *bl = M->instance->bl; - peer_id_t id; - if (!cmp_peer_id (M->to_id, MK_USER (M->instance->our_id))) { - id = M->from_id; - } else { - id = M->to_id; - } - peer_t *P = user_chat_get (bl, id); - if (!P) { - P = talloc0 (sizeof (*P)); - P->id = id; - switch (get_peer_type (id)) { - case PEER_USER: - bl->users_allocated ++; - break; - case PEER_CHAT: - bl->chats_allocated ++; - break; - case PEER_GEO_CHAT: - bl->geo_chats_allocated ++; - break; - case PEER_ENCR_CHAT: - bl->encr_chats_allocated ++; - break; - } - bl->peer_tree = tree_insert_peer (bl->peer_tree, P, lrand48 ()); - assert (bl->peer_num < MAX_PEER_NUM); - bl->Peers[bl->peer_num ++] = P; - } - if (!P->last) { - P->last = M; - M->prev = M->next = 0; - } else { - if (get_peer_type (P->id) != PEER_ENCR_CHAT) { - struct message *N = P->last; - struct message *NP = 0; - while (N && N->id > M->id) { - NP = N; - N = N->next; - } - if (N) { assert (N->id < M->id); } - M->next = N; - M->prev = NP; - if (N) { N->prev = M; } - if (NP) { NP->next = M; } - else { P->last = M; } - } else { - struct message *N = P->last; - struct message *NP = 0; - M->next = N; - M->prev = NP; - if (N) { N->prev = M; } - if (NP) { NP->next = M; } - else { P->last = M; } - } - } -} - -void message_del_peer (struct message *M) { - peer_id_t id; - if (!cmp_peer_id (M->to_id, MK_USER (M->instance->our_id))) { - id = M->from_id; - } else { - id = M->to_id; - } - peer_t *P = user_chat_get (M->instance->bl, id); - if (M->prev) { - M->prev->next = M->next; - } - if (M->next) { - M->next->prev = M->prev; - } - if (P && P->last == M) { - P->last = M->next; - } -} - -struct message *fetch_alloc_message (struct mtproto_connection *mtp, struct telegram *instance) { - struct binlog *bl = mtp->bl; - - debug("fetch_alloc_message()\n"); - int data[2]; - prefetch_data (mtp, data, 8); - struct message *M = message_get (bl, data[1]); - - if (!M) { - M = talloc0 (sizeof (*M)); - M->instance = instance; - M->id = data[1]; - message_insert_tree (M); - mtp->bl->messages_allocated ++; - fetch_message (mtp, M); - return M; - } - fetch_message (mtp, M); - return M; -} - -struct message *fetch_alloc_geo_message (struct mtproto_connection *mtp, struct telegram *instance) { - debug("fetch_alloc_geo_message()\n"); - struct message *M = talloc (sizeof (*M)); - M->instance = instance; - fetch_geo_message (mtp, M); - struct message *M1 = tree_lookup_message (mtp->bl->message_tree, M); - mtp->bl->messages_allocated ++; - if (M1) { - message_del_use (M1); - message_del_peer (M1); - free_message (M1); - memcpy (M1, M, sizeof (*M)); - tfree (M, sizeof (*M)); - message_add_use (M1); - message_add_peer (M1); - mtp->bl->messages_allocated --; - return M1; - } else { - message_add_use (M); - message_add_peer (M); - mtp->bl->message_tree = tree_insert_message (mtp->bl->message_tree, M, lrand48 ()); - return M; - } -} - -struct message *fetch_alloc_encrypted_message (struct mtproto_connection *mtp, - struct telegram *instance) { - struct binlog *bl = mtp->bl; - debug("fetch_alloc_encrypted_message()\n"); - int data[3]; - prefetch_data (mtp, data, 12); - struct message *M = message_get (bl, *(long long *)(data + 1)); - - if (!M) { - M = talloc0 (sizeof (*M)); - M->instance = instance; - M->id = *(long long *)(data + 1); - message_insert_tree (M); - mtp->bl->messages_allocated ++; - assert (message_get (bl, M->id) == M); - debug ("id = %lld\n", M->id); - } - fetch_encrypted_message (mtp, M); - return M; -} - -struct message *fetch_alloc_message_short (struct mtproto_connection *mtp, - struct telegram *instance) { - struct binlog *bl = mtp->bl; - int data[1]; - prefetch_data (mtp, data, 4); - struct message *M = message_get (bl, data[0]); - - if (!M) { - M = talloc0 (sizeof (*M)); - M->instance = instance; - M->id = data[0]; - message_insert_tree (M); - mtp->bl->messages_allocated ++; - } - fetch_message_short (mtp, M); - return M; -} - -struct message *fetch_alloc_message_short_chat (struct mtproto_connection *mtp, struct telegram *instance) { - struct binlog *bl = mtp->bl; - int data[1]; - prefetch_data (mtp, data, 4); - struct message *M = message_get (bl, data[0]); - - if (!M) { - M = talloc0 (sizeof (*M)); - M->instance = instance; - M->id = data[0]; - message_insert_tree (M); - mtp->bl->messages_allocated ++; - } - fetch_message_short_chat (mtp, M); - return M; -} - -struct chat *fetch_alloc_chat (struct mtproto_connection *mtp) { - struct binlog *bl = mtp->bl; - debug("fetch_alloc_chat()\n"); - int data[2]; - prefetch_data (mtp, data, 8); - peer_t *U = user_chat_get (bl, MK_CHAT (data[1])); - debug("id %d\n", U->id.id); - debug("type %d\n", U->id.type); - if (!U) { - bl->chats_allocated ++; - U = talloc0 (sizeof (*U)); - U->id = MK_CHAT (data[1]); - bl->peer_tree = tree_insert_peer (bl->peer_tree, U, lrand48 ()); - assert (bl->peer_num < MAX_PEER_NUM); - bl->Peers[bl->peer_num ++] = U; - } - fetch_chat (mtp, &U->chat); - event_peer_allocated(mtp->connection->instance, U); - return &U->chat; -} - -struct chat *fetch_alloc_chat_full (struct mtproto_connection *mtp) { - struct binlog *bl = mtp->bl; - int data[3]; - prefetch_data (mtp, data, 12); - peer_t *U = user_chat_get (bl, MK_CHAT (data[2])); - if (U) { - fetch_chat_full (mtp, &U->chat); - return &U->chat; - } else { - bl->chats_allocated ++; - U = talloc0 (sizeof (*U)); - U->id = MK_CHAT (data[2]); - bl->peer_tree = tree_insert_peer (bl->peer_tree, U, lrand48 ()); - fetch_chat_full (mtp, &U->chat); - assert (bl->peer_num < MAX_PEER_NUM); - bl->Peers[bl->peer_num ++] = U; - return &U->chat; - } -} - -void free_chat (struct chat *U) { - if (U->title) { tfree_str (U->title); } - if (U->print_title) { tfree_str (U->print_title); } -} - -int print_stat (struct binlog *bl, char *s, int len) { - return tsnprintf (s, len, - "bl->users_allocated\t%d\n" - "bl->chats_allocated\t%d\n" - "secret_bl->chats_allocated\t%d\n" - "bl->peer_num\t%d\n" - "bl->messages_allocated\t%d\n", - bl->users_allocated, - bl->chats_allocated, - bl->encr_chats_allocated, - bl->peer_num, - bl->messages_allocated - ); -} - -peer_t *user_chat_get (struct binlog *bl, peer_id_t id) { - static peer_t U; - U.id = id; - return tree_lookup_peer (bl->peer_tree, &U); -} - -struct message *message_get (struct binlog *bl, long long id) { - struct message M; - M.id = id; - return tree_lookup_message (bl->message_tree, &M); -} - -void update_message_id (struct message *M, long long id) { - struct binlog *bl = M->instance->bl; - bl->message_tree = tree_delete_message (bl->message_tree, M); - M->id = id; - bl->message_tree = tree_insert_message (bl->message_tree, M, lrand48 ()); -} - -void message_insert_tree (struct message *M) { - struct binlog *bl = M->instance->bl; - assert (M->id); - bl->message_tree = tree_insert_message (bl->message_tree, M, lrand48 ()); -} - -void message_remove_tree (struct message *M) { - struct binlog *bl = M->instance->bl; - assert (M->id); - bl->message_tree = tree_delete_message (bl->message_tree, M); -} - -void message_insert (struct message *M) { - message_add_use (M); - message_add_peer (M); -} - -void message_insert_unsent (struct message *M) { - struct binlog *bl = M->instance->bl; - bl->message_unsent_tree = tree_insert_message (bl->message_unsent_tree, M, lrand48 ()); -} - -void message_remove_unsent (struct message *M) { - struct binlog *bl = M->instance->bl; - bl->message_unsent_tree = tree_delete_message (bl->message_unsent_tree, M); -} - -void __send_msg (struct message *M) { - debug ("Resending message...\n"); - //print_message (M); - - assert(M->instance); - do_send_msg (M->instance, M); -} - -void send_all_unsent (struct binlog *bl) { - tree_act_message (bl->message_unsent_tree, __send_msg); -} - -void peer_insert_name (struct binlog *bl, peer_t *P) { - //if (!P->print_name || !strlen (P->print_name)) { return; } - //debug ("+%s\n", P->print_name); - bl->peer_by_name_tree = tree_insert_peer_by_name (bl->peer_by_name_tree, P, lrand48 ()); -} - -void peer_delete_name (struct binlog *bl, peer_t *P) { - //if (!P->print_name || !strlen (P->print_name)) { return; } - //debug ("-%s\n", P->print_name); - bl->peer_by_name_tree = tree_delete_peer_by_name (bl->peer_by_name_tree, P); -} - -peer_t *peer_lookup_name (struct binlog *bl, const char *s) { - static peer_t P; - P.print_name = (void *)s; - peer_t *R = tree_lookup_peer_by_name (bl->peer_by_name_tree, &P); - return R; -} - -void free_messages (struct binlog *bl) -{ - while (bl->message_tree) { - struct message *M = tree_get_min_message (bl->message_tree); - assert (M); - debug ("freeing message: %lld\n", M->id); - bl->message_tree = tree_delete_message (bl->message_tree, M); - bl->messages_allocated --; - free_message (M); - } -} - -void free_peers (struct binlog *bl) -{ - while (bl->peer_by_name_tree) { - bl->peer_by_name_tree = tree_delete_peer_by_name (bl->peer_by_name_tree, - tree_get_min_peer_by_name(bl->peer_by_name_tree)); - } - while (bl->peer_tree) { - union peer *P = tree_get_min_peer (bl->peer_tree); - assert (P); - bl->peer_tree = tree_delete_peer (bl->peer_tree, P); - bl->peer_num --; - free (P->print_name); - tfree (P, sizeof (union peer)); - } -} - diff --git a/structures.h b/structures.h deleted file mode 100644 index cc4ce08..0000000 --- a/structures.h +++ /dev/null @@ -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 . - - 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 - -//#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 - diff --git a/telegram-base.c b/telegram-base.c new file mode 100644 index 0000000..abae430 --- /dev/null +++ b/telegram-base.c @@ -0,0 +1,372 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#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); +} + diff --git a/telegram-base.h b/telegram-base.h new file mode 100644 index 0000000..1496ba6 --- /dev/null +++ b/telegram-base.h @@ -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 diff --git a/purple-plugin/telegram-purple.c b/telegram-purple.c similarity index 57% rename from purple-plugin/telegram-purple.c rename to telegram-purple.c index 166a15e..d78dec4 100644 --- a/purple-plugin/telegram-purple.c +++ b/telegram-purple.c @@ -48,10 +48,13 @@ #include "request.h" // telegram-purple includes -#include "telegram.h" +#include #include "telegram-purple.h" -#include "structures.h" -#include "net.h" +//#include "structures.h" +#include "tgp-net.h" +#include "tgp-timers.h" +#include "msglog.h" +#include "telegram-base.h" #define CONFIG_DIR ".telegram-purple" #define BUDDYNAME_MAX_LENGTH 128 @@ -61,17 +64,11 @@ PurpleGroup *tggroup; void tgprpl_login_on_connected(); -void message_allocated_handler (struct telegram *instance, struct message *M); -void peer_allocated_handler (struct telegram *instance, void *user); -void user_info_received_handler (struct telegram *instance, struct tgl_user *user, int showInfo); -void download_finished_handler (struct telegram *instance, struct download *D); -void telegram_on_phone_registration (struct telegram *instance); -void telegram_on_client_registration (struct telegram *instance); -void on_new_user_status(struct telegram *instance, void *user); -void on_user_typing(struct telegram *instance, void *user); -void on_chat_joined (struct telegram *instance, peer_id_t chatid); static PurpleChat *blist_find_chat_by_id(PurpleConnection *gc, const char *id); -static void tgprpl_has_output(void *handle); +//static void tgprpl_has_output(void *handle); +void on_chat_get_info (struct tgl_state *TLS, void *extra, int success, struct tgl_chat *C); +void on_user_get_info (struct tgl_state *TLS, void *show_info, int success, struct tgl_user *U); +static int user_get_alias (tgl_peer_t *user, char *buffer, int maxlen); static const char *chat_id_get_comp_val (PurpleConnection *gc, int id, char *value) { @@ -82,6 +79,7 @@ static const char *chat_id_get_comp_val (PurpleConnection *gc, int id, char *val return g_hash_table_lookup(table, value); } + /** * Assure that the given chat is opened */ @@ -105,21 +103,20 @@ static PurpleConversation *chat_show (PurpleConnection *gc, int id) g_hash_table_insert(conn->joining_chats, name, 0); // join chat first - do_get_chat_info (conn->tg, MK_CHAT(id)); - telegram_flush (conn->tg); + tgl_do_get_chat_info (conn->TLS, TGL_MK_CHAT(id), 0, on_chat_get_info, NULL); } g_free(name); } return convo; } - +/* static PurpleChat *get_chat_by_id (PurpleConnection *gc, int id) { gchar *name = g_strdup_printf ("%d", id); PurpleChat *chat = blist_find_chat_by_id (gc, name); g_free (name); return chat; -} +}*/ /** * Returns the base icon name for the given buddy and account. @@ -149,13 +146,14 @@ static void tgprpl_tooltip_text(PurpleBuddy * buddy, PurpleNotifyUserInfo * info purple_debug_info(PLUGIN_ID, "tgprpl_tooltip_text()\n"); debug ("purple_buddy_get_protocol_data: %s\n", buddy->name); - peer_id_t *peer = purple_buddy_get_protocol_data(buddy); + tgl_peer_id_t *peer = purple_buddy_get_protocol_data(buddy); if(peer == NULL) { purple_notify_user_info_add_pair_plaintext(info, "Status", "Offline"); return; } - peer_t *P = user_chat_get (get_conn_from_buddy(buddy)->tg->bl, *peer); + tgl_peer_t *P = tgl_peer_get (get_conn_from_buddy(buddy)->TLS, *peer); + purple_notify_user_info_add_pair_plaintext(info, "Status", P->user.status.online == 1 ? "Online" : "Offline"); struct tm *tm = localtime ((void *)&P->user.status.when); char buffer [21]; @@ -163,350 +161,108 @@ static void tgprpl_tooltip_text(PurpleBuddy * buddy, PurpleNotifyUserInfo * info purple_notify_user_info_add_pair_plaintext(info, "Last seen: ", buffer); } - -/* OUTPUT */ - -/** - * Libpurple announced that new output should be written to the write-handle - */ -static void tgprpl_output_cb(gpointer data, gint source, PurpleInputCondition cond) -{ - mtproto_handle *conn = data; - if (!conn->mtp) { - debug ("connection no longer existing, do nothing. \n"); - return; - } - if (mtp_write_output(conn->mtp) == 0) { - debug("no output, removing output...\n"); - purple_input_remove(conn->wh); - conn->wh = 0; - } -} - -/** - * Telegram announced new output in its buffers - */ -static void tgprpl_has_output(void *handle) -{ - debug("tgprpl_has_output(%p)\n", handle); - mtproto_handle *conn = handle; - if (! conn->wh) { - conn->wh = purple_input_add(conn->fd, PURPLE_INPUT_WRITE, tgprpl_output_cb, handle); - } -} - -/* - * Libpurple announced that new input should be read from the read-handle - */ -static void tgprpl_input_cb(gpointer data, gint source, PurpleInputCondition cond) -{ - mtproto_handle *conn = data; - debug("tgprpl_input_cb()\n"); - if (!conn->fd) { - debug("conn for handle no longer existing, not reading input\n"); - return; - } - mtp_read_input(conn->mtp); - - if (conn->mtp) { - // processing of the answer may have inserted new queries - telegram_flush (conn->mtp->instance); - - // free all mtproto_connections that may have errored - mtproto_free_closed(conn->mtp->instance, 0); - } -} - -/** - * Telegram requests a new connectino to our configured proxy - */ -void telegram_on_proxy_request(struct telegram *tg, struct proxy_request *req) -{ - telegram_conn *conn = tg->extra; - req->extra = tg; - purple_proxy_connect (conn->gc, conn->pa, req->DC->ip, req->DC->port, - tgprpl_login_on_connected, req); -} - /** * Handle a proxy-close of telegram * * Remove all open inputs added to purple */ -void telegram_on_proxy_close(void *handle) -{ - mtproto_handle *conn = handle; - debug ("Closing proxy-handles - fd: %d, write-handle: %d, read-handle: %d\n", - conn->fd, conn->wh, conn->rh); - if (conn->rh) { - purple_input_remove (conn->rh); - } - if (conn->wh) { - purple_input_remove (conn->wh); - } - conn->rh = conn->wh = 0; - conn->mtp = 0; - tfree (conn, sizeof(mtproto_handle)); -} - -void phone_registration_entered (PurpleConnection* gc, PurpleRequestFields* fields) -{ - telegram_conn *conn = purple_connection_get_protocol_data(gc); - 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) { - telegram_on_phone_registration (conn->tg); - return; - } - - do_send_code_result_auth (conn->tg, code, first, last); - telegram_flush (conn->tg); -} - - -void telegram_on_phone_registration (struct telegram *instance) -{ - telegram_conn *conn = instance->extra; - - purple_debug_info(PLUGIN_ID, "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( phone_registration_entered ), "Cancel", NULL, conn->pa, NULL, NULL, conn->gc); -} - -void client_registration_entered (gpointer data, const gchar *code) -{ - struct telegram *tg = data; - do_send_code_result (tg, code); - telegram_flush (tg); -} - -void client_registration_canceled (gpointer data) -{ - struct telegram *tg = data; - telegram_conn *conn = tg->extra; - - purple_connection_error_reason(conn->gc, - PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, "registration canceled"); -} gboolean queries_timerfunc (gpointer data) { debug ("queries_timerfunc()\n"); telegram_conn *conn = data; - work_timers (conn->tg); - telegram_flush (conn->tg); if (conn->updated) { debug ("State updated, storing current session...\n"); conn->updated = 0; - telegram_store_session (conn->tg); + write_state_file (conn->TLS); } return 1; } -void telegram_on_client_registration (struct telegram *instance) -{ - purple_debug_info(PLUGIN_ID, "Client is not registered, registering...\n"); - telegram_conn *conn = instance->extra; - - 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(client_registration_entered), // ok_cb - "Cancel", // cancel_text - G_CALLBACK(client_registration_canceled), // cancel_cb - conn->pa, // account - NULL, // who - NULL, // conv - conn->tg // user_data - ); +void telegram_on_ready (struct tgl_state *TLS) { + debug ("telegram_on_ready().\n"); + telegram_conn *conn = TLS->ev_base; + purple_connection_set_state(conn->gc, PURPLE_CONNECTED); + purple_connection_set_display_name(conn->gc, purple_account_get_username(conn->pa)); + purple_blist_add_account(conn->pa); + tggroup = purple_find_group("Telegram"); + if (tggroup == NULL) { + purple_debug_info (PLUGIN_ID, "PurpleGroup = NULL, creating"); + tggroup = purple_group_new ("Telegram"); + purple_blist_add_group (tggroup, NULL); + } + + tgl_do_get_difference (TLS, 0, 0, 0); + tgl_do_get_dialog_list (TLS, 0, 0); + tgl_do_update_contact_list (TLS, 0, 0); + + conn->timer = purple_timeout_add (5000, queries_timerfunc, conn); } -void telegram_on_ready (struct telegram *instance) -{ - purple_debug_info(PLUGIN_ID, "telegram_on_ready().\n"); - telegram_conn *conn = instance->extra; - purple_connection_set_state(conn->gc, PURPLE_CONNECTED); - purple_connection_set_display_name(conn->gc, purple_account_get_username(conn->pa)); - purple_blist_add_account(conn->pa); - tggroup = purple_find_group("Telegram"); - if (tggroup == NULL) { - purple_debug_info (PLUGIN_ID, "PurpleGroup = NULL, creating"); - tggroup = purple_group_new ("Telegram"); - purple_blist_add_group (tggroup, NULL); - } - do_get_difference(instance, 0); - do_get_dialog_list(instance); - do_update_contact_list(instance); - telegram_flush (conn->tg); - conn->timer = purple_timeout_add (5000, queries_timerfunc, conn); -} - -/** - * A proxy connection was created by purple - * - * Use the connection to create a new mtproto-connection and create a handle, - * with additional info for libpurple associated with the new connection - */ -void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_message) -{ - purple_debug_info(PLUGIN_ID, "tgprpl_login_on_connected()\n"); - struct proxy_request *req = (struct proxy_request*)data; - struct telegram *tg = req->tg; - - if (fd == -1) { - failure("purple_proxy_connect failed: %s\n", error_message); - telegram_destroy(tg); - return; - } - - mtproto_handle *conn = talloc(sizeof (mtproto_handle)); - conn->fd = fd; - conn->wh = purple_input_add(fd, PURPLE_INPUT_WRITE, tgprpl_output_cb, conn); - conn->rh = purple_input_add(fd, PURPLE_INPUT_READ, tgprpl_input_cb, conn); - conn->mtp = telegram_add_proxy(tg, req, fd, conn); -} - -void telegram_on_error (struct telegram *tg, const char *err) -{ - debug ("telegram_on_error()\n"); - telegram_conn *conn = tg->extra; - - purple_connection_error_reason(conn->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, - err); -} - -void on_update_user_name (struct telegram *tg, peer_t *user) -{ - // debug("on_update_user_name(id=%d, type=%d)\n", user->id.id, user->id.type); - // Update user name -} - -void on_update_user_photo (struct telegram *tg, peer_t *user) -{ - // debug("on_update_user_photo(id=%d, type=%d)\n", user->id.id, user->id.type); - // Update user photo -} - -void on_update_user_registered (struct telegram *tg, peer_t *user) -{ - // debug("on_update_user_name(id=%d, type=%d)\n", user->id.id, user->id.type); - // Notify about a new user -} - -void on_update_chat_participants (struct telegram *tg, peer_t *chat) -{ - // debug("on_update_chat_participants(chat.id=%d)\n", chat->id.id); - // Refresh chat participants -} - -void on_update_chat_add_participant (struct telegram *tg, peer_t *chat, peer_id_t user, peer_id_t inviter) -{ - // debug("on_update_chat_add_participant(chat.id=%d)\n", chat->id.id); - // Add chat participant -} - -void on_update_chat_del_participant (struct telegram *tg, peer_t *chat, peer_id_t user, void *_ UU) -{ - // debug("on_update_chat_del_participant(chat.id=%d)\n", chat->id.id); - // Remove chat participant -} - -void on_update_chat_user_typing (struct telegram *tg, peer_t *chat, peer_t *user, void *_ UU) -{ - // debug("on_update_chat_user_typing(chat.id=%d, user.id=%d)\n", chat->id.id, user->id.id); - // Set or unset user in chat typing -} - -void on_update_auth_new (struct telegram *tg, char *location) -{ - // debug("un_update_auth_new(location=%s)\n", location); - // Info: new device authenticated for this phone number -} - -struct telegram_config tgconf = { - NULL, - tgprpl_has_output, // on output - telegram_on_proxy_request, - telegram_on_proxy_close, - telegram_on_phone_registration, - telegram_on_client_registration, - telegram_on_ready, - telegram_on_error, - - // user - peer_allocated_handler, - on_new_user_status, - on_user_typing, - on_update_user_name, - on_update_user_photo, - on_update_user_registered, - - // chat - on_update_chat_participants, - on_update_chat_add_participant, - on_update_chat_del_participant, - on_update_chat_user_typing, - - // misc - on_update_auth_new, - message_allocated_handler, - download_finished_handler, - user_info_received_handler, - on_chat_joined +static void message_received_handler (struct tgl_state *TLS, struct tgl_message *M); +static void user_update_handler (struct tgl_state *TLS, struct tgl_user *U, unsigned flags); +static void chat_update_handler (struct tgl_state *TLS, struct tgl_chat *C, unsigned flags); +void on_user_typing (struct tgl_state *TLS, struct tgl_user *U, enum tgl_typing_status status); +struct tgl_update_callback tgp_callback = { + .logprintf = debug, + .new_msg = message_received_handler, + .msg_receive = message_received_handler, + .user_update = user_update_handler, + .chat_update = chat_update_handler, + .type_notification = on_user_typing }; - /** * This must be implemented. */ static void tgprpl_login(PurpleAccount * acct) { - purple_debug_info(PLUGIN_ID, "tgprpl_login()\n"); + purple_debug_info (PLUGIN_ID, "tgprpl_login()\n"); PurpleConnection *gc = purple_account_get_connection(acct); char const *username = purple_account_get_username(acct); - // create a new instance of telegram - struct telegram *tg = telegram_new (username, &tgconf); - telegram_restore_session(tg); + struct tgl_state *TLS = tgl_state_alloc (); + + const char *dir = CONFIG_DIR; + struct passwd *pw = getpwuid(getuid()); + int len = strlen (dir) + strlen (pw->pw_dir) + 2 + strlen (username); + TLS->base_path = malloc (len); + snprintf (TLS->base_path, len, "%s/%s/%s", pw->pw_dir, dir, username); + debug ("base configuration path: '%s'", TLS->base_path); + g_mkdir_with_parents(TLS->base_path, 0700); + + len += strlen ("/downloads"); + char *ddir = malloc (len); + sprintf (ddir, "%s/downloads", TLS->base_path); + tgl_set_download_directory (TLS, ddir); + g_mkdir_with_parents(ddir, 0700); + free (ddir); + + tgl_set_verbosity (TLS, 4); + tgl_set_rsa_key (TLS, "/etc/telegram-purple/server.pub"); + + // create handle to store additional info for libpurple in // the new telegram instance telegram_conn *conn = g_new0(telegram_conn, 1); - conn->tg = tg; + conn->TLS = TLS; conn->gc = gc; conn->pa = acct; conn->new_messages = g_queue_new(); - conn->joining_chats = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - purple_connection_set_protocol_data(gc, conn); + purple_connection_set_protocol_data (gc, conn); + + tgl_set_ev_base (TLS, conn); + tgl_set_net_methods (TLS, &tgp_conn_methods); + tgl_set_timer_methods (TLS, &tgp_timers); + tgl_set_callback (TLS, &tgp_callback); - tg->extra = conn; + tgl_init (TLS); purple_connection_set_state (conn->gc, PURPLE_CONNECTING); - telegram_connect (tg); + + + telegram_login (TLS); } /** @@ -517,23 +273,23 @@ static void tgprpl_close(PurpleConnection * gc) purple_debug_info(PLUGIN_ID, "tgprpl_close()\n"); telegram_conn *conn = purple_connection_get_protocol_data(gc); purple_timeout_remove(conn->timer); - telegram_destroy(conn->tg); + tgl_free_all (conn->TLS); } -static int chat_add_message(struct telegram *tg, struct message *M) +static int chat_add_message(struct tgl_state *TLS, struct tgl_message *M) { - telegram_conn *conn = tg->extra; + telegram_conn *conn = TLS->ev_base; if (chat_show (conn->gc, M->to_id.id)) { // chat initialies, add message now - if (M->from_id.id == tg->our_id) { - serv_got_chat_in(conn->gc, get_peer_id(M->to_id), "You", + if (tgl_get_peer_id (M->from_id) == TLS->our_id) { + serv_got_chat_in(conn->gc, tgl_get_peer_id (M->to_id), "You", PURPLE_MESSAGE_RECV, M->message, M->date); } else { - peer_t *fromPeer = user_chat_get (tg->bl, M->from_id); + tgl_peer_t *fromPeer = tgl_peer_get (TLS, M->from_id); char *alias = malloc(BUDDYNAME_MAX_LENGTH); - user_get_alias(fromPeer, alias, BUDDYNAME_MAX_LENGTH); - serv_got_chat_in(conn->gc, get_peer_id(M->to_id), alias, + user_get_alias (fromPeer, alias, BUDDYNAME_MAX_LENGTH); + serv_got_chat_in (conn->gc, tgl_get_peer_id (M->to_id), alias, PURPLE_MESSAGE_RECV, M->message, M->date); g_free(alias); } @@ -545,10 +301,10 @@ static int chat_add_message(struct telegram *tg, struct message *M) } } -void message_allocated_handler(struct telegram *tg, struct message *M) +void message_received_handler(struct tgl_state *TLS, struct tgl_message *M) { debug ("message_allocated_handler\n"); - telegram_conn *conn = tg->extra; + telegram_conn *conn = TLS->ev_base; PurpleConnection *gc = conn->gc; if (M->service || (M->flags & (FLAG_MESSAGE_EMPTY | FLAG_DELETED))) { @@ -558,40 +314,40 @@ void message_allocated_handler(struct telegram *tg, struct message *M) return; } - int id = get_peer_id(M->from_id); - peer_id_t to_id = M->to_id; + int id = tgl_get_peer_id (M->from_id); + tgl_peer_id_t to_id = M->to_id; char *from = g_strdup_printf("%d", id); char *to = g_strdup_printf("%d", to_id.id); - switch (to_id.type) { - case PEER_CHAT: + switch (tgl_get_peer_type (to_id)) { + case TGL_PEER_CHAT: debug ("PEER_CHAT\n"); - chat_add_message(tg, M); + chat_add_message (TLS, M); break; - case PEER_USER: + case TGL_PEER_USER: debug ("PEER_USER\n"); - if (M->from_id.id == tg->our_id) { + if (tgl_get_peer_id (M->from_id) == TLS->our_id) { serv_got_im(gc, to, M->message, PURPLE_MESSAGE_SEND, M->date); } else { serv_got_im(gc, from, M->message, PURPLE_MESSAGE_RECV, M->date); } break; - case PEER_ENCR_CHAT: + case TGL_PEER_ENCR_CHAT: break; - case PEER_GEO_CHAT: + case TGL_PEER_GEO_CHAT: break; } g_free(from); conn->updated = 1; } -void on_new_user_status(struct telegram *tg, void *peer) +void on_new_user_status (struct tgl_state *TLS, void *peer) { - telegram_conn *conn = tg->extra; - peer_t *p = peer; - char *who = g_strdup_printf("%d", get_peer_id(p->user.id)); + telegram_conn *conn = TLS->ev_base; + tgl_peer_t *p = peer; + char *who = g_strdup_printf("%d", tgl_get_peer_id (p->user.id)); PurpleAccount *account = purple_connection_get_account(conn->gc); if (p->user.status.online == 1) purple_prpl_got_user_status(account, who, "available", "message", "", NULL); @@ -600,12 +356,11 @@ void on_new_user_status(struct telegram *tg, void *peer) g_free(who); } -void on_user_typing(struct telegram *tg, void *peer) +void on_user_typing (struct tgl_state *TLS, struct tgl_user *U, enum tgl_typing_status status) { - telegram_conn *conn = tg->extra; - peer_t *p = peer; + telegram_conn *conn = TLS->ev_base; - char *who = g_strdup_printf("%d", get_peer_id(p->user.id)); + char *who = g_strdup_printf("%d", tgl_get_peer_id (U->id)); serv_got_typing(conn->gc, who, 2, PURPLE_TYPING); g_free(who); } @@ -642,98 +397,120 @@ static PurpleChat *blist_find_chat_by_id(PurpleConnection *gc, const char *id) return blist_find_chat_by_hasht_cond(gc, hasht_cmp_id, &id); } -static char *peer_get_peer_id_as_string(peer_t *user) +static char *peer_get_peer_id_as_string(tgl_peer_t *user) { - return g_strdup_printf("%d", get_peer_id(user->id)); + return g_strdup_printf("%d", tgl_get_peer_id (user->id)); } -void peer_allocated_handler(struct telegram *tg, void *usr) + +static void sanitize_alias(char *buffer) { - telegram_conn *conn = tg->extra; + size_t len = strlen(buffer); + gchar *curr; + while ((curr = g_utf8_strchr(buffer, len, '\n'))) { + *curr = 0x20; + } +} + +static int user_get_alias (tgl_peer_t *user, char *buffer, int maxlen) +{ + char* last_name = (user->user.last_name && strlen(user->user.last_name)) ? user->user.last_name : ""; + char* first_name = (user->user.first_name && strlen(user->user.first_name)) ? user->user.first_name : ""; + sanitize_alias (last_name); + sanitize_alias (first_name); + if (strlen(first_name) && strlen(last_name)) { + return snprintf(buffer, maxlen, "%s %s", first_name, last_name); + } else if (strlen(first_name)) { + return snprintf(buffer, maxlen, "%s", first_name); + } else if (strlen(last_name)) { + return snprintf(buffer, maxlen, "%s", last_name); + } else { + return snprintf(buffer, maxlen, "%d", tgl_get_peer_id (user->id)); + } +} + +void user_update_handler (struct tgl_state *TLS, struct tgl_user *user, unsigned flags) +{ + if (!(flags & FLAG_CREATED)) { return; } + + telegram_conn *conn = TLS->ev_base; PurpleConnection *gc = conn->gc; PurpleAccount *pa = conn->pa; - peer_t *user = usr; - gchar *name = peer_get_peer_id_as_string(user); //g_strdup_printf("%d", get_peer_id(user->id)); - debug("Allocated peer: %s\n", name); - switch (user->id.type) { - case PEER_USER: { - debug("Peer type: user.\n"); - // TODO: this should probably be freed again somwhere - char *alias = malloc(BUDDYNAME_MAX_LENGTH); - if (user_get_alias(user, alias, BUDDYNAME_MAX_LENGTH) < 0) { - purple_debug_info(PLUGIN_ID, "Buddyalias of (%d) too long, not adding to buddy list.\n", - get_peer_id(user->id)); - return; - } - PurpleBuddy *buddy = purple_find_buddy(pa, name); - if (!buddy) { - char *actual = user->id.id == tg->our_id ? "You" : alias; - purple_debug_info(PLUGIN_ID, "Adding %s to buddy list\n", name); - purple_debug_info(PLUGIN_ID, "Alias %s\n", actual); - buddy = purple_buddy_new(pa, name, actual); - purple_blist_add_buddy(buddy, NULL, tggroup, NULL); - do_get_user_info(conn->tg, user->id, 0); - } - purple_buddy_set_protocol_data(buddy, (gpointer)&user->id); - - PurpleAccount *account = purple_connection_get_account(gc); - if (user->user.status.online == 1) - purple_prpl_got_user_status(account, name, "available", "message", "", NULL); - else - purple_prpl_got_user_status(account, name, "mobile", "message", "", NULL); - - g_free(alias); - g_free(name); - } - break; - case PEER_CHAT: { - debug("Peer type: chat.\n"); - PurpleChat *ch = blist_find_chat_by_id(gc, name); - if (!ch) { - gchar *admin = g_strdup_printf("%d", user->chat.admin_id); - GHashTable *htable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - g_hash_table_insert(htable, g_strdup("subject"), user->chat.title); - g_hash_table_insert(htable, g_strdup("id"), name); - g_hash_table_insert(htable, g_strdup("owner"), admin); - debug("Adding chat to blist: %s (%s, %s)\n", user->chat.title, name, admin); - ch = purple_chat_new(pa, user->chat.title, htable); - purple_blist_add_chat(ch, NULL, NULL); - } - - GHashTable *gh = purple_chat_get_components(ch); - //char const *id = g_hash_table_lookup(gh, "id"); - char const *owner = g_hash_table_lookup(gh, "owner"); - - PurpleConversation *conv = purple_find_chat(gc, atoi(name)); + gchar *name = peer_get_peer_id_as_string ((tgl_peer_t *)user); //g_strdup_printf("%d", get_peer_id(user->id)); + debug("Allocated user: %s\n", name); + // TODO: this should probably be freed again somwhere + char *alias = malloc(BUDDYNAME_MAX_LENGTH); + if (user_get_alias((tgl_peer_t *)user, alias, BUDDYNAME_MAX_LENGTH) < 0) { + purple_debug_info(PLUGIN_ID, "Buddyalias of (%d) too long, not adding to buddy list.\n", + tgl_get_peer_id(user->id)); + return; + } + PurpleBuddy *buddy = purple_find_buddy(pa, name); + if (!buddy) { + char *actual = tgl_get_peer_id (user->id) == TLS->our_id ? "You" : alias; + purple_debug_info(PLUGIN_ID, "Adding %s to buddy list\n", name); + purple_debug_info(PLUGIN_ID, "Alias %s\n", actual); + buddy = purple_buddy_new(pa, name, actual); + purple_blist_add_buddy(buddy, NULL, tggroup, NULL); + tgl_do_get_user_info (TLS, user->id, 0, on_user_get_info, 0); + } + purple_buddy_set_protocol_data(buddy, (gpointer)&user->id); - purple_conv_chat_clear_users(purple_conversation_get_chat_data(conv)); - if (conv) { - struct chat_user *usr = user->chat.user_list; - int size = user->chat.user_list_size; - int i; - for (i = 0; i < size; i++) { - struct chat_user *cu = (usr + i); - // TODO: Inviter ID - // peer_id_t u = MK_USER (cu->user_id); - // peer_t *uchat = user_chat_get(u); - const char *cuname = g_strdup_printf("%d", cu->user_id); - debug("Adding user %s to chat %s\n", cuname, name); - purple_conv_chat_add_user(purple_conversation_get_chat_data(conv), cuname, "", - PURPLE_CBFLAGS_NONE | (!strcmp(owner, cuname) ? PURPLE_CBFLAGS_FOUNDER : 0), 0); - } - } - } - break; - case PEER_GEO_CHAT: - debug("Peer type: geo-chat.\n"); - break; - case PEER_ENCR_CHAT: - debug("Peer type: encrypted chat.\n"); - break; - case PEER_UNKNOWN: - debug("Peer type: unknown.\n"); - break; + PurpleAccount *account = purple_connection_get_account(gc); + if (user->status.online == 1) + purple_prpl_got_user_status(account, name, "available", "message", "", NULL); + else + purple_prpl_got_user_status(account, name, "mobile", "message", "", NULL); + + g_free(alias); + g_free(name); +} + +void chat_update_handler (struct tgl_state *TLS, struct tgl_chat *chat, unsigned flags) +{ + if (!(flags & FLAG_CREATED)) { return; } + tgl_do_get_chat_info (TLS, chat->id, 0, on_chat_get_info, 0); + + telegram_conn *conn = TLS->ev_base; + PurpleConnection *gc = conn->gc; + PurpleAccount *pa = conn->pa; + + gchar *name = peer_get_peer_id_as_string ((tgl_peer_t *)chat); //g_strdup_printf("%d", get_peer_id(user->id)); + debug("Allocated chat: %s\n", name); + PurpleChat *ch = blist_find_chat_by_id(gc, name); + if (!ch) { + gchar *admin = g_strdup_printf("%d", chat->admin_id); + GHashTable *htable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + g_hash_table_insert(htable, g_strdup("subject"), chat->title); + g_hash_table_insert(htable, g_strdup("id"), name); + g_hash_table_insert(htable, g_strdup("owner"), admin); + debug("Adding chat to blist: %s (%s, %s)\n", chat->title, name, admin); + ch = purple_chat_new(pa, chat->title, htable); + purple_blist_add_chat(ch, NULL, NULL); + } + + GHashTable *gh = purple_chat_get_components(ch); + //char const *id = g_hash_table_lookup(gh, "id"); + char const *owner = g_hash_table_lookup(gh, "owner"); + + PurpleConversation *conv = purple_find_chat(gc, atoi(name)); + + purple_conv_chat_clear_users(purple_conversation_get_chat_data(conv)); + if (conv) { + struct tgl_chat_user *usr = chat->user_list; + int size = chat->user_list_size; + int i; + for (i = 0; i < size; i++) { + struct tgl_chat_user *cu = (usr + i); + // TODO: Inviter ID + // tgl_peer_id_t u = MK_USER (cu->user_id); + // tgl_peer_t *uchat = user_chat_get(u); + const char *cuname = g_strdup_printf("%d", cu->user_id); + debug("Adding user %s to chat %s\n", cuname, name); + purple_conv_chat_add_user(purple_conversation_get_chat_data(conv), cuname, "", + PURPLE_CBFLAGS_NONE | (!strcmp(owner, cuname) ? PURPLE_CBFLAGS_FOUNDER : 0), 0); + } } } @@ -747,54 +524,52 @@ PurpleNotifyUserInfo *create_user_notify_info(struct tgl_user *usr) return info; } -void user_info_received_handler(struct telegram *tg, struct tgl_user *usr, int show_info) +void on_userpic_loaded (struct tgl_state *TLS, void *extra, int success, char *filename) { + telegram_conn *conn = TLS->ev_base; + + gchar *data = NULL; + size_t len; + GError *err = NULL; + g_file_get_contents (filename, &data, &len, &err); + int imgStoreId = purple_imgstore_add_with_id (g_memdup(data, len), len, NULL); + debug("Imagestore id: %d\n", imgStoreId); + //Create user info + struct download_desc *dld = extra; + struct tgl_user *U = dld->data; + + char *who = g_strdup_printf("%d", tgl_get_peer_id (U->id)); + + if(dld->type == 1) + { + PurpleNotifyUserInfo *info = create_user_notify_info(U); + char *profile_image = profile_image = g_strdup_printf("
", imgStoreId); + purple_notify_user_info_add_pair(info, "Profile image", profile_image); + purple_notify_userinfo(conn->gc, who, info, NULL, NULL); + g_free(profile_image); + } + purple_buddy_icons_set_for_user(conn->pa, who, g_memdup(data, len), len, NULL); + g_free(who); +} + +void on_user_get_info (struct tgl_state *TLS, void *show_info, int success, struct tgl_user *U) { + assert (success); debug("Get user info. \n %d", show_info); - char *who = g_strdup_printf("%d", usr->id.id); - if (usr->photo.sizes_num == 0 && show_info) + char *who = g_strdup_printf("%d", tgl_get_peer_id (U->id)); + if (U->photo.sizes_num == 0 && show_info) { - telegram_conn *conn = tg->extra; - PurpleNotifyUserInfo *info = create_user_notify_info(usr); + telegram_conn *conn = TLS->ev_base; + PurpleNotifyUserInfo *info = create_user_notify_info(U); purple_notify_userinfo(conn->gc, who, info, NULL, NULL); } else { - struct download_desc *dld = talloc(sizeof(struct download_desc)); - dld->data = usr; - dld->type = show_info == 1 ? 1 : 2; - do_load_photo(tg, &usr->photo, 0, dld); + struct download_desc *dld = malloc (sizeof(struct download_desc)); + dld->data = U; + dld->type = show_info ? 1 : 2; + tgl_do_load_photo (TLS, &U->photo, on_userpic_loaded, dld); } g_free(who); } - -void download_finished_handler(struct telegram *tg, struct download *D) -{ - debug("download_finished_handler %s type %d\n", D->name, D->type); - //TODO: We need a type for user-photos! - if(D->type == 0) - { - struct download_desc *dl_desc = D->extra; - struct tgl_user *usr = dl_desc->data; - gchar *data = NULL; - size_t len; - GError *err = NULL; - g_file_get_contents(D->name, &data, &len, &err); - int imgStoreId = purple_imgstore_add_with_id(g_memdup(data, len), len, NULL); - debug("Imagestore id: %d\n", imgStoreId); - //Create user info - char *who = g_strdup_printf("%d", usr->id.id); - telegram_conn *conn = tg->extra; - if(dl_desc->type == 1) - { - PurpleNotifyUserInfo *info = create_user_notify_info(usr); - char *profile_image = profile_image = g_strdup_printf("
", imgStoreId); - purple_notify_user_info_add_pair(info, "Profile image", profile_image); - purple_notify_userinfo(conn->gc, who, info, NULL, NULL); - g_free(profile_image); - } - purple_buddy_icons_set_for_user(conn->pa, who, g_memdup(data, len), len, NULL); - g_free(who); - } -} /** * This PRPL function should return a positive value on success. * If the message is too big to be sent, return -E2BIG. If @@ -811,9 +586,9 @@ static int tgprpl_send_im(PurpleConnection * gc, const char *who, const char *me purple_debug_info (PLUGIN_ID, "tgprpl_send_im()\n"); PurpleBuddy *b = purple_find_buddy (pa, who); - peer_id_t *peer = purple_buddy_get_protocol_data (b); - do_send_message (conn->tg, *peer, message, strlen(message)); - telegram_flush (conn->tg); + tgl_peer_id_t *peer = purple_buddy_get_protocol_data (b); + + tgl_do_send_message (conn->TLS, *peer, message, strlen (message), 0, 0); return 1; } @@ -838,11 +613,11 @@ static int tgprpl_send_chat(PurpleConnection * gc, int id, const char *message, purple_debug_info(PLUGIN_ID, "tgprpl_send_chat()\n"); telegram_conn *conn = purple_connection_get_protocol_data (gc); //PurpleConversation *convo = purple_find_chat(gc, id); - do_send_message (conn->tg, MK_CHAT(id), message, strlen(message)); + tgl_do_send_message (conn->TLS, TGL_MK_CHAT(id), message, strlen(message), 0, 0); - char *who = g_strdup_printf("%d", id); - serv_got_chat_in(gc, id, "You", PURPLE_MESSAGE_RECV, message, time(NULL)); - g_free(who); + //char *who = g_strdup_printf("%d", id); + //serv_got_chat_in(gc, id, "You", PURPLE_MESSAGE_RECV, message, time(NULL)); + //g_free(who); return 1; } @@ -906,14 +681,14 @@ static void tgprpl_rem_deny(PurpleConnection * gc, const char *name) static unsigned int tgprpl_send_typing(PurpleConnection * gc, const char *who, PurpleTypingState typing) { purple_debug_info(PLUGIN_ID, "tgprpl_send_typing()\n"); - telegram_conn *conn = purple_connection_get_protocol_data(gc); + /*telegram_conn *conn = purple_connection_get_protocol_data(gc); PurpleBuddy *b = purple_find_buddy(conn->pa, who); if (b) { - peer_id_t *peer = purple_buddy_get_protocol_data(b); + tgl_peer_id_t *peer = purple_buddy_get_protocol_data(b); if (peer) { - do_update_typing (conn->tg, *peer); + tgl_do_update_typing (conn->tg, *peer); } - } + }*/ return 0; } @@ -987,8 +762,8 @@ static void tgprpl_get_info(PurpleConnection * gc, const char *username) purple_debug_info(PLUGIN_ID, "tgprpl_get_info()\n"); telegram_conn *conn = purple_connection_get_protocol_data(gc); - peer_id_t u = MK_USER(atoi(username)); - do_get_user_info(conn->tg, u, 1); + tgl_peer_id_t u = TGL_MK_USER(atoi(username)); + tgl_do_get_user_info (conn->TLS, u, 0, on_user_get_info, (void *)1l); purple_debug_info(PLUGIN_ID, "tgprpl_get_info ready()\n"); //fetch_alloc_user_full(tg->connection); //fetch_user_full(tg->connection, user); @@ -1072,37 +847,27 @@ static void tgprpl_chat_join(PurpleConnection * gc, GHashTable * data) } if (!purple_find_chat(gc, atoi(id))) { debug ("chat now known\n"); - char *subject, *owner, *part; - do_get_chat_info (conn->tg, MK_CHAT(atoi(id))); - telegram_flush (conn->tg); + //char *subject, *owner, *part; + tgl_do_get_chat_info (conn->TLS, TGL_MK_CHAT(atoi(id)), 0, on_chat_get_info, 0); } else { debug ("chat already known\n"); serv_got_joined_chat(conn->gc, atoi(id), groupname); } } -void on_chat_joined (struct telegram *instance, peer_id_t chatid) -{ - debug ("on_chat_joined(%d)\n", chatid.id); - telegram_conn *conn = instance->extra; - - peer_t *peer = user_chat_get (instance->bl, chatid); - if (!peer) { - warning ("WARNING: chat with given id %d is not existing.\n", chatid.id); - return; - } - if (!peer->id.type == PEER_CHAT) { - warning ("WARNING: peer with given id %d and type %d is not a chat.\n", peer->id.id, peer->id.type); - return; - } - PurpleConversation *conv = serv_got_joined_chat(conn->gc, chatid.id, peer->chat.title); - int cnt = peer->chat.user_list_size; - struct chat_user *curr = peer->chat.user_list; +void on_chat_get_info (struct tgl_state *TLS, void *extra, int success, struct tgl_chat *C) { + assert (success); + debug ("on_chat_joined(%d)\n", tgl_get_peer_id (C->id)); + telegram_conn *conn = TLS->ev_base; + + PurpleConversation *conv = serv_got_joined_chat(conn->gc, tgl_get_peer_id (C->id), C->title); + int cnt = C->user_list_size; + struct tgl_chat_user *curr = C->user_list; int i; for (i = 0; i < cnt; i++) { - peer_id_t part_id = MK_USER((curr + i)->user_id); + tgl_peer_id_t part_id = TGL_MK_USER((curr + i)->user_id); char *name = g_strdup_printf ("%d", part_id.id); - int flags = PURPLE_CBFLAGS_NONE | ((peer->chat.admin_id == part_id.id) ? PURPLE_CBFLAGS_FOUNDER : 0); + int flags = PURPLE_CBFLAGS_NONE | ((C->admin_id == tgl_get_peer_id (part_id)) ? PURPLE_CBFLAGS_FOUNDER : 0); debug ("purple_conv_chat_add_user (..., name=%s, ..., flags=%d)", name, flags); purple_conv_chat_add_user( purple_conversation_get_chat_data(conv), @@ -1114,18 +879,18 @@ void on_chat_joined (struct telegram *instance, peer_id_t chatid) } debug ("g_queue_pop_head()\n"); - struct message *M = 0; + struct tgl_message *M = 0; while ((M = g_queue_pop_head (conn->new_messages))) { debug ("adding msg-id\n"); - int id = get_peer_id(M->from_id); - if (!chat_add_message(instance, M)) { + //int id = tgl_get_peer_id (M->from_id); + if (!chat_add_message(TLS, M)) { // chat still not working? - warning ("WARNING, chat %d still not existing... \n", chatid.id); + warning ("WARNING, chat %d still not existing... \n", tgl_get_peer_id (C->id)); break; } } - gchar *name = g_strdup_printf ("%d", chatid.id); + gchar *name = g_strdup_printf ("%d", tgl_get_peer_id (C->id)); g_hash_table_remove (conn->joining_chats, name); g_free (name); } @@ -1258,14 +1023,6 @@ static PurplePluginProtocolInfo prpl_info = { static void tgprpl_init(PurplePlugin *plugin) { - const char *dir = CONFIG_DIR; - if (!tgconf.base_config_path) { - struct passwd *pw = getpwuid(getuid()); - int len = strlen (dir) + strlen (pw->pw_dir) + 2; - tgconf.base_config_path = talloc (len); - tsnprintf (tgconf.base_config_path, len, "%s/%s", pw->pw_dir, dir); - debug ("base configuration path: %s", tgconf.base_config_path); - } PurpleAccountOption *option; GList *verification_values = NULL; diff --git a/purple-plugin/telegram-purple.h b/telegram-purple.h similarity index 58% rename from purple-plugin/telegram-purple.h rename to telegram-purple.h index bc4cd7b..6c12a8d 100644 --- a/purple-plugin/telegram-purple.h +++ b/telegram-purple.h @@ -26,62 +26,45 @@ #define TG_BUILD "8" #include -#include "notify.h" -#include "plugin.h" -#include "version.h" -#include "account.h" -#include "connection.h" -#include "mtproto-client.h" +#include +#include +#include +#include +#include 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 diff --git a/telegram.c b/telegram.c deleted file mode 100755 index 0bd80d3..0000000 --- a/telegram.c +++ /dev/null @@ -1,480 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#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 = ""; - } - 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); - } - } -} - diff --git a/telegram.h b/telegram.h deleted file mode 100644 index eebf435..0000000 --- a/telegram.h +++ /dev/null @@ -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 -#include "glib.h" -#include "loop.h" -#include "tree.h" -#include "queries.h" -#include - -// 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 diff --git a/tg-server.pub b/tg-server.pub index 4e006b4..5e38bb0 100644 --- a/tg-server.pub +++ b/tg-server.pub @@ -6,4 +6,3 @@ Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+ 8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB -----END RSA PUBLIC KEY----- - diff --git a/tgp-net.c b/tgp-net.c new file mode 100644 index 0000000..92a9614 --- /dev/null +++ b/tgp-net.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tgp-net.h" +//#include "include.h" +#include +#include +//#include "mtproto-client.h" +//#include "mtproto-common.h" +//#include "tree.h" +//#include "tools.h" + +#include +#include + +#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 +}; diff --git a/tgp-net.h b/tgp-net.h new file mode 100644 index 0000000..258a045 --- /dev/null +++ b/tgp-net.h @@ -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 diff --git a/tgp-timers.c b/tgp-timers.c new file mode 100644 index 0000000..eec0456 --- /dev/null +++ b/tgp-timers.c @@ -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 +#include +#include +#include + +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 +}; diff --git a/tgp-timers.h b/tgp-timers.h new file mode 100644 index 0000000..6791ec1 --- /dev/null +++ b/tgp-timers.h @@ -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 diff --git a/tools.c b/tools.c deleted file mode 100644 index 130c3cb..0000000 --- a/tools.c +++ /dev/null @@ -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 . - - Copyright Vitaly Valtman 2013 -*/ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include - -#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 diff --git a/tools.h b/tools.h deleted file mode 100644 index 3f3eca2..0000000 --- a/tools.h +++ /dev/null @@ -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 . - - 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 diff --git a/tree.h b/tree.h deleted file mode 100644 index fd79b75..0000000 --- a/tree.h +++ /dev/null @@ -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 . - - Copyright Vitaly Valtman 2013 -*/ -#ifndef __TREE_H__ -#define __TREE_H__ -#include - -#include -#include -#include - -#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