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