├── .gitignore ├── .gitmodules ├── .travis.yml ├── CHANGELOG ├── LICENSE ├── LICENSE.h ├── Makefile.in ├── Makefile.tgl ├── Makefile.tl-parser ├── README-Cygwin.md ├── README-LUA ├── README-PY.md ├── README.es ├── README.md ├── ax_lua.m4 ├── ax_python.m4 ├── bootstrap ├── config.h.in ├── config.sample ├── configure ├── configure.ac ├── debian ├── changelog ├── clean ├── compat ├── control ├── copyright ├── docs ├── install ├── rules ├── source │ └── format ├── telegram-cli.8 ├── telegram-cli.logrotate ├── telegram-cli.manpages ├── telegram-cli.postinst.debhelper ├── telegram-cli.preinst ├── telegram-cli.preinst.debhelper ├── telegram-cli.prerm ├── telegram-cli.prerm.debhelper ├── telegram-cli.upstart └── watch ├── event-old.h ├── gentoo └── net-im │ └── telegram-cli │ ├── Manifest │ └── telegram-cli-9999.ebuild ├── interface.c ├── interface.h ├── json-tg.c ├── json-tg.h ├── loop.c ├── loop.h ├── lua-tg.c ├── lua-tg.h ├── m4-ax_gcc_builtin.m4 ├── m4_ax_check_openssl.m4 ├── m4_ax_check_zlib.m4 ├── main.c ├── mime.types ├── python-tg.c ├── python-tg.h ├── python-types.c ├── python-types.h ├── rpm └── telegram-cli-Beta-2.fc20.x86_64.rpm ├── server.pub ├── start-telegram-daemon ├── telegram-cli-cygwin.patch ├── telegram-cli.spec ├── telegram-daemon ├── telegram.h ├── test.lua ├── tg-server.pub └── tg-test.py /.gitignore: -------------------------------------------------------------------------------- 1 | telegram 2 | *.o 3 | Makefile 4 | aclocal.m4 5 | autom4te.cache 6 | config.h 7 | config.log 8 | config.status 9 | .idea/ 10 | nbproject/ 11 | bin/ 12 | objs/ 13 | dep/ 14 | auto/ 15 | libs/ 16 | debian/telegram-cli.[a-z] 17 | debian/files 18 | debian/telegram-cli/* 19 | debian/telegram-cli.debhelper.log 20 | debian/telegram-cli.substvars 21 | __pycache__ 22 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tgl"] 2 | path = tgl 3 | url = https://github.com/vysheng/tgl.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | compiler: 4 | - gcc 5 | - clang 6 | 7 | install: 8 | - sudo apt-get update 9 | - sudo apt-get install libconfig8-dev 10 | - sudo apt-get install libreadline6-dev 11 | - sudo apt-get install libssl-dev 12 | - sudo apt-get install liblua5.2-dev lua5.2 13 | - sudo apt-get install python-dev python 14 | - sudo apt-get install libevent-dev 15 | - sudo apt-get install libjansson-dev 16 | 17 | script: 18 | - git submodule update --init --recursive 19 | - ./configure 20 | - make 21 | 22 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | 1.3.3 2 | * support for sending custom keyboard 3 | * fixed contact_search 4 | * TGL-2.0.3 5 | 1.3.2 6 | * use TGL-2.0.2 7 | * add block/unblock user methods 8 | * support for autocomplete for bot's commands 9 | 1.3.1 10 | * added error codes 11 | 1.3.0 12 | * layer 28 support (passwords, replies, webpages, other changes) 13 | * output in json format 14 | * support for lua functions in CLI mode (register_interface_function) 15 | * bugfixes 16 | * output error codes to socket 17 | * allow [reply=], [disable_preview] and [enable_preview] prefixes to query 18 | 1.2.1 19 | * fixed registration/login problem 20 | * added extension to downloads 21 | 1.2.0 22 | * layer 22 support 23 | * new authorization code 24 | * fixed time-related problems 25 | * fixed crash after hibernation 26 | 1.0.6 27 | * layer 18 support 28 | 1.0.5 29 | * listening socket (tcp and unix) for commands 30 | 1.0.4 31 | * changed create_group_chat format 32 | * changed search query 33 | * rewritten interface code. Support for escaped characters in quotes 34 | 1.0.3 35 | * options to help to run telegram-cli as daemon 36 | 1.0.2 37 | * Bug fixes 38 | 1.0.1 39 | * Added pfs support. To use it you should add 'pfs_enabled=true' line to config. 40 | * Added export_card/import_card methods 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /LICENSE.h: -------------------------------------------------------------------------------- 1 | " GNU GENERAL PUBLIC LICENSE\n" 2 | " Version 2, June 1991\n" 3 | "\n" 4 | " Copyright (C) 1989, 1991 Free Software Foundation, Inc.,\n" 5 | " 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" 6 | " Everyone is permitted to copy and distribute verbatim copies\n" 7 | " of this license document, but changing it is not allowed.\n" 8 | "\n" 9 | " Preamble\n" 10 | "\n" 11 | " The licenses for most software are designed to take away your\n" 12 | "freedom to share and change it. By contrast, the GNU General Public\n" 13 | "License is intended to guarantee your freedom to share and change free\n" 14 | "software--to make sure the software is free for all its users. This\n" 15 | "General Public License applies to most of the Free Software\n" 16 | "Foundation's software and to any other program whose authors commit to\n" 17 | "using it. (Some other Free Software Foundation software is covered by\n" 18 | "the GNU Lesser General Public License instead.) You can apply it to\n" 19 | "your programs, too.\n" 20 | "\n" 21 | " When we speak of free software, we are referring to freedom, not\n" 22 | "price. Our General Public Licenses are designed to make sure that you\n" 23 | "have the freedom to distribute copies of free software (and charge for\n" 24 | "this service if you wish), that you receive source code or can get it\n" 25 | "if you want it, that you can change the software or use pieces of it\n" 26 | "in new free programs; and that you know you can do these things.\n" 27 | "\n" 28 | " To protect your rights, we need to make restrictions that forbid\n" 29 | "anyone to deny you these rights or to ask you to surrender the rights.\n" 30 | "These restrictions translate to certain responsibilities for you if you\n" 31 | "distribute copies of the software, or if you modify it.\n" 32 | "\n" 33 | " For example, if you distribute copies of such a program, whether\n" 34 | "gratis or for a fee, you must give the recipients all the rights that\n" 35 | "you have. You must make sure that they, too, receive or can get the\n" 36 | "source code. And you must show them these terms so they know their\n" 37 | "rights.\n" 38 | "\n" 39 | " We protect your rights with two steps: (1) copyright the software, and\n" 40 | "(2) offer you this license which gives you legal permission to copy,\n" 41 | "distribute and/or modify the software.\n" 42 | "\n" 43 | " Also, for each author's protection and ours, we want to make certain\n" 44 | "that everyone understands that there is no warranty for this free\n" 45 | "software. If the software is modified by someone else and passed on, we\n" 46 | "want its recipients to know that what they have is not the original, so\n" 47 | "that any problems introduced by others will not reflect on the original\n" 48 | "authors' reputations.\n" 49 | "\n" 50 | " Finally, any free program is threatened constantly by software\n" 51 | "patents. We wish to avoid the danger that redistributors of a free\n" 52 | "program will individually obtain patent licenses, in effect making the\n" 53 | "program proprietary. To prevent this, we have made it clear that any\n" 54 | "patent must be licensed for everyone's free use or not licensed at all.\n" 55 | "\n" 56 | " The precise terms and conditions for copying, distribution and\n" 57 | "modification follow.\n" 58 | "\n" 59 | " GNU GENERAL PUBLIC LICENSE\n" 60 | " TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n" 61 | "\n" 62 | " 0. This License applies to any program or other work which contains\n" 63 | "a notice placed by the copyright holder saying it may be distributed\n" 64 | "under the terms of this General Public License. The \"Program\", below,\n" 65 | "refers to any such program or work, and a \"work based on the Program\"\n" 66 | "means either the Program or any derivative work under copyright law:\n" 67 | "that is to say, a work containing the Program or a portion of it,\n" 68 | "either verbatim or with modifications and/or translated into another\n" 69 | "language. (Hereinafter, translation is included without limitation in\n" 70 | "the term \"modification\".) Each licensee is addressed as \"you\".\n" 71 | "\n" 72 | "Activities other than copying, distribution and modification are not\n" 73 | "covered by this License; they are outside its scope. The act of\n" 74 | "running the Program is not restricted, and the output from the Program\n" 75 | "is covered only if its contents constitute a work based on the\n" 76 | "Program (independent of having been made by running the Program).\n" 77 | "Whether that is true depends on what the Program does.\n" 78 | "\n" 79 | " 1. You may copy and distribute verbatim copies of the Program's\n" 80 | "source code as you receive it, in any medium, provided that you\n" 81 | "conspicuously and appropriately publish on each copy an appropriate\n" 82 | "copyright notice and disclaimer of warranty; keep intact all the\n" 83 | "notices that refer to this License and to the absence of any warranty;\n" 84 | "and give any other recipients of the Program a copy of this License\n" 85 | "along with the Program.\n" 86 | "\n" 87 | "You may charge a fee for the physical act of transferring a copy, and\n" 88 | "you may at your option offer warranty protection in exchange for a fee.\n" 89 | "\n" 90 | " 2. You may modify your copy or copies of the Program or any portion\n" 91 | "of it, thus forming a work based on the Program, and copy and\n" 92 | "distribute such modifications or work under the terms of Section 1\n" 93 | "above, provided that you also meet all of these conditions:\n" 94 | "\n" 95 | " a) You must cause the modified files to carry prominent notices\n" 96 | " stating that you changed the files and the date of any change.\n" 97 | "\n" 98 | " b) You must cause any work that you distribute or publish, that in\n" 99 | " whole or in part contains or is derived from the Program or any\n" 100 | " part thereof, to be licensed as a whole at no charge to all third\n" 101 | " parties under the terms of this License.\n" 102 | "\n" 103 | " c) If the modified program normally reads commands interactively\n" 104 | " when run, you must cause it, when started running for such\n" 105 | " interactive use in the most ordinary way, to print or display an\n" 106 | " announcement including an appropriate copyright notice and a\n" 107 | " notice that there is no warranty (or else, saying that you provide\n" 108 | " a warranty) and that users may redistribute the program under\n" 109 | " these conditions, and telling the user how to view a copy of this\n" 110 | " License. (Exception: if the Program itself is interactive but\n" 111 | " does not normally print such an announcement, your work based on\n" 112 | " the Program is not required to print an announcement.)\n" 113 | "\n" 114 | "These requirements apply to the modified work as a whole. If\n" 115 | "identifiable sections of that work are not derived from the Program,\n" 116 | "and can be reasonably considered independent and separate works in\n" 117 | "themselves, then this License, and its terms, do not apply to those\n" 118 | "sections when you distribute them as separate works. But when you\n" 119 | "distribute the same sections as part of a whole which is a work based\n" 120 | "on the Program, the distribution of the whole must be on the terms of\n" 121 | "this License, whose permissions for other licensees extend to the\n" 122 | "entire whole, and thus to each and every part regardless of who wrote it.\n" 123 | "\n" 124 | "Thus, it is not the intent of this section to claim rights or contest\n" 125 | "your rights to work written entirely by you; rather, the intent is to\n" 126 | "exercise the right to control the distribution of derivative or\n" 127 | "collective works based on the Program.\n" 128 | "\n" 129 | "In addition, mere aggregation of another work not based on the Program\n" 130 | "with the Program (or with a work based on the Program) on a volume of\n" 131 | "a storage or distribution medium does not bring the other work under\n" 132 | "the scope of this License.\n" 133 | "\n" 134 | " 3. You may copy and distribute the Program (or a work based on it,\n" 135 | "under Section 2) in object code or executable form under the terms of\n" 136 | "Sections 1 and 2 above provided that you also do one of the following:\n" 137 | "\n" 138 | " a) Accompany it with the complete corresponding machine-readable\n" 139 | " source code, which must be distributed under the terms of Sections\n" 140 | " 1 and 2 above on a medium customarily used for software interchange; or,\n" 141 | "\n" 142 | " b) Accompany it with a written offer, valid for at least three\n" 143 | " years, to give any third party, for a charge no more than your\n" 144 | " cost of physically performing source distribution, a complete\n" 145 | " machine-readable copy of the corresponding source code, to be\n" 146 | " distributed under the terms of Sections 1 and 2 above on a medium\n" 147 | " customarily used for software interchange; or,\n" 148 | "\n" 149 | " c) Accompany it with the information you received as to the offer\n" 150 | " to distribute corresponding source code. (This alternative is\n" 151 | " allowed only for noncommercial distribution and only if you\n" 152 | " received the program in object code or executable form with such\n" 153 | " an offer, in accord with Subsection b above.)\n" 154 | "\n" 155 | "The source code for a work means the preferred form of the work for\n" 156 | "making modifications to it. For an executable work, complete source\n" 157 | "code means all the source code for all modules it contains, plus any\n" 158 | "associated interface definition files, plus the scripts used to\n" 159 | "control compilation and installation of the executable. However, as a\n" 160 | "special exception, the source code distributed need not include\n" 161 | "anything that is normally distributed (in either source or binary\n" 162 | "form) with the major components (compiler, kernel, and so on) of the\n" 163 | "operating system on which the executable runs, unless that component\n" 164 | "itself accompanies the executable.\n" 165 | "\n" 166 | "If distribution of executable or object code is made by offering\n" 167 | "access to copy from a designated place, then offering equivalent\n" 168 | "access to copy the source code from the same place counts as\n" 169 | "distribution of the source code, even though third parties are not\n" 170 | "compelled to copy the source along with the object code.\n" 171 | "\n" 172 | " 4. You may not copy, modify, sublicense, or distribute the Program\n" 173 | "except as expressly provided under this License. Any attempt\n" 174 | "otherwise to copy, modify, sublicense or distribute the Program is\n" 175 | "void, and will automatically terminate your rights under this License.\n" 176 | "However, parties who have received copies, or rights, from you under\n" 177 | "this License will not have their licenses terminated so long as such\n" 178 | "parties remain in full compliance.\n" 179 | "\n" 180 | " 5. You are not required to accept this License, since you have not\n" 181 | "signed it. However, nothing else grants you permission to modify or\n" 182 | "distribute the Program or its derivative works. These actions are\n" 183 | "prohibited by law if you do not accept this License. Therefore, by\n" 184 | "modifying or distributing the Program (or any work based on the\n" 185 | "Program), you indicate your acceptance of this License to do so, and\n" 186 | "all its terms and conditions for copying, distributing or modifying\n" 187 | "the Program or works based on it.\n" 188 | "\n" 189 | " 6. Each time you redistribute the Program (or any work based on the\n" 190 | "Program), the recipient automatically receives a license from the\n" 191 | "original licensor to copy, distribute or modify the Program subject to\n" 192 | "these terms and conditions. You may not impose any further\n" 193 | "restrictions on the recipients' exercise of the rights granted herein.\n" 194 | "You are not responsible for enforcing compliance by third parties to\n" 195 | "this License.\n" 196 | "\n" 197 | " 7. If, as a consequence of a court judgment or allegation of patent\n" 198 | "infringement or for any other reason (not limited to patent issues),\n" 199 | "conditions are imposed on you (whether by court order, agreement or\n" 200 | "otherwise) that contradict the conditions of this License, they do not\n" 201 | "excuse you from the conditions of this License. If you cannot\n" 202 | "distribute so as to satisfy simultaneously your obligations under this\n" 203 | "License and any other pertinent obligations, then as a consequence you\n" 204 | "may not distribute the Program at all. For example, if a patent\n" 205 | "license would not permit royalty-free redistribution of the Program by\n" 206 | "all those who receive copies directly or indirectly through you, then\n" 207 | "the only way you could satisfy both it and this License would be to\n" 208 | "refrain entirely from distribution of the Program.\n" 209 | "\n" 210 | "If any portion of this section is held invalid or unenforceable under\n" 211 | "any particular circumstance, the balance of the section is intended to\n" 212 | "apply and the section as a whole is intended to apply in other\n" 213 | "circumstances.\n" 214 | "\n" 215 | "It is not the purpose of this section to induce you to infringe any\n" 216 | "patents or other property right claims or to contest validity of any\n" 217 | "such claims; this section has the sole purpose of protecting the\n" 218 | "integrity of the free software distribution system, which is\n" 219 | "implemented by public license practices. Many people have made\n" 220 | "generous contributions to the wide range of software distributed\n" 221 | "through that system in reliance on consistent application of that\n" 222 | "system; it is up to the author/donor to decide if he or she is willing\n" 223 | "to distribute software through any other system and a licensee cannot\n" 224 | "impose that choice.\n" 225 | "\n" 226 | "This section is intended to make thoroughly clear what is believed to\n" 227 | "be a consequence of the rest of this License.\n" 228 | "\n" 229 | " 8. If the distribution and/or use of the Program is restricted in\n" 230 | "certain countries either by patents or by copyrighted interfaces, the\n" 231 | "original copyright holder who places the Program under this License\n" 232 | "may add an explicit geographical distribution limitation excluding\n" 233 | "those countries, so that distribution is permitted only in or among\n" 234 | "countries not thus excluded. In such case, this License incorporates\n" 235 | "the limitation as if written in the body of this License.\n" 236 | "\n" 237 | " 9. The Free Software Foundation may publish revised and/or new versions\n" 238 | "of the General Public License from time to time. Such new versions will\n" 239 | "be similar in spirit to the present version, but may differ in detail to\n" 240 | "address new problems or concerns.\n" 241 | "\n" 242 | "Each version is given a distinguishing version number. If the Program\n" 243 | "specifies a version number of this License which applies to it and \"any\n" 244 | "later version\", you have the option of following the terms and conditions\n" 245 | "either of that version or of any later version published by the Free\n" 246 | "Software Foundation. If the Program does not specify a version number of\n" 247 | "this License, you may choose any version ever published by the Free Software\n" 248 | "Foundation.\n" 249 | "\n" 250 | " 10. If you wish to incorporate parts of the Program into other free\n" 251 | "programs whose distribution conditions are different, write to the author\n" 252 | "to ask for permission. For software which is copyrighted by the Free\n" 253 | "Software Foundation, write to the Free Software Foundation; we sometimes\n" 254 | "make exceptions for this. Our decision will be guided by the two goals\n" 255 | "of preserving the free status of all derivatives of our free software and\n" 256 | "of promoting the sharing and reuse of software generally.\n" 257 | "\n" 258 | " NO WARRANTY\n" 259 | "\n" 260 | " 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n" 261 | "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n" 262 | "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n" 263 | "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n" 264 | "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n" 265 | "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n" 266 | "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n" 267 | "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n" 268 | "REPAIR OR CORRECTION.\n" 269 | "\n" 270 | " 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n" 271 | "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n" 272 | "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n" 273 | "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n" 274 | "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n" 275 | "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n" 276 | "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n" 277 | "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n" 278 | "POSSIBILITY OF SUCH DAMAGES.\n" 279 | "\n" 280 | " END OF TERMS AND CONDITIONS\n" 281 | "\n" 282 | " How to Apply These Terms to Your New Programs\n" 283 | "\n" 284 | " If you develop a new program, and you want it to be of the greatest\n" 285 | "possible use to the public, the best way to achieve this is to make it\n" 286 | "free software which everyone can redistribute and change under these terms.\n" 287 | "\n" 288 | " To do so, attach the following notices to the program. It is safest\n" 289 | "to attach them to the start of each source file to most effectively\n" 290 | "convey the exclusion of warranty; and each file should have at least\n" 291 | "the \"copyright\" line and a pointer to where the full notice is found.\n" 292 | "\n" 293 | " \n" 294 | " Copyright (C) \n" 295 | "\n" 296 | " This program is free software; you can redistribute it and/or modify\n" 297 | " it under the terms of the GNU General Public License as published by\n" 298 | " the Free Software Foundation; either version 2 of the License, or\n" 299 | " (at your option) any later version.\n" 300 | "\n" 301 | " This program is distributed in the hope that it will be useful,\n" 302 | " but WITHOUT ANY WARRANTY; without even the implied warranty of\n" 303 | " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" 304 | " GNU General Public License for more details.\n" 305 | "\n" 306 | " You should have received a copy of the GNU General Public License along\n" 307 | " with this program; if not, write to the Free Software Foundation, Inc.,\n" 308 | " 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" 309 | "\n" 310 | "Also add information on how to contact you by electronic and paper mail.\n" 311 | "\n" 312 | "If the program is interactive, make it output a short notice like this\n" 313 | "when it starts in an interactive mode:\n" 314 | "\n" 315 | " Gnomovision version 69, Copyright (C) year name of author\n" 316 | " Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n" 317 | " This is free software, and you are welcome to redistribute it\n" 318 | " under certain conditions; type `show c' for details.\n" 319 | "\n" 320 | "The hypothetical commands `show w' and `show c' should show the appropriate\n" 321 | "parts of the General Public License. Of course, the commands you use may\n" 322 | "be called something other than `show w' and `show c'; they could even be\n" 323 | "mouse-clicks or menu items--whatever suits your program.\n" 324 | "\n" 325 | "You should also get your employer (if you work as a programmer) or your\n" 326 | "school, if any, to sign a \"copyright disclaimer\" for the program, if\n" 327 | "necessary. Here is a sample; alter the names:\n" 328 | "\n" 329 | " Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n" 330 | " `Gnomovision' (which makes passes at compilers) written by James Hacker.\n" 331 | "\n" 332 | " , 1 April 1989\n" 333 | " Ty Coon, President of Vice\n" 334 | "\n" 335 | "This General Public License does not permit incorporating your program into\n" 336 | "proprietary programs. If your program is a subroutine library, you may\n" 337 | "consider it more useful to permit linking proprietary applications with the\n" 338 | "library. If this is what you want to do, use the GNU Lesser General\n" 339 | "Public License instead of this License.\n" 340 | -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | srcdir=@srcdir@ 2 | 3 | CFLAGS=@CFLAGS@ 4 | LDFLAGS=@LDFLAGS@ @OPENSSL_LDFLAGS@ 5 | CPPFLAGS=@CPPFLAGS@ @OPENSSL_INCLUDES@ 6 | DEFS=@DEFS@ 7 | COMPILE_FLAGS=${CFLAGS} ${CPFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Werror -Wextra -Wno-missing-field-initializers -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb -Wno-unused-parameter -fPIC 8 | EXTRA_LIBS=@LIBS@ @EXTRA_LIBS@ @OPENSSL_LIBS@ 9 | LOCAL_LDFLAGS=-rdynamic -ggdb -levent ${EXTRA_LIBS} -ldl -lpthread -lutil 10 | LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} 11 | 12 | DEP=dep 13 | AUTO=auto 14 | EXE=bin 15 | OBJ=objs 16 | LIB=libs 17 | DIR_LIST=${DEP} ${AUTO} ${EXE} ${OBJ} ${LIB} ${DEP}/auto ${OBJ}/auto 18 | 19 | EXE_LIST=${EXE}/telegram-cli 20 | 21 | TG_OBJECTS=${OBJ}/main.o ${OBJ}/loop.o ${OBJ}/interface.o ${OBJ}/lua-tg.o ${OBJ}/json-tg.o ${OBJ}/python-tg.o ${OBJ}/python-types.o 22 | 23 | INCLUDE=-I. -I${srcdir} -I${srcdir}/tgl 24 | CC=@CC@ 25 | 26 | .SUFFIXES: 27 | 28 | .SUFFIXES: .c .h .o 29 | 30 | all: ${EXE_LIST} ${DIR_LIST} 31 | create_dirs_and_headers: ${DIR_LIST} ${AUTO}/auto-skip.h ${AUTO}/auto-fetch.h ${AUTO}/auto-store.h ${AUTO}/auto-autocomplete.h ${AUTO}/auto-types.h ${AUTO}/constants.h ${AUTO}/constants.h ${AUTO}/auto-skip.h ${AUTO}/auto-fetch.h ${AUTO}/auto-store.h ${AUTO}/auto-autocomplete.h ${AUTO}/auto-types.h ${AUTO}/auto-fetch-ds.h ${AUTO}/auto-free-ds.h ${AUTO}/auto-store-ds.h ${AUTO}/auto-print-ds.h 32 | create_dirs: ${DIR_LIST} 33 | dump-tl: ${EXE}/dump-tl-file 34 | 35 | include ${srcdir}/Makefile.tl-parser 36 | include ${srcdir}/Makefile.tgl 37 | 38 | ${DIR_LIST}: 39 | @test -d $@ || mkdir -p $@ 40 | 41 | OBJ_LIST=${TG_OBJECTS} ${TGL_OBJECTS} ${TGL_COMMON_OBJECTS} ${GENERATE_OBJECTS} ${TL_PARSER_OBJECTS} ${TGL_OBJECTS_AUTO} 42 | DEPENDENCE=$(subst ${OBJ}/,${DEP}/,$(patsubst %.o,%.d,${OBJ_LIST})) 43 | DEPENDENCE_LIST=${DEPENDENCE} 44 | 45 | -include ${DEPENDENCE_LIST} 46 | 47 | ${TG_OBJECTS}: ${OBJ}/%.o: ${srcdir}/%.c | create_dirs_and_headers 48 | ${CC} ${INCLUDE} ${COMPILE_FLAGS} -c -MP -MD -MF ${DEP}/$*.d -MQ ${OBJ}/$*.o -o $@ $< 49 | 50 | ${EXE}/telegram-cli: ${TG_OBJECTS} ${LIB}/libtgl.a 51 | ${CC} $^ ${LINK_FLAGS} -o $@ 52 | 53 | clean: 54 | rm -rf ${DIR_LIST} config.log config.status > /dev/null || echo "all clean" 55 | 56 | -------------------------------------------------------------------------------- /Makefile.tgl: -------------------------------------------------------------------------------- 1 | TGL_OBJECTS=${OBJ}/mtproto-common.o ${OBJ}/mtproto-client.o ${OBJ}/queries.o ${OBJ}/structures.o ${OBJ}/binlog.o ${OBJ}/tgl.o ${OBJ}/updates.o ${OBJ}/tgl-net.o ${OBJ}/tgl-timers.o ${OBJ}/tg-mime-types.o ${OBJ}/mtproto-utils.o 2 | 3 | TGL_OBJECTS_AUTO=${OBJ}/auto/auto-skip.o ${OBJ}/auto/auto-fetch.o ${OBJ}/auto/auto-store.o ${OBJ}/auto/auto-autocomplete.o ${OBJ}/auto/auto-types.o ${OBJ}/auto/auto-fetch-ds.o ${OBJ}/auto/auto-free-ds.o ${OBJ}/auto/auto-store-ds.o ${OBJ}/auto/auto-print-ds.o 4 | 5 | 6 | TLD_OBJECTS=${OBJ}/dump-tl-file.o 7 | GENERATE_OBJECTS=${OBJ}/generate.o 8 | TGL_COMMON_OBJECTS=${OBJ}/tools.o 9 | TGL_OBJ_C=${GENERATE_OBJECTS} ${TGL_COMMON_OBJECTS} ${TGL_OBJECTS} ${TLD_OBJECTS} 10 | 11 | .SUFFIXES: 12 | 13 | .SUFFIXES: .c .h .o 14 | 15 | dump-tl: ${EXE}/dump-tl-file 16 | 17 | ${TGL_OBJECTS}: ${AUTO}/constants.h ${AUTO}/auto-skip.h ${AUTO}/auto-fetch.h ${AUTO}/auto-store.h ${AUTO}/auto-autocomplete.h ${AUTO}/auto-types.h ${AUTO}/auto-fetch-ds.h ${AUTO}/auto-free-ds.h ${AUTO}/auto-store-ds.h ${AUTO}/auto-print-ds.h 18 | 19 | ${TGL_OBJ_C}: ${OBJ}/%.o: ${srcdir}/tgl/%.c | create_dirs 20 | ${CC} ${INCLUDE} ${COMPILE_FLAGS} -iquote ${srcdir}/tgl -c -MP -MD -MF ${DEP}/$*.d -MQ ${OBJ}/$*.o -o $@ $< 21 | 22 | ${TGL_OBJECTS_AUTO}: ${OBJ}/auto/%.o: ${AUTO}/%.c | create_dirs 23 | ${CC} ${INCLUDE} ${COMPILE_FLAGS} -iquote ${srcdir}/tgl -c -MP -MD -MF ${DEP}/$*.d -MQ ${OBJ}/$*.o -o $@ $< 24 | 25 | #${OBJ}/auto/auto.o: ${AUTO}/auto.c 26 | # ${CC} ${INCLUDE} ${COMPILE_FLAGS} -iquote ${srcdir}/tgl -c -MP -MD -MF ${DEP}/auto/auto.d -MQ ${OBJ}/auto/auto.o -o $@ $< 27 | 28 | ${LIB}/libtgl.a: ${TGL_OBJECTS} ${TGL_COMMON_OBJECTS} ${TGL_OBJECTS_AUTO} 29 | rm -f $@ && ar ruv $@ $^ 30 | 31 | ${EXE}/generate: ${GENERATE_OBJECTS} ${TGL_COMMON_OBJECTS} 32 | ${CC} ${GENERATE_OBJECTS} ${TGL_COMMON_OBJECTS} ${LINK_FLAGS} -o $@ 33 | 34 | ${AUTO}/scheme.tlo: ${AUTO}/scheme.tl ${EXE}/tl-parser 35 | ${EXE}/tl-parser -e $@ ${AUTO}/scheme.tl 36 | 37 | ${AUTO}/scheme.tl: ${srcdir}/tgl/scheme.tl ${srcdir}/tgl/encrypted_scheme.tl ${srcdir}/tgl/binlog.tl ${srcdir}/tgl/append.tl ${srcdir}/tgl/mtproto.tl | ${AUTO} 38 | cat $^ > $@ 39 | 40 | ${AUTO}/scheme2.tl: ${AUTO}/scheme.tl ${EXE}/tl-parser 41 | ${EXE}/tl-parser -E ${AUTO}/scheme.tl 2> $@ || ( cat $@ && rm $@ && false ) 42 | 43 | ${AUTO}/auto-%.c: ${AUTO}/scheme.tlo ${EXE}/generate auto/constants.h ${AUTO}/auto-%.h | create_dirs_and_headers 44 | ${EXE}/generate -g $(patsubst ${AUTO}/auto-%.c,%,$@) ${AUTO}/scheme.tlo > $@ || rm $@ 45 | 46 | ${AUTO}/auto-%.h: ${AUTO}/scheme.tlo ${EXE}/generate 47 | ${EXE}/generate -g $(patsubst ${AUTO}/auto-%.h,%-header,$@) ${AUTO}/scheme.tlo > $@ || rm $@ 48 | 49 | ${AUTO}/constants.h: ${AUTO}/scheme2.tl ${srcdir}/tgl/gen_constants_h.awk 50 | awk -f ${srcdir}/tgl/gen_constants_h.awk < $< > $@ 51 | 52 | ${EXE}/dump-tl-file: ${OBJ}/auto/auto.o ${TLD_OBJECTS} 53 | ${CC} ${OBJ}/auto/auto.o ${TLD_OBJECTS} ${LINK_FLAGS} -o $@ 54 | 55 | -------------------------------------------------------------------------------- /Makefile.tl-parser: -------------------------------------------------------------------------------- 1 | TL_PARSER_OBJECTS=${OBJ}/tl-parser.o ${OBJ}/tlc.o ${OBJ}/crc32.o 2 | 3 | ${TL_PARSER_OBJECTS}: ${OBJ}/%.o: ${srcdir}/tgl/tl-parser/%.c | create_dirs 4 | ${CC} ${INCLUDE} ${COMPILE_FLAGS} -iquote ${srcdir}/tgl/tl-parser -c -MP -MD -MF ${DEP}/$*.d -MQ ${OBJ}/$*.o -o $@ $< 5 | 6 | ${EXE}/tl-parser: ${TL_PARSER_OBJECTS} 7 | ${CC} $^ ${LINK_FLAGS} -o $@ 8 | -------------------------------------------------------------------------------- /README-Cygwin.md: -------------------------------------------------------------------------------- 1 | ### Installation on Windows 2 | To use telegram-cli in Windows, you should compile with Cygwin which has POSIX API functionality. 3 | 4 | Install [Cygwin](https://www.cygwin.com/) and cygwin's package manager, [apt-cyg](https://github.com/transcode-open/apt-cyg). 5 | 6 | In Cygwin Terminal, install compiler and tools : 7 | 8 | apt-cyg install cygwin32-gcc-core cygwin32-gcc-g++ gcc-core gcc-g++ make wget patch diffutils grep tar gzip 9 | 10 | Now you have a compiler, but no libraries. You need readline, openssl, libconfig, liblua, python and libjansson to use telegram-cli's full functionality. 11 | 12 | 13 | Then Clone GitHub Repository in Cygwin Terminal 14 | 15 | git clone --recursive https://github.com/vysheng/tg.git 16 | 17 | 18 | In Cygwin Terminal, type: 19 | 20 | apt-cyg install libevent-devel openssl-devel libreadline-devel lua-devel python3 21 | (Install package 'python' to use Python 2.7, or install package 'python3' to use Python 3) 22 | 23 | libconfig and libjansson is not in cygwin's package, so you should compile yourself. 24 | 25 | Compile libconfig 26 | 27 | wget http://www.hyperrealm.com/libconfig/libconfig-1.5.tar.gz 28 | tar xvf libconfig-1.5.tar.gz && cd libconfig-1.5 29 | ./configure 30 | make && make install && cd .. 31 | 32 | Compile libjansson 33 | 34 | wget http://www.digip.org/jansson/releases/jansson-2.7.tar.gz 35 | tar xvf jansson-2.7.tar.gz && cd jansson-2.7 36 | ./configure 37 | make && make install && cd .. 38 | 39 | Then, go to tg directory then generate Makefile. 40 | 41 | cd tg 42 | ./configure 43 | 44 | We need to patch Makefile and loop.c to compile in cygwin. Download this [patch](https://gist.github.com/ied206/d774a445f36004d263ab) then untar. Then, patch in tg directory. 45 | 46 | patch -p1 < telegram-cli-cygwin.patch 47 | 48 | Then 49 | make 50 | 51 | After compile is done, **telegram-cli.exe** will be generated in **bin** directory. 52 | 53 | To run telegram-cli, type 54 | 55 | bin/telegram-cli -k tg-server.pub 56 | 57 | **Caution**: A binary compiled with Cygwin should be run in Cygwin Terminal. 58 | -------------------------------------------------------------------------------- /README-LUA: -------------------------------------------------------------------------------- 1 | To use lua with client you should write lua script. You can specify it from config ("lua_script" option) or from command_line [-s]. 2 | 3 | It should have several functions: 4 | on_binlog_replay_end() - it is called when replay of old events end. Any updates prior this call were already received by this client 5 | some time ago. 6 | 7 | on_get_difference_end() - it is called after first get_difference call. So we received all updates after last client execute. 8 | 9 | on_our_id(our_id) - Informs about id of currently logged in user. 10 | 11 | on_msg_receive(msg) - it is called when we receive new msg (!! may be called before on_binlog_replay_end, than it is old msg). 12 | 13 | on_user_update(user,what_changed) - updated info about user. what_changed is array of strings. 14 | on_chat_update(user,what_changed) - updated info about user. what_changed is array of strings. 15 | on_secret_chat_update(user,what_changed) - updated info about user. what_changed is array of strings. 16 | 17 | 18 | 19 | Also, you can call several functions. Each this function last two arguments, are cb_function and cb_extra. 20 | These functions may return false immidiately if something is bad with args, or return true and call cb_function in future. 21 | cb_function would have two or three arguments: first cb_extra, second success (1 or 0), third result (if applicable). 22 | 23 | If you want to pass msg to function, you should pass it's id. 24 | If you want to pass peer to function, you should pass it's print_name. 25 | Or, you can pass string user#id chat#id and secret_chat#id as peer. It is in some cases better. For example if you want to postpone and you are afraid, that print_name would be changed in the meantime. 26 | 27 | Function_list (arguments are listed aside from cb_function and cb_extra, : 28 | get_contact_list () 29 | get_dialog_list () 30 | 31 | rename_chat (chat, new_name) 32 | chat_set_photo (chat, file) 33 | 34 | send_typing (peer) 35 | send_typing_abort (peer) 36 | 37 | send_msg (peer, text) 38 | fwd_msg (peer, msg) 39 | 40 | send_photo (peer, file) 41 | send_video (peer, file) 42 | send_audio (peer, file) 43 | send_document (peer, file) 44 | send_text (peer, file) 45 | 46 | load_photo(msg) 47 | load_video(msg) 48 | load_video_thumb(msg) 49 | load_audio(msg) 50 | load_document(msg) 51 | load_document_thumb(msg) 52 | 53 | chat_info (chat) 54 | user_info (user) 55 | 56 | get_history (peer, limit) 57 | 58 | chat_add_user (chat, user) 59 | chat_del_user (chat, user) 60 | 61 | add_contact (phone, first_name, last_name) 62 | rename_contact (phone, first_name, last_name) 63 | 64 | msg_search (peer, text) 65 | msg_global_search (text) 66 | 67 | mark_read (peer) 68 | 69 | set_profile_photo (file) 70 | 71 | create_secret_chat (user) 72 | create_group_chat (user, name) 73 | 74 | delete_msg (msg) 75 | restore_msg (number) 76 | 77 | status_online () 78 | status_offline () 79 | 80 | send_location (peer, latitude, longitude) 81 | 82 | Also, you have function 83 | postpone (cb_function, cb_extra, timeout). It will call your cb_function in specified number of seconds (number of seconds may be double). 84 | register_interface_function (name, cb_function, cb_arg, description, arg1_type, arg2_type, ...) adds function to CLI interface 85 | -------------------------------------------------------------------------------- /README-PY.md: -------------------------------------------------------------------------------- 1 | Python Bindings 2 | ==================== 3 | All of the functions and methods are executed in the network loop of tg, ***NOT IMMEDIATELY***. What this means is all calls should be considered async, and so there is an optional callback parameter for every function/method as the last parameter. For many uses, you won't care about the return value, so you can leave out the callback. Note there are a few cases where the callback is considered mandatory when the function is considered an information query and has no functionality without returned data. These will explicitly have the callback in the parameter list and will be noted in the description. 4 | 5 | You can specify the python script from config ("python_script" option) or from command_line [-Z]. 6 | 7 | Version Notes 8 | ===================== 9 | The python integration is written with Python 2/3 in mind, however, there is a bias to Python 3. Because of this, there are a few caveats: 10 | - I am only testing against Python 2.7, and have no intention to support/test < 2.7 but am more than happy to accept PRs for fixes as long as it does not break 2.7/3 11 | - repr/print of native types is dumbed down for < 2.7.9, I highly recommend using this version or newer. (This is due to a [bug](http://bugs.python.org/issue22023) in python) 12 | 13 | TGL Callbacks 14 | ============= 15 | Assign python fuctions to the following tgl attributes to set callbacks from TG. 16 | 17 | | Callback | Description | 18 | |--------- | ---------------------| 19 | |`tgl.on_binlog_replay_end()` | This is called when replay of old events end. Any updates prior this call were already received by this client some time ago.| 20 | |`tgl.on_get_difference_end()`| This is called after first get_difference call. So we received all updates after last client execute.| 21 | |`tgl.on_our_id(our_id)`|Informs about id of currently logged in user.| 22 | |`tgl.on_msg_receive(msg)`| This is called when we receive new `tgl.Msg` object (*may be called before on_binlog_replay_end, than it is old msg*).| 23 | |`tgl.on_user_update(peer, what_changed)`|updated info about user. peer is a `tgl.Peer` object representing the user, and what_changed is array of strings.| 24 | |`tgl.on_chat_update(peer, what_changed)`|updated info about chat. peer is a `tgl.Peer` object representing the chat, and what_changed is array of strings.| 25 | |`tgl.on_secret_chat_update(peer, what_changed)`|updated info about secret chat. peer is a `tgl.Peer` object representing the secret chat, and what_changed is array of strings.| 26 | 27 | Python Callback Signatures 28 | ========================= 29 | As mentioned, all methods and functions have callbacks. The following are the different signatures that may be required (*The description of the method will mention which is used*) 30 | 31 | | Type | Signature | Description | 32 | |----- | ------------------ | ------------| 33 | |empty_cb|`(success)`|This just indicated the success of the call. All other callback types have this as well.| 34 | |contact_list_cb|`(success, peer_list)`|`peer_list` is a list of `tgl.Peer` objects| 35 | |dialog_list_cb|`(success, dialog_list)`|`dialog_list` is a list of dicts, with keys: 'peer': `tgl.Peer`, 'message': `tgl.Msg`| 36 | |msg_cb|`(success, msg)`|`msg` is a `tgl.Msg`| 37 | |msg_list_cb|`(success, msg_list)`|`msg_list` is a list of `tgl.Msg` objects| 38 | |file_cb|`(success, file_path)`|`file_path` is a string with an absolute path| 39 | |chat_cb|`(success, peer)`|`peer` is a `tgl.Peer` that will have the type of `tgl.PEER_CHAT`| 40 | |peer_cb|`(success, peer)`|`peer` is a `tgl.Peer`| 41 | |secret_chat_cb|`(success, peer)`|`peer` is a `tgl.Peer` that will have the type of `tgl.PEER_ENCR_CHAT`| 42 | |user_cb|`(success, peer)`|`peer` is a `tgl.Peer` that will have the type of `tgl.PEER_USER`| 43 | |str_cb|`(success, string)`|`string` is a simple string| 44 | 45 | TGL Module Level Fuctions 46 | ========================= 47 | All of these functions are accessed by importing the `tgl` module. 48 | 49 | | Function | Description | Callback Type | 50 | |--------- | ---------------------| ------------- | 51 | |`tgl.get_contact_list (callback)`|Retrieve peers stored in the contact list. *requires callback*|`contact_list_cb`| 52 | |`tgl.get_dialog_list (callback)`|Get a list of current conversations with the `tgl.Peer` and the most recent `tgl.Msg`. *requires callback*|`dialog_list_cb`| 53 | |`tgl.add_contact (phone, first_name, last_name)`|Adds contact to contact list, last name is optional|`contact_list_cb`| 54 | |`tgl.del_contact (peer)`|Removes contact from contact list|`empty_cb`| 55 | |`tgl.rename_contact (phone, first_name, last_name) `|Renaming a contact means sending the first/last name with the same phone number of an existing contact|`contact_list_cb`| 56 | |`tgl.msg_global_search (text, callback)`|Get all messages that match the search text. *requires callback*|`msg_list_cb`| 57 | |`tgl.set_profile_photo (file_path)`|Sets avatar to image found at `file_path`, no checking on the file.|`empty_cb`| 58 | |`tgl.create_secret_chat (user)`|Creates secret chat with user, callback recommended to get new peer for the secret chat.|`secret_chat_cb`| 59 | |`tgl.create_group_chat (peer_list, name)`|`peer_list` contains users to create group with, must be more than 1 peer.|`empty_cb`| 60 | |`tgl.restore_msg (msg_id)`|Restore a deleted message by message id.|`empty_cb`| 61 | |`tgl.status_online ()`|Sets status as online|`empty_cb`| 62 | |`tgl.status_offline ()`|Sets status as offline|`empty_cb`| 63 | |`tgl.import_chat_link (link)`|Join channel using the `link`.|`empty_cb`| 64 | |`tgl.safe_exit (exit_status)`|Exception to the rule about callbacks, no callback parameter is accepted. Causes the bot to quit after cleaning up. `exit_status` is an optional parameter with the exit status (On glibc, this must be 0-255)|NONE| 65 | 66 | Peer 67 | ==== 68 | ## Attributes 69 | | Attribute | Type | Description | 70 | |---------- | ---- | ----------------------| 71 | |`id`|`int`|Telegram peer id| 72 | |`type`|`int`|Peer type, you can compare this with `tgl.PEER_CHAT`, `tgl.PEER_USER`, or `tgl.PEER_ENCR_CHAT`| 73 | |`type_name`|`string`|Text representation of the type of the peer, `'chat'`, `'user'`, or `'secret_chat'`| 74 | |`name`|`string`|Returns the tg print version of the name. Usually `FirstName_LastName` for user, and the chatname with spaces replaced with `_`| 75 | |`user_id`|`int`|Used in secret chats, since a secret chat has it's own id, this is the id of the user at the endpoint.| 76 | |`user_list`|`peer_list`|Only used in `tgl.PEER_CHAT` peers, contains list of users. This currently does not work, it is not populating properly.| 77 | |`user_status`|`dict`|Only used in `tgl.PEER_USER` peers. Dictionary with the current status, keys: 'online': `bool`, 'when': `datetime`| 78 | |`phone`|`string`|Only used in `tgl.PEER_USER` peers. Phone number, only available if user is on contact list.| 79 | |`username`|`string`|Only used in `tgl.PEER_USER` peers. Will be `None` if username is not set.| 80 | |`first_name`|`string`|Only used in `tgl.PEER_USER` peers.| 81 | |`last_name`|`string`|Only used in `tgl.PEER_USER` peers.| 82 | 83 | ## Methods 84 | | Method | Description | Callback Type | 85 | |------- | ---------------------| ------------- | 86 | |`peer.rename_chat (new_name)`||`empty_cb`| 87 | |`peer.chat_set_photo (file)`|Sets avatar for the group to image found at `file_path`, no checking on the file. The calling peer must be of type `tgl.PEER_CHAT`.|`msg_cb`| 88 | |`peer.send_typing ()`|Tell peer that you are typing.|`empty_cb`| 89 | |`peer.send_typing_abort ()`|Tell peer you are done typing.|`empty_cb`| 90 | |`peer.send_msg (text, reply=msg_id, preview=bool)`|Sends message to peer. Optional keyword arguments: reply is the message id we are replying to, preview is a boolean that forces URL preview on or off.|`msg_cb`| 91 | |`peer.fwd_msg (msg_id)`|Forwards msg with message id to peer.|`msg_cb`| 92 | |`peer.fwd_media (msg_id)`|Forwards media with message id to peer.|`msg_cb`| 93 | |`peer.send_photo (file)`|Send media to peer using `file`. No checking is done on the contents of the file.|`msg_cb`| 94 | |`peer.send_video (file)`|Send media to peer using `file`. No checking is done on the contents of the file.|`msg_cb`| 95 | |`peer.send_audio (file)`|Send media to peer using `file`. No checking is done on the contents of the file.|`msg_cb`| 96 | |`peer.send_document (file)`|Send media to peer using `file`. No checking is done on the contents of the file.|`msg_cb`| 97 | |`peer.send_text (file)`|Send media to peer using `file`. No checking is done on the contents of the file.|`msg_cb`| 98 | |`peer.send_location (latitude, longitude)`|Sends location media message to peer, `longitude` and `latitude` should be specified as double.|`msg_cb`| 99 | |`peer.chat_add_user (user)`|Adds `user`(`tgl.Peer`) to the group. The calling peer must be of type `tgl.PEER_CHAT`|`empty_cb`| 100 | |`peer.chat_del_user (user)`|Removes `user`(`tgl.Peer`) from the group. The calling peer must be of type `tgl.PEER_CHAT`|`empty_cb`| 101 | |`peer.mark_read ()`|Marks the dialog with the peer as read. This cannot be done on message level.|`empty_cb`| 102 | |`peer.msg_search (text, callback)`|Get all messages that match the search text with the peer. *requires callback*|`msg_list_cb`| 103 | |`peer.get_history (offset, limit, callback)`|Get all messages with the peer. `offset` specifies what message to start at, and `limit` specifies how many messages to retrieve. See example below for one method to get the entire history. *requires callback*|`msg_list_cb`| 104 | |`peer.info ()`|Gets peer info.|`peer_cb`| 105 | 106 | Example usage for `peer.get_history`: 107 | ``` 108 | from functools import partial 109 | history = [] 110 | # Get all the history, 100 msgs at a time 111 | peer.get_history(0, 100, partial(history_callback, 100, peer)) 112 | 113 | def history_callback(msg_count, peer, success, msgs) 114 | history.extend(msgs) 115 | if len(msgs) == msg_count: 116 | peer.get_history(len(history), msg_count, partial(history_callback, msg_count, peer)) 117 | ``` 118 | 119 | Msg 120 | ==== 121 | ## Attributes 122 | | Attribute | Type | Description | 123 | |---------- | ---- | ----------------------| 124 | |`id`|`int`|Message id| 125 | |`flags`|`int`|tgl flags, see source code for tgl for various possible flags. This is a bitfield in an int.| 126 | |`mention`|`bool`|`True` if you are @mentioned.| 127 | |`out`|`bool`|`True` if you sent this message.| 128 | |`unread`|`bool`|`True` if you have not marked this as read.| 129 | |`service`|`bool`|`True` if the message is a service messages, see tgl.Msg.action for the type.| 130 | |`src`|`tgl.Peer`|Peer who sent the message| 131 | |`dest`|`tgl.Peer`|Peer who the message was sent too. In a group, this will be the chat peer. Otherwise it will be you.| 132 | |`text`|`string`|Text contents of the message. This may be `None` if it's media without caption.| 133 | |`media`|`dict`|Dictionary that varies based on the media type.| 134 | |`date`|`datetime`|When the message was sent.| 135 | |`fwd_src`|`tgl.Peer`|The user that sent the forwarded message.| 136 | |`fwd_date`|`datetime`|When the forwarded message was originally sent.| 137 | |`reply`|`tgl.Msg`|Message that this message is replying to.| 138 | |`reply_id`|`int`|Message id that this message is replying to.| 139 | |`action`|`int`|Action enum for the message if `msg.service == True`. See all the possible values below| 140 | 141 | ## Action Type Constants 142 | - tgl.ACTION_NONE 143 | - tgl.ACTION_GEO_CHAT_CREATE 144 | - tgl.ACTION_GEO_CHAT_CHECKIN 145 | - tgl.ACTION_CHAT_CREATE 146 | - tgl.ACTION_CHAT_EDIT_TITLE 147 | - tgl.ACTION_CHAT_EDIT_PHOTO 148 | - tgl.ACTION_CHAT_DELETE_PHOTO 149 | - tgl.ACTION_CHAT_ADD_USER 150 | - tgl.ACTION_CHAT_ADD_USER_BY_LINK 151 | - tgl.ACTION_CHAT_DELETE_USER 152 | - tgl.ACTION_SET_MESSAGE_TTL 153 | - tgl.ACTION_READ_MESSAGES 154 | - tgl.ACTION_DELETE_MESSAGES 155 | - tgl.ACTION_SCREENSHOT_MESSAGES 156 | - tgl.ACTION_FLUSH_HISTORY 157 | - tgl.ACTION_RESEND 158 | - tgl.ACTION_NOTIFY_LAYER 159 | - tgl.ACTION_TYPING 160 | - tgl.ACTION_NOOP 161 | - tgl.ACTION_COMMIT_KEY 162 | - tgl.ACTION_ABORT_KEY 163 | - tgl.ACTION_REQUEST_KEY 164 | - tgl.ACTION_ACCEPT_KEY 165 | 166 | ## Methods 167 | | Method | Description | Callback Type | 168 | |------- | ---------------------| ------------- | 169 | |`msg.load_photo(callback)`|Saves the media and returns the path to the file in the callback. *requires callback*|`file_cb`| 170 | |`msg.load_video(callback)`|Saves the media and returns the path to the file in the callback. *requires callback*|`file_cb`| 171 | |`msg.load_video_thumb(callback)`|Saves the media and returns the path to the file in the callback. *requires callback*|`file_cb`| 172 | |`msg.load_audio(callback)`|Saves the media and returns the path to the file in the callback. *requires callback*|`file_cb`| 173 | |`msg.load_document(callback)`|Saves the media and returns the path to the file in the callback. *requires callback*|`file_cb`| 174 | |`msg.load_document_thumb(callback)`|Saves the media and returns the path to the file in the callback. *requires callback*|`file_cb`| 175 | |`msg.delete_msg ()`|Deletes the message from the local history|`empty_cb`| 176 | -------------------------------------------------------------------------------- /README.es: -------------------------------------------------------------------------------- 1 | ## Telegram messenger CLI [![Build Status](https://travis-ci.org/vysheng/tg.png)](https://travis-ci.org/vysheng/tg) 2 | 3 | !!!! May be outdated. Please refer to english README as more actual. 4 | 5 | 6 | Interfaz de línea de comandos para: [Telegram](http://telegram.org). Usa interfaz readline. 7 | 8 | ### Documentación del API y el protocolo 9 | 10 | La documentación del APi de Telegram está disponible aquí: http://core.telegram.org/api 11 | 12 | La documentación del protocolo MTproto está disponible aquí: http://core.telegram.org/mtproto 13 | 14 | ### Instalación 15 | 16 | Clona el Repositorio GitHub 17 | 18 | $ git clone https://github.com/vysheng/tg.git && cd tg 19 | 20 | o descarga y descomprime el zip 21 | 22 | $ wget https://github.com/vysheng/tg/archive/master.zip -O tg-master.zip 23 | $ unzip tg-master.zip && cd tg-master 24 | 25 | #### Linux 26 | 27 | Librerías requeridas: readline openssl y (si desea usar config) libconfig y liblua. 28 | Si no deseas usarlo, pasa las siguientes opciones --disable-libconfig y --disable-liblua respectivamente. 29 | 30 | En Ubuntu usa: 31 | 32 | $ sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev 33 | 34 | En gentoo: 35 | 36 | $ sudo emerge -av sys-libs/readline dev-libs/libconfig dev-libs/openssl dev-lang/lua 37 | 38 | En Fedora: 39 | 40 | $ sudo yum install lua-devel openssl-devel libconfig-devel readline-devel 41 | 42 | Por defecto Makefile utiliza liblua5.2 de ubuntu. Si utilizas una versión diferente de liblua o linux, tienes que ejecutar el script ./configure o recibirás un error de compilación extraño. 43 | 44 | Entonces 45 | 46 | $ ./configure 47 | $ make 48 | 49 | 50 | #### Mac OS X 51 | 52 | El cliente depende de [librería readline](http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html) y [libconfig](http://www.hyperrealm.com/libconfig/), las cuales no están incluídas en OS X por defecto. Debes instalar estas librerías de forma manual, usando por ejemplo [Homebrew](http://brew.sh/). 53 | 54 | $ brew install libconfig 55 | $ brew install readline 56 | $ brew install lua 57 | $ export CFLAGS="-I/usr/local/include -I/usr/local/Cellar/readline/6.2.4/include" 58 | $ export LDFLAGS="-L/usr/local/lib -L/usr/local/Cellar/readline/6.2.4/lib" 59 | $ ./configure && make 60 | 61 | Gracias a [@jfontan](https://github.com/vysheng/tg/issues/3#issuecomment-28293731) por esta solución. 62 | 63 | #### FreeBSD 64 | 65 | Instalar estos puertos: 66 | 67 | * devel/libconfig 68 | * devel/libexecinfo 69 | 70 | Entonces construir: 71 | 72 | $ env CC=clang CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./configure 73 | $ make 74 | 75 | #### Otros UNIX 76 | 77 | Si logras ejecutarlo en otros UNIX, por favor házmelo saber. 78 | 79 | 80 | ### Uso 81 | 82 | ./telegram -k 83 | 84 | 85 | Por defecto la clave pública se almacena en la misma carpeta con el nombre tg-server.pub o en /etc/telegram/server.pub, si no lo es, indica dónde encontrarlo: 86 | 87 | ./telegram -k tg-server.pub 88 | 89 | El Cliente soporta completamiento con TAB e historial de comandos. 90 | 91 | Peer se refiere al nombre del contacto o de diálogo y se puede acceder por completamiento con Tab. 92 | Para los contactos de usuario el peer es el Nombre Apellido con todos los espacios cambiados a guiones bajos. 93 | Para los chats es su título con todos los espacios cambiados a guiones bajos. 94 | Para los chats encriptados es Nombre Apellido con todos los espacios cambiados a guiones bajos. 95 | 96 | Si dos o más peers tienen el mismo nombre, una almohadilla y un número es añadido al nombre. (por ejemplo A_B,A_B#1,A_B#2 y así sucesivamente). 97 | 98 | ### Comandos soportados 99 | 100 | #### Mensajería 101 | 102 | 103 | * **msg** \ texto - envía el mensaje a este usuario. 104 | * **fwd** \ \ - reenviar un mensaje al usuario. Puedes ver los número de mensajes iniciando el Cliente con -N. 105 | * **chat_with_peer** \ - inicia un chat con este usuario. /exit o /quit para salir de este modo. 106 | * **add_contact** \ \ \ - intenta añadir este contacto a la lista de contactos. 107 | * **rename_contact** \ \ \ - intenta renombrar el contacto. Si tienes otro dispositivo será una pelea. 108 | * **mark_read** \ - marca todos los mensajes como recibidos de ese usuario. 109 | 110 | #### Multimedia 111 | 112 | * **send_photo** \ \ - manda una foto al usuario. 113 | * **send_video** \ \ - envia un video al usuario. 114 | * **send_text** \ \ - envia un archivo de texto como un mensaje en plano. 115 | * **load_photo**/load_video/load_video_thumb \ - carga foto/video indicado del directorio de descarga. 116 | * **view_photo**/view_video/view_video_thumb \ - carga foto/video indicado del directorio de descarga y lo abre con el visor por defecto del sistema. 117 | 118 | 119 | #### Opciones de chat de grupo 120 | 121 | * **chat_info** \ - imprime información del chat. 122 | * **chat_add_user** \ \ - agrega un usuario al chat. 123 | * **chat_del_user** \ \ - elimina un usuario del chat. 124 | * **rename_chat** \ \ - cambia el nombre al chat. 125 | 126 | #### Search 127 | 128 | * **search** \ patrón - busca el patrón indicado en los mensajes con ese usuario. 129 | * **global_search** patrón - busca el patrón indicado en todos los mensajes. 130 | 131 | #### Chat secreto 132 | 133 | * **create_secret_chat** \ - crea un chat secreto con el usuario indicado. 134 | * **visualize_key** \ - Muestra la clave de cifrado. Debes compararla con la del otro usuario. 135 | 136 | #### Estadísticas e información varia. 137 | 138 | * **user_info** \ - muestra información sobre el usuario. 139 | * **history** \ [limit] - muestra el historial (y la marca como leído). Limite por defecto = 40. 140 | * **dialog_list** - muestra información acerca del dialogo 141 | * **contact_list** - muestra información acerca de tu lista de contactos. 142 | * **suggested_contacts** - muestra información sobre sus contactos, tiene un máximo de amigos comunes. 143 | * **stats** - solo para depuración. 144 | * **show_license** - muestra la licencia GPLv2. 145 | * **help** - imprime esta ayuda. 146 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Telegram messenger CLI [![Build Status](https://travis-ci.org/vysheng/tg.png)](https://travis-ci.org/vysheng/tg) 2 | 3 | Command-line interface for [Telegram](http://telegram.org). Uses readline interface. 4 | 5 | ### API, Protocol documentation 6 | 7 | Documentation for Telegram API is available here: http://core.telegram.org/api 8 | 9 | Documentation for MTproto protocol is available here: http://core.telegram.org/mtproto 10 | 11 | ### Upgrading to version 1.0 12 | 13 | First of all, the binary is now in ./bin folder and is named telegram-cli. So be careful, not to use old binary. 14 | 15 | Second, config folder is now ${HOME}/.telegram-cli 16 | 17 | Third, database is not compatible with older versions, so you'll have to login again. 18 | 19 | Fourth, in peer_name '#' are substitued to '@'. (Not applied to appending of '#%d' in case of two peers having same name). 20 | 21 | ### Installation 22 | 23 | Clone GitHub Repository 24 | 25 | git clone --recursive https://github.com/vysheng/tg.git && cd tg 26 | 27 | ### Python Support 28 | 29 | Python support is currently limited to Python 2.7 or Python 3.1+. Other versions may work but are not tested. 30 | 31 | #### Linux and BSDs 32 | 33 | Install libs: readline, openssl and (if you want to use config) libconfig, liblua, python and libjansson. 34 | If you do not want to use them pass options --disable-libconfig, --disable-liblua, --disable-python and --disable-json respectively. 35 | 36 | On Ubuntu/Debian use: 37 | 38 | sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev libjansson-dev libpython-dev make 39 | 40 | On gentoo: 41 | 42 | sudo emerge -av sys-libs/readline dev-libs/libconfig dev-libs/openssl dev-lang/lua dev-libs/libevent dev-libs/jansson dev-lang/python 43 | 44 | On Fedora: 45 | 46 | sudo dnf install lua-devel openssl-devel libconfig-devel readline-devel libevent-devel libjansson-devel python-devel 47 | 48 | On Archlinux: 49 | 50 | yaourt -S telegram-cli-git 51 | 52 | On FreeBSD: 53 | 54 | pkg install libconfig libexecinfo lua52 python 55 | 56 | On OpenBSD: 57 | 58 | pkg_add libconfig libexecinfo lua python 59 | 60 | On openSUSE: 61 | 62 | sudo zypper in lua-devel libconfig-devel readline-devel libevent-devel libjansson-devel python-devel libopenssl-devel 63 | 64 | Then, 65 | 66 | ./configure 67 | make 68 | 69 | #### Other methods to install on linux 70 | 71 | On Gentoo: use ebuild provided. 72 | 73 | On Arch: https://aur.archlinux.org/packages/telegram-cli-git 74 | 75 | #### Mac OS X 76 | 77 | The client depends on [readline library](http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html) and [libconfig](http://www.hyperrealm.com/libconfig/), which are not included in OS X by default. You have to install these libraries manually. 78 | 79 | If using [Homebrew](http://brew.sh/): 80 | 81 | brew install libconfig readline lua python libevent jansson 82 | export CFLAGS="-I/usr/local/include -I/usr/local/Cellar/readline/6.3.8/include" 83 | export LDFLAGS="-L/usr/local/lib -L/usr/local/Cellar/readline/6.3.8/lib" 84 | ./configure && make 85 | 86 | Thanks to [@jfontan](https://github.com/vysheng/tg/issues/3#issuecomment-28293731) for this solution. 87 | 88 | If using [MacPorts](https://www.macports.org): 89 | 90 | sudo port install libconfig-hr 91 | sudo port install readline 92 | sudo port install lua51 93 | sudo port install python34 94 | sudo port install libevent 95 | export CFLAGS="-I/usr/local/include -I/opt/local/include -I/opt/local/include/lua-5.1" 96 | export LDFLAGS="-L/usr/local/lib -L/opt/local/lib -L/opt/local/lib/lua-5.1" 97 | ./configure && make 98 | 99 | Install these ports: 100 | 101 | * devel/libconfig 102 | * devel/libexecinfo 103 | * lang/lua52 104 | 105 | Then build: 106 | 107 | env CC=clang CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib LUA=/usr/local/bin/lua52 LUA_INCLUDE=-I/usr/local/include/lua52 LUA_LIB=-llua-5.2 ./configure 108 | make 109 | 110 | #### Other UNIX 111 | 112 | If you manage to launch it on other UNIX, please let me know. 113 | 114 | ### Contacts 115 | If you would like to ask a question, you can write to my telegram or to the github (or both). To contact me via telegram, you should use import_card method with argument 000653bf:0738ca5d:5521fbac:29246815:a27d0cda 116 | 117 | 118 | ### Usage 119 | 120 | bin/telegram-cli -k 121 | 122 | By default, the public key is stored in tg-server.pub in the same folder or in /etc/telegram-cli/server.pub. If not, specify where to find it: 123 | 124 | bin/telegram-cli -k tg-server.pub 125 | 126 | Client support TAB completion and command history. 127 | 128 | Peer refers to the name of the contact or dialog and can be accessed by TAB completion. 129 | For user contacts peer name is Name Lastname with all spaces changed to underscores. 130 | For chats it is it's title with all spaces changed to underscores 131 | For encrypted chats it is Name Lastname with all spaces changed to underscores. 132 | 133 | If two or more peers have same name, number is appended to the name. (for example A_B, A_B#1, A_B#2 and so on) 134 | 135 | ### Supported commands 136 | 137 | #### Messaging 138 | 139 | * **msg** \ Text - sends message to this peer 140 | * **fwd** \ \ - forward message to user. You can see message numbers starting client with -N 141 | * **chat_with_peer** \ starts one on one chat session with this peer. /exit or /quit to end this mode. 142 | * **add_contact** \ \ \ - tries to add contact to contact-list by phone 143 | * **rename_contact** \ \ \ - tries to rename contact. If you have another device it will be a fight 144 | * **mark_read** \ - mark read all received messages with peer 145 | * **delete_msg** \ - deletes message (not completly, though) 146 | * **restore_msg** \ - restores delete message. Impossible for secret chats. Only possible short time (one hour, I think) after deletion 147 | 148 | #### Multimedia 149 | 150 | * **send_photo** \ \ - sends photo to peer 151 | * **send_video** \ \ - sends video to peer 152 | * **send_text** \ \ - sends text file as plain messages 153 | * **load_photo**/load_video/load_video_thumb/load_audio/load_document/load_document_thumb \ - loads photo/video/audio/document to download dir 154 | * **view_photo**/view_video/view_video_thumb/view_audio/view_document/view_document_thumb \ - loads photo/video to download dir and starts system default viewer 155 | * **fwd_media** \ send media in your message. Use this to prevent sharing info about author of media (though, it is possible to determine user_id from media itself, it is not possible get access_hash of this user) 156 | * **set_profile_photo** \ - sets userpic. Photo should be square, or server will cut biggest central square part 157 | 158 | 159 | #### Group chat options 160 | 161 | * **chat_info** \ - prints info about chat 162 | * **chat_add_user** \ \ - add user to chat 163 | * **chat_del_user** \ \ - remove user from chat 164 | * **rename_chat** \ \ 165 | * **create_group_chat** \ \ \ \ ... - creates a groupchat with users, use chat_add_user to add more users 166 | * **chat_set_photo** \ \ - sets group chat photo. Same limits as for profile photos. 167 | 168 | #### Search 169 | 170 | * **search** \ pattern - searches pattern in messages with peer 171 | * **global_search** pattern - searches pattern in all messages 172 | 173 | #### Secret chat 174 | 175 | * **create_secret_chat** \ - creates secret chat with this user 176 | * **visualize_key** \ - prints visualization of encryption key. You should compare it to your partner's one 177 | * **set_ttl** \ \ - sets ttl to secret chat. Though client does ignore it, client on other end can make use of it 178 | * **accept_secret_chat** \ - manually accept secret chat (only useful when starting with -E key) 179 | 180 | #### Stats and various info 181 | 182 | * **user_info** \ - prints info about user 183 | * **history** \ [limit] - prints history (and marks it as read). Default limit = 40 184 | * **dialog_list** - prints info about your dialogs 185 | * **contact_list** - prints info about users in your contact list 186 | * **suggested_contacts** - print info about contacts, you have max common friends 187 | * **stats** - just for debugging 188 | * **show_license** - prints contents of GPLv2 189 | * **help** - prints this help 190 | * **get_self** - get our user info 191 | 192 | #### Card 193 | * **export_card** - print your 'card' that anyone can later use to import your contact 194 | * **import_card** \ - gets user by card. You can write messages to him after that. 195 | 196 | #### Other 197 | * **quit** - quit 198 | * **safe_quit** - wait for all queries to end then quit 199 | -------------------------------------------------------------------------------- /ax_python.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_python.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_PYTHON 8 | # 9 | # DESCRIPTION 10 | # 11 | # This macro does a complete Python development environment check. 12 | # 13 | # It recurses through several python versions (from 2.1 to 2.6 in this 14 | # version), looking for an executable. When it finds an executable, it 15 | # looks to find the header files and library. 16 | # 17 | # It sets PYTHON_BIN to the name of the python executable, 18 | # PYTHON_INCLUDE_DIR to the directory holding the header files, and 19 | # PYTHON_LIB to the name of the Python library. 20 | # 21 | # This macro calls AC_SUBST on PYTHON_BIN (via AC_CHECK_PROG), 22 | # PYTHON_INCLUDE_DIR and PYTHON_LIB. 23 | # 24 | # LICENSE 25 | # 26 | # Copyright (c) 2008 Michael Tindal 27 | # 28 | # This program is free software; you can redistribute it and/or modify it 29 | # under the terms of the GNU General Public License as published by the 30 | # Free Software Foundation; either version 2 of the License, or (at your 31 | # option) any later version. 32 | # 33 | # This program is distributed in the hope that it will be useful, but 34 | # WITHOUT ANY WARRANTY; without even the implied warranty of 35 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 36 | # Public License for more details. 37 | # 38 | # You should have received a copy of the GNU General Public License along 39 | # with this program. If not, see . 40 | # 41 | # As a special exception, the respective Autoconf Macro's copyright owner 42 | # gives unlimited permission to copy, distribute and modify the configure 43 | # scripts that are the output of Autoconf when processing the Macro. You 44 | # need not follow the terms of the GNU General Public License when using 45 | # or distributing such scripts, even though portions of the text of the 46 | # Macro appear in them. The GNU General Public License (GPL) does govern 47 | # all other use of the material that constitutes the Autoconf Macro. 48 | # 49 | # This special exception to the GPL applies to versions of the Autoconf 50 | # Macro released by the Autoconf Archive. When you make and distribute a 51 | # modified version of the Autoconf Macro, you may extend this special 52 | # exception to the GPL to apply to your modified version as well. 53 | 54 | #serial 14 55 | 56 | AC_DEFUN([AX_PYTHON], 57 | [AC_MSG_CHECKING(for python build information) 58 | AC_MSG_RESULT([]) 59 | for python in python3.5 python3.4 python3.3 python3.2 python3.1 python3 python2.7 python2.6 python2 python; do 60 | AC_CHECK_PROGS(PYTHON_BIN, [$python]) 61 | ax_python_bin=$PYTHON_BIN 62 | if test x$ax_python_bin != x; then 63 | AC_CHECK_LIB($ax_python_bin, main, ax_python_lib=$ax_python_bin, ax_python_lib=no) 64 | if test x$ax_python_lib == xno; then 65 | AC_CHECK_LIB(${ax_python_bin}m, main, ax_python_lib=${ax_python_bin}m, ax_python_lib=no) 66 | fi 67 | if test x$ax_python_lib == xno; then 68 | AC_CHECK_LIB(${ax_python_bin}mu, main, ax_python_lib=${ax_python_bin}mu, ax_python_lib=no) 69 | fi 70 | if test x$ax_python_lib != xno; then 71 | ax_python_header=`$ax_python_bin -c "from distutils.sysconfig import *; print(get_config_var('CONFINCLUDEPY'))"` 72 | if test x$ax_python_header != x; then 73 | break; 74 | fi 75 | fi 76 | fi 77 | unset ac_cv_prog_PYTHON_BIN 78 | unset PYTHON_BIN 79 | done 80 | if test x$ax_python_bin = x; then 81 | ax_python_bin=no 82 | fi 83 | if test x$ax_python_header = x; then 84 | ax_python_header=no 85 | fi 86 | if test x$ax_python_lib = x; then 87 | ax_python_lib=no 88 | fi 89 | 90 | AC_MSG_RESULT([ results of the Python check:]) 91 | AC_MSG_RESULT([ Binary: $ax_python_bin]) 92 | AC_MSG_RESULT([ Library: $ax_python_lib]) 93 | AC_MSG_RESULT([ Include Dir: $ax_python_header]) 94 | 95 | 96 | PYTHON_FOUND=yes 97 | if test x$ax_python_header != xno; then 98 | PYTHON_INCLUDE_DIR=$ax_python_header 99 | AC_SUBST(PYTHON_INCLUDE_DIR) 100 | else 101 | PYTHON_FOUND=no 102 | fi 103 | 104 | if test x$ax_python_lib != xno; then 105 | PYTHON_LIB=$ax_python_lib 106 | AC_SUBST(PYTHON_LIB) 107 | else 108 | PYTHON_FOUND=no 109 | fi 110 | AC_SUBST(PYTHON_FOUND) 111 | 112 | ])dnl 113 | -------------------------------------------------------------------------------- /bootstrap: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | aclocal 4 | autoheader 5 | automake --gnu --add-missing 6 | autoconf 7 | -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* disable extf queries */ 4 | #undef DISABLE_EXTF 5 | 6 | /* Use libevent v1 */ 7 | #undef EVENT_V1 8 | 9 | /* Use libevent v2 */ 10 | #undef EVENT_V2 11 | 12 | /* Define to 1 if you have the `alarm' function. */ 13 | #undef HAVE_ALARM 14 | 15 | /* Define to 1 if you have the header file. */ 16 | #undef HAVE_ARPA_INET_H 17 | 18 | /* Define to 1 if you have the `endpwent' function. */ 19 | #undef HAVE_ENDPWENT 20 | 21 | /* Define to 1 if you have the header file. */ 22 | #undef HAVE_EXECINFO_H 23 | 24 | /* Define to 1 if you have the header file. */ 25 | #undef HAVE_FCNTL_H 26 | 27 | /* Define to 1 if you have the header file. */ 28 | #undef HAVE_INTTYPES_H 29 | 30 | /* Define to 1 if you have the header file. */ 31 | #undef HAVE_LAUXLIB_H 32 | 33 | /* Define to 1 if you have the `config' library (-lconfig). */ 34 | #undef HAVE_LIBCONFIG 35 | 36 | /* Define to 1 if you have the `event' library (-levent). */ 37 | #undef HAVE_LIBEVENT 38 | 39 | /* Define to 1 if you have the `jansson' library (-ljansson). */ 40 | #undef HAVE_LIBJANSSON 41 | 42 | /* Define to 1 if you have the `m' library (-lm). */ 43 | #undef HAVE_LIBM 44 | 45 | /* Define to 1 if you have `z' library (-lz) */ 46 | #undef HAVE_LIBZ 47 | 48 | /* Define to 1 if you have the header file. */ 49 | #undef HAVE_LUACONF_H 50 | 51 | /* Define to 1 if you have the header file. */ 52 | #undef HAVE_LUALIB_H 53 | 54 | /* Define to 1 if you have the header file. */ 55 | #undef HAVE_LUA_H 56 | 57 | /* Define to 1 if you have the header file. */ 58 | #undef HAVE_MACH_MACH_H 59 | 60 | /* Define to 1 if your system has a GNU libc compatible `malloc' function, and 61 | to 0 otherwise. */ 62 | #undef HAVE_MALLOC 63 | 64 | /* Define to 1 if you have the header file. */ 65 | #undef HAVE_MALLOC_H 66 | 67 | /* Define to 1 if you have the `memmove' function. */ 68 | #undef HAVE_MEMMOVE 69 | 70 | /* Define to 1 if you have the header file. */ 71 | #undef HAVE_MEMORY_H 72 | 73 | /* Define to 1 if you have the `memset' function. */ 74 | #undef HAVE_MEMSET 75 | 76 | /* Define to 1 if you have the `mkdir' function. */ 77 | #undef HAVE_MKDIR 78 | 79 | /* Define to 1 if you have the header file. */ 80 | #undef HAVE_NETDB_H 81 | 82 | /* Define to 1 if you have the header file. */ 83 | #undef HAVE_NETINET_IN_H 84 | 85 | /* Define to 1 if your system has a GNU libc compatible `realloc' function, 86 | and to 0 otherwise. */ 87 | #undef HAVE_REALLOC 88 | 89 | /* Define to 1 if you have the `select' function. */ 90 | #undef HAVE_SELECT 91 | 92 | /* Define to 1 if you have the `socket' function. */ 93 | #undef HAVE_SOCKET 94 | 95 | /* Define to 1 if you have the header file. */ 96 | #undef HAVE_STDINT_H 97 | 98 | /* Define to 1 if you have the header file. */ 99 | #undef HAVE_STDLIB_H 100 | 101 | /* Define to 1 if you have the `strdup' function. */ 102 | #undef HAVE_STRDUP 103 | 104 | /* Define to 1 if you have the header file. */ 105 | #undef HAVE_STRINGS_H 106 | 107 | /* Define to 1 if you have the header file. */ 108 | #undef HAVE_STRING_H 109 | 110 | /* Define to 1 if you have the `strndup' function. */ 111 | #undef HAVE_STRNDUP 112 | 113 | /* Define to 1 if you have the header file. */ 114 | #undef HAVE_SYS_FILE_H 115 | 116 | /* Define to 1 if you have the header file. */ 117 | #undef HAVE_SYS_SOCKET_H 118 | 119 | /* Define to 1 if you have the header file. */ 120 | #undef HAVE_SYS_STAT_H 121 | 122 | /* Define to 1 if you have the header file. */ 123 | #undef HAVE_SYS_TYPES_H 124 | 125 | /* Define to 1 if you have the header file. */ 126 | #undef HAVE_TERMIOS_H 127 | 128 | /* Define to 1 if you have the `uname' function. */ 129 | #undef HAVE_UNAME 130 | 131 | /* Define to 1 if you have the header file. */ 132 | #undef HAVE_UNISTD_H 133 | 134 | /* Define to 1 if the system has the `__builtin_bswap32' built-in function */ 135 | #undef HAVE___BUILTIN_BSWAP32 136 | 137 | /* Define to the address where bug reports for this package should be sent. */ 138 | #undef PACKAGE_BUGREPORT 139 | 140 | /* Define to the full name of this package. */ 141 | #undef PACKAGE_NAME 142 | 143 | /* Define to the full name and version of this package. */ 144 | #undef PACKAGE_STRING 145 | 146 | /* Define to the one symbol short name of this package. */ 147 | #undef PACKAGE_TARNAME 148 | 149 | /* Define to the home page for this package. */ 150 | #undef PACKAGE_URL 151 | 152 | /* Define to the version of this package. */ 153 | #undef PACKAGE_VERSION 154 | 155 | /* Use custom prog name */ 156 | #undef PROG_NAME 157 | 158 | /* Define to 1 if you have the ANSI C header files. */ 159 | #undef STDC_HEADERS 160 | 161 | /* use json */ 162 | #undef USE_JSON 163 | 164 | /* use lua */ 165 | #undef USE_LUA 166 | 167 | /* use python */ 168 | #undef USE_PYTHON 169 | 170 | /* fixed for correct valgrind work */ 171 | #undef VALGRIND_FIXES 172 | 173 | /* Define to `int' if doesn't define. */ 174 | #undef gid_t 175 | 176 | /* Define to `__inline__' or `__inline' if that's what the C compiler 177 | calls it, or to nothing if 'inline' is not supported under any name. */ 178 | #ifndef __cplusplus 179 | #undef inline 180 | #endif 181 | 182 | /* Define to rpl_malloc if the replacement function should be used. */ 183 | #undef malloc 184 | 185 | /* Define to rpl_realloc if the replacement function should be used. */ 186 | #undef realloc 187 | 188 | /* Define to `unsigned int' if does not define. */ 189 | #undef size_t 190 | 191 | /* Define to `int' if doesn't define. */ 192 | #undef uid_t 193 | -------------------------------------------------------------------------------- /config.sample: -------------------------------------------------------------------------------- 1 | # This is an empty config file 2 | # Feel free to put something here 3 | 4 | default_profile = "binlog"; 5 | 6 | test_dc1 = { 7 | config_directory = ".telegram/test_dc1"; 8 | test = true; 9 | msg_num = true; 10 | binlog_enabled = true; 11 | }; 12 | 13 | binlog = { 14 | config_directory = ".telegram/binlog"; 15 | test = false; 16 | msg_num = true; 17 | binlog_enabled = true; 18 | log_level = 2; 19 | }; 20 | 21 | binlog_mts = { 22 | config_directory = ".telegram/binlog_mts"; 23 | test = false; 24 | msg_num = true; 25 | binlog_enabled = true; 26 | log_level = 2; 27 | }; 28 | 29 | mega = { 30 | config_directory = ".telegram/mega"; 31 | test = false; 32 | msg_num = true; 33 | binlog_enabled = true; 34 | log_level = 2; 35 | }; 36 | 37 | new = { 38 | config_directory = ".telegram/new"; 39 | test = false; 40 | msg_num = true; 41 | }; 42 | 43 | production = { 44 | config_directory = ".telegram/production"; 45 | test = false; 46 | msg_num = true; 47 | }; 48 | 49 | test = { 50 | config_directory = ".telegram/test"; 51 | test = true; 52 | msg_num = true; 53 | }; 54 | 55 | test1 = { 56 | config_directory = ".telegram/test1"; 57 | msg_num = true; 58 | binlog_enabled = true; 59 | }; 60 | 61 | test2 = { 62 | config_directory = ".telegram/test2"; 63 | msg_num = true; 64 | binlog_enabled = true; 65 | }; 66 | 67 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ([2.68]) 2 | AC_INIT([telegram-cli], [1.0]) 3 | AC_CONFIG_SRCDIR([config.h.in]) 4 | AC_CONFIG_HEADERS([config.h]) 5 | 6 | m4_include([ax_lua.m4]) 7 | m4_include([ax_python.m4]) 8 | m4_include([m4_ax_check_openssl.m4]) 9 | m4_include([m4_ax_check_zlib.m4]) 10 | m4_include([m4-ax_gcc_builtin.m4]) 11 | 12 | # Checks for programs. 13 | AC_PROG_CC 14 | 15 | # BSD locations for headers and libraries from packages, Linux locations for self-compiled stuff. 16 | CPPFLAGS="$CPPFLAGS -I/usr/local/include" 17 | LDFLAGS="$LDFLAGS -L/usr/local/lib" 18 | 19 | # Checks for libraries. 20 | AC_CHECK_LIB([m], [sqrt]) 21 | AC_SEARCH_LIBS([clock_gettime], [rt]) 22 | AC_SEARCH_LIBS([backtrace], [execinfo]) 23 | AC_CHECK_LIB([event], [event_base_new], [], [AC_MSG_ERROR([no libevent found])]) 24 | 25 | EVENT_VER="" 26 | 27 | AC_CHECK_HEADER(event2/event.h, [AC_DEFINE([EVENT_V2], [1], [Use libevent v2])], [ 28 | AC_CHECK_HEADER(event.h, [AC_DEFINE([EVENT_V1], [1], [Use libevent v1])], [AC_MSG_ERROR([no libevent found])]) 29 | ]) 30 | 31 | EXTRA_LIBS="" 32 | 33 | # OPENSSL_INCLUDES to the include directives required 34 | # OPENSSL_LIBS to the -l directives required 35 | # OPENSSL_LDFLAGS to the -L or -R flags required 36 | 37 | AX_CHECK_OPENSSL(,[AC_MSG_ERROR([No openssl found])]) 38 | AX_CHECK_ZLIB(, [AC_MSG_ERROR([No zlib found])]) 39 | 40 | AC_CHECK_LIB([readline], [rl_save_prompt], [ EXTRA_LIBS="${EXTRA_LIBS} -lreadline" ; ], [AC_MSG_ERROR([no libreadline found])]) 41 | 42 | AC_MSG_CHECKING([for libconfig]) 43 | AC_ARG_ENABLE(libconfig,[--enable-libconfig/--disable-libconfig], 44 | [ 45 | if test "x$enableval" = "xno" ; then 46 | AC_MSG_RESULT([disabled]) 47 | else 48 | AC_MSG_RESULT([enabled]) 49 | AC_CHECK_LIB([config],[config_init],[],AC_MSG_ERROR([No libconfig found. Try --disable-libconfig])) 50 | fi 51 | ],[ 52 | AC_MSG_RESULT([enabled]) 53 | AC_CHECK_LIB([config],[config_init],[],AC_MSG_ERROR([No libconfig found. Try --disable-libconfig])) 54 | ]) 55 | 56 | AC_ARG_ENABLE(extf,[--enable-extf/--disable-extf], 57 | [ 58 | if test "x$enableval" = "xno" ; then 59 | AC_DEFINE([DISABLE_EXTF],[1],[disable extf queries]) 60 | fi 61 | ],[ 62 | ]) 63 | 64 | AC_MSG_CHECKING([for liblua]) 65 | AC_ARG_ENABLE(liblua,[--enable-liblua/--disable-liblua], 66 | [ 67 | if test "x$enableval" = "xno" ; then 68 | AC_MSG_RESULT([disabled]) 69 | else 70 | AC_MSG_RESULT([enabled]) 71 | AX_PROG_LUA([],[], 72 | [ 73 | AX_LUA_HEADERS([],[AC_MSG_ERROR([No lua headers found. Try --disable-liblua])]) 74 | AX_LUA_LIBS([],[AC_MSG_ERROR([No lua libs found. Try --disable-liblua])]) 75 | [EXTRA_LIBS="${EXTRA_LIBS} ${LUA_LIB}" ; ] 76 | [CPPFLAGS="${CPPFLAGS} ${LUA_INCLUDE}" ; ] 77 | AC_DEFINE(USE_LUA,1,[use lua]) 78 | ], 79 | [ 80 | AC_MSG_ERROR([No lua found. Try --disable-liblua]) 81 | ]) 82 | fi 83 | ],[ 84 | AC_MSG_RESULT([enabled]) 85 | AX_PROG_LUA([],[], 86 | [ 87 | AX_LUA_HEADERS([],[AC_MSG_ERROR([No lua headers found. Try --disable-liblua])]) 88 | AX_LUA_LIBS([],[AC_MSG_ERROR([No lua libs found. Try --disable-liblua])]) 89 | [EXTRA_LIBS="${EXTRA_LIBS} ${LUA_LIB}" ; ] 90 | [CPPFLAGS="${CPPFLAGS} ${LUA_INCLUDE}" ; ] 91 | AC_DEFINE(USE_LUA,1,[use lua]) 92 | ], 93 | [ 94 | AC_MSG_ERROR([No lua found. Try --disable-liblua]) 95 | ]) 96 | ]) 97 | 98 | AC_MSG_CHECKING([for python]) 99 | AC_ARG_ENABLE(python,[--enable-python/--disable-python], 100 | [ 101 | if test "x$enableval" = "xno" ; then 102 | AC_MSG_RESULT([disabled]) 103 | else 104 | AC_MSG_RESULT([enabled]) 105 | 106 | AX_PYTHON() 107 | AC_SUBST([PYTHON_FOUND]) 108 | if test $PYTHON_FOUND = no ; then 109 | AC_MSG_ERROR([No supported python lib version found. Try --disable-python]) 110 | else 111 | AC_SUBST([PYTHON_LIBS]) 112 | AC_SUBST([PYTHON_CFLAGS]) 113 | EXTRA_LIBS="${EXTRA_LIBS} -l${PYTHON_LIB}" 114 | CPPFLAGS="${CPPFLAGS} -I${PYTHON_INCLUDE_DIR}" 115 | AC_DEFINE(USE_PYTHON,1,[use python]) 116 | fi 117 | fi 118 | ],[ 119 | AC_MSG_RESULT([enabled]) 120 | 121 | AX_PYTHON() 122 | AC_SUBST([PYTHON_FOUND]) 123 | if test $PYTHON_FOUND = no ; then 124 | AC_MSG_ERROR([No supported python lib version found. Try --disable-python]) 125 | else 126 | AC_SUBST([PYTHON_LIBS]) 127 | AC_SUBST([PYTHON_CFLAGS]) 128 | EXTRA_LIBS="${EXTRA_LIBS} -l${PYTHON_LIB}" 129 | CPPFLAGS="${CPPFLAGS} -I${PYTHON_INCLUDE_DIR}" 130 | AC_DEFINE(USE_PYTHON,1,[use python]) 131 | fi 132 | ]) 133 | 134 | 135 | 136 | AC_MSG_CHECKING([for libjansson]) 137 | AC_ARG_ENABLE(json,[--enable-json/--disable-json], 138 | [ 139 | if test "x$enableval" = "xno" ; then 140 | AC_MSG_RESULT([disabled]) 141 | else 142 | AC_MSG_RESULT([enabled]) 143 | AC_CHECK_LIB([jansson],[json_array_set_new],[],AC_MSG_ERROR([No libjansson found. Try --disable-json])) 144 | AC_DEFINE(USE_JSON,1,[use json]) 145 | fi 146 | ],[ 147 | AC_MSG_RESULT([enabled]) 148 | AC_CHECK_LIB([jansson],[json_array_set_new],[],AC_MSG_ERROR([No libjansson found. Try --disable-json])) 149 | AC_DEFINE(USE_JSON,1,[use json]) 150 | ]) 151 | 152 | #check for custom prog name 153 | AC_MSG_CHECKING([progname]) 154 | AC_ARG_WITH(progname,[--with-progname=], 155 | [ 156 | if test "x$with_progname" = "xno" ; then 157 | AC_MSG_RESULT([default]) 158 | elif test "x$with_progname" = "xyes" ; then 159 | AC_MSG_RESULT([default]) 160 | else 161 | AC_MSG_RESULT(["$with_progname"]) 162 | AC_DEFINE_UNQUOTED([PROG_NAME], ["$with_progname"], [Use custom prog name]) 163 | fi 164 | ],[ 165 | AC_MSG_RESULT([default]) 166 | ]) 167 | 168 | AC_ARG_ENABLE(valgrind,[--enable-valgrind/--disable-valgrind], 169 | [ 170 | if test "x$enableval" = "xyes" ; then 171 | AC_CHECK_HEADER(valgrind/memcheck.h, [AC_DEFINE([VALGRIND_FIXES], [1], [fixed for correct valgrind work])], [ 172 | ]) 173 | fi 174 | ],[ 175 | ]) 176 | 177 | 178 | # Checks for header files. 179 | AC_CHECK_HEADERS([execinfo.h fcntl.h malloc.h netdb.h stdlib.h string.h unistd.h arpa/inet.h mach/mach.h netinet/in.h sys/file.h sys/socket.h termios.h]) 180 | 181 | # Checks for typedefs, structures, and compiler characteristics. 182 | AC_TYPE_SIZE_T 183 | AC_TYPE_UID_T 184 | AC_C_INLINE 185 | 186 | # Checks for library functions. 187 | AC_FUNC_MALLOC 188 | AC_FUNC_REALLOC 189 | AC_CHECK_FUNCS([alarm endpwent memset memmove mkdir select socket strdup strndup uname]) 190 | 191 | AX_GCC_BUILTIN(__builtin_bswap32) 192 | 193 | AC_SUBST(EXTRA_LIBS) 194 | AC_CONFIG_FILES([Makefile]) 195 | AC_OUTPUT 196 | 197 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | telegram-cli (1.0.6-1) unstable; urgency=low 2 | 3 | * Upstream update version 4 | * Inpliment -e option 5 | 6 | -- Steve Illichevsky Sat, 11 Oct 2014 08:47:07 +0400 7 | 8 | telegram-cli (1.0.5.1-1) unstable; urgency=low 9 | 10 | * Initial release 11 | 12 | -- Steve Illichevsky Sun, 05 Oct 2014 09:37:06 +0400 13 | -------------------------------------------------------------------------------- /debian/clean: -------------------------------------------------------------------------------- 1 | Makefile -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: telegram-cli 2 | Section: net 3 | Priority: extra 4 | Maintainer: Steve Illichevsky 5 | Build-Depends: debhelper (>= 8.0.0), 6 | autotools-dev, 7 | autoconf-archive, 8 | libreadline-dev, 9 | libconfig-dev, 10 | libssl-dev, 11 | lua5.1, 12 | liblua5.1-dev, 13 | lua-lgi, 14 | libevent-dev 15 | Standards-Version: 3.9.5 16 | Homepage: https://github.com/vysheng/tg 17 | Vcs-Git: git://github.com/vysheng/tg.git 18 | Vcs-Browser: https://github.com/vysheng/tg 19 | 20 | Package: telegram-cli 21 | Architecture: any 22 | Depends: ${shlibs:Depends}, ${misc:Depends} 23 | Description: Command-line interface for Telegram messenger 24 | Telegram messenger is a cloud-based instant messaging designed for 25 | smart phones and similar to Whatsapp but more flexible, and 26 | powerful. You can send messages, photos, videos and documents to 27 | people who are in your phone contacts (and have Telegram). Telegram 28 | also supports secret chats whose provide a private (encrypted) way of 29 | communication. 30 | . 31 | This package contains a command-line based client for Telegram with 32 | the following features: 33 | * Colored terminal messages. 34 | * Message management: history, stats, etc. 35 | * Group chat: create and manage groups. 36 | * Secret chat: secured and encrypted conversations. 37 | * Contact management: add/edit/remove contacts. 38 | * Multimedia support: send/load photos and videos. 39 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: http://dep.debian.net/deps/dep5 2 | Upstream-Name: telegram-cli 3 | Source: https://github.com/vysheng/tg 4 | 5 | Files: * 6 | Copyright: 2013-2014 Vitaly Valtman 7 | License: GPL-3.0+ 8 | 9 | Files: debian/* 10 | Copyright: 2014 Steve Illichevsky 11 | License: GPL-3.0+ 12 | 13 | License: GPL-3.0+ 14 | This program is free software: you can redistribute it and/or modify 15 | it under the terms of the GNU General Public License as published by 16 | the Free Software Foundation, either version 3 of the License, or 17 | (at your option) any later version. 18 | . 19 | This package is distributed in the hope that it will be useful, 20 | but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | GNU General Public License for more details. 23 | . 24 | You should have received a copy of the GNU General Public License 25 | along with this program. If not, see . 26 | . 27 | On Debian systems, the complete text of the GNU General 28 | Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". 29 | 30 | # Please also look if there are files or directories which have a 31 | # different copyright/license attached and list them here. 32 | -------------------------------------------------------------------------------- /debian/docs: -------------------------------------------------------------------------------- 1 | README.es 2 | README-LUA 3 | README.md 4 | #telegram-cli.8 5 | -------------------------------------------------------------------------------- /debian/install: -------------------------------------------------------------------------------- 1 | bin/telegram-cli usr/bin 2 | server.pub etc/telegram-cli 3 | 4 | #bin/telegram-cli usr/share/telegram-daemon/bin 5 | #start-telegram-daemon /usr/share/telegram-daemon/bin 6 | test.lua var/lib/telegram-cli/ 7 | #telegram-daemon etc/init.d 8 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | # Sample debian/rules that uses debhelper. 4 | # This file was originally written by Joey Hess and Craig Small. 5 | # As a special exception, when this file is copied by dh-make into a 6 | # dh-make output file, you may use that output file without restriction. 7 | # This special exception was added by Craig Small in version 0.37 of dh-make. 8 | 9 | # Uncomment this to turn on verbose mode. 10 | export DH_VERBOSE=1 11 | 12 | VERSION=$(shell dpkg-parsechangelog | sed -n 's/^Version: //p' | cut -f1 -d'-') 13 | PACKAGE_NAME=$(shell dpkg-parsechangelog | sed -n 's/^Source: //p') 14 | %: 15 | dh $@ --with autotools-dev 16 | build-orig: 17 | mkdir -p $(PACKAGE_NAME)-$(VERSION) 18 | tar --exclude=ax_lua.m4 --exclude=debian --exclude=\.pc \ 19 | --exclude=$(PACKAGE_NAME)-$(VERSION) -cf - . \ 20 | | ( cd $(PACKAGE_NAME)-$(VERSION) && tar xf - ) 21 | tar -cf ../$(PACKAGE_NAME)_$(VERSION).orig.tar $(PACKAGE_NAME)-$(VERSION) 22 | $(RM) -r $(PACKAGE_NAME)-$(VERSION) 23 | xz ../$(PACKAGE_NAME)_$(VERSION).orig.tar 24 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /debian/telegram-cli.8: -------------------------------------------------------------------------------- 1 | .TH man 8 "02 October 2014" "1.0.5.1" "telegram-cli man page" 2 | .SH NAME 3 | telegram-cli \- Command-line interface for Telegram messenger 4 | .SH SYNOPSIS 5 | telegram-cli -k [keyfile] 6 | .SH DESCRIPTION 7 | Telegram messenger is a cloud-based instant messaging designed for 8 | smart phones and similar to Whatsapp but more flexible, and 9 | powerful. You can send messages, photos, videos and documents to 10 | people who are in your phone contacts (and have Telegram). Telegram 11 | also supports secret chats whose provide a private (encrypted) way of 12 | communication. 13 | . 14 | This package contains a command-line based client for Telegram with 15 | the following features: 16 | * Colored terminal messages. 17 | * Message management: history, stats, etc. 18 | * Group chat: create and manage groups. 19 | * Secret chat: secured and encrypted conversations. 20 | * Contact management: add/edit/remove contacts. 21 | * Multimedia support: send/load photos and videos. 22 | .SH OPTIONS 23 | Telegram-cli Usage 24 | -u specify username (would not be asked during authorization) 25 | -k specify location of public key (possible multiple entries) 26 | -v increase verbosity (0-ERROR 1-WARNIN 2-NOTICE 3+-DEBUG-levels) 27 | -N message num mode 28 | -c config file name 29 | -p use specified profile 30 | -l log level 31 | -f during authorization fetch all messages since registration 32 | -E diable auto accept of encrypted chats 33 | -s lua script file 34 | -W send dialog_list query and wait for answer before reading input 35 | -C disable color output 36 | -R disable readline 37 | -d daemon mode 38 | -L log file name 39 | -U change uid after start 40 | -G change gid after start 41 | -D disable output 42 | -P port to listen for input commands 43 | -S unix socket to create 44 | .SH SEE ALSO 45 | .SH BUGS 46 | No known bugs. 47 | .SH AUTHOR 48 | Vitaliy Vatman (-@-) -------------------------------------------------------------------------------- /debian/telegram-cli.logrotate: -------------------------------------------------------------------------------- 1 | /var/lib/telegram-cli/*.log { 2 | daily 3 | missingok 4 | rotate 31 5 | compress 6 | notifempty 7 | nocreate 8 | } 9 | -------------------------------------------------------------------------------- /debian/telegram-cli.manpages: -------------------------------------------------------------------------------- 1 | debian/telegram-cli.8 2 | -------------------------------------------------------------------------------- /debian/telegram-cli.postinst.debhelper: -------------------------------------------------------------------------------- 1 | # Automatically added by dh_installinit 2 | if [ -e "/etc/init/telegram-cli.conf" ]; then 3 | invoke-rc.d telegram-cli start || exit $? 4 | fi 5 | # End automatically added section 6 | # Automatically added by dh_installinit 7 | update-rc.d -f telegram-cli remove >/dev/null || exit $? 8 | # End automatically added section 9 | -------------------------------------------------------------------------------- /debian/telegram-cli.preinst: -------------------------------------------------------------------------------- 1 | adduser --system --home /var/lib/telegram-cli --gecos "Telegram Daemon User" --group telegramd -------------------------------------------------------------------------------- /debian/telegram-cli.preinst.debhelper: -------------------------------------------------------------------------------- 1 | # Automatically added by dh_installinit 2 | if [ "$1" = install ] || [ "$1" = upgrade ]; then 3 | if [ -e "/etc/init.d/telegram-cli" ] && [ ! -L "/etc/init.d/telegram-cli" ]; then 4 | if [ "`md5sum \"/etc/init.d/telegram-cli\" | sed -e \"s/ .*//\"`" != \ 5 | "`dpkg-query -W -f='${Conffiles}' telegram-cli | sed -n -e \"\\\\' /etc/init.d/telegram-cli '{s/ obsolete$//;s/.* //p}\"`" ] 6 | then 7 | echo "Obsolete conffile /etc/init.d/telegram-cli has been modified by you, renaming to .dpkg-bak" 8 | mv -f "/etc/init.d/telegram-cli" "/etc/init.d/telegram-cli.dpkg-bak" 9 | else 10 | rm -f "/etc/init.d/telegram-cli" 11 | fi 12 | fi 13 | fi 14 | # End automatically added section 15 | -------------------------------------------------------------------------------- /debian/telegram-cli.prerm: -------------------------------------------------------------------------------- 1 | # Automatically added by dh_installinit 2 | if [ -e "/etc/init/telegram-cli.conf" ]; then 3 | invoke-rc.d telegram-cli stop || exit $? 4 | fi 5 | # End automatically added section 6 | 7 | deluser --remove-home telegramd -------------------------------------------------------------------------------- /debian/telegram-cli.prerm.debhelper: -------------------------------------------------------------------------------- 1 | # Automatically added by dh_installinit 2 | if [ -e "/etc/init/telegram-cli.conf" ]; then 3 | invoke-rc.d telegram-cli stop || exit $? 4 | fi 5 | # End automatically added section 6 | -------------------------------------------------------------------------------- /debian/telegram-cli.upstart: -------------------------------------------------------------------------------- 1 | # Service 2 | 3 | setuid telegramd 4 | setgid telegramd 5 | 6 | script 7 | exec /usr/bin/telegram-cli -s /var/lib/telegram-cli/test.lua -W -d -C -vvvv -l 0 -L /var/lib/telegram-cli/telegram-cli.log -P 8002 8 | # This example for Daemon wich keep log in his home directory 9 | # This daemon can listen localhost:8002 tcp port 10 | end script 11 | -------------------------------------------------------------------------------- /debian/watch: -------------------------------------------------------------------------------- 1 | version=3 2 | 3 | opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/tg-$1\.tar\.gz/ \ 4 | https://github.com/vysheng/tg/tags .*/v?(\d\S*)\.tar\.gz 5 | -------------------------------------------------------------------------------- /event-old.h: -------------------------------------------------------------------------------- 1 | #ifndef __EVENT_OLD_H__ 2 | #define __EVENT_OLD_H__ 3 | 4 | #include 5 | #include 6 | 7 | #define BEV_EVENT_READ EVBUFFER_READ 8 | #define BEV_EVENT_WRITE EVBUFFER_WRITE 9 | #define BEV_EVENT_EOF EVBUFFER_EOF 10 | #define BEV_EVENT_ERROR EVBUFFER_ERROR 11 | #define BEV_EVENT_TIMEOUT EVBUFFER_TIMEOUT 12 | 13 | typedef int evutil_socket_t; 14 | 15 | static inline struct event *event_new (struct event_base *base, int fd, int what, void(*callback)(int, short, void *), void *arg) __attribute__ ((unused)); 16 | static inline struct event *event_new (struct event_base *base, int fd, int what, void(*callback)(int, short, void *), void *arg) { 17 | struct event *ev = malloc (sizeof (*ev)); 18 | event_set (ev, fd, what, callback, arg); 19 | event_base_set (base, ev); 20 | return ev; 21 | } 22 | 23 | static inline struct event *evtimer_new (struct event_base *base, void(*callback)(int, short, void *), void *arg) __attribute__ ((unused)); 24 | static inline struct event *evtimer_new (struct event_base *base, void(*callback)(int, short, void *), void *arg) { 25 | struct event *ev = malloc (sizeof (*ev)); 26 | event_set (ev, -1, 0, callback, arg); 27 | event_base_set (base, ev); 28 | return ev; 29 | } 30 | 31 | static void event_free (struct event *ev) __attribute__ ((unused)); 32 | static void event_free (struct event *ev) { 33 | event_del (ev); 34 | free (ev); 35 | } 36 | 37 | static struct bufferevent *bufferevent_socket_new (struct event_base *base, int fd, int flags) __attribute__ ((unused)); 38 | static struct bufferevent *bufferevent_socket_new (struct event_base *base, int fd, int flags) { 39 | assert (!flags); 40 | struct bufferevent *bev = bufferevent_new(fd, 0, 0, 0, 0); 41 | bufferevent_base_set (base, bev); 42 | return bev; 43 | } 44 | 45 | static inline void *event_get_callback_arg(const struct event *ev) { 46 | return ev->ev_arg; 47 | } 48 | #endif 49 | -------------------------------------------------------------------------------- /gentoo/net-im/telegram-cli/Manifest: -------------------------------------------------------------------------------- 1 | EBUILD telegram-cli-9999.ebuild 926 SHA256 d9c959af30c77afe8e6b1cee162e5362edfb9da6980b53ef71c3cae5f621bf05 SHA512 eeef9e1d2d7cd0b600be0d44de39e9c38207d5fb8f675e7ba239c1e907ab5df6e198a5810e6bb08445c7c2a98cc50bf78554f52b4c7c0534f111bfa3256b8186 WHIRLPOOL 700a6fd9930074ec36dfb3f4b248a43e6d7c0ab0f97ed6b56343e79fb15a087d99eb52ad67a818e67cbb1a848d65cc395f60b319f3fda60c87c10e9f4e132838 2 | -------------------------------------------------------------------------------- /gentoo/net-im/telegram-cli/telegram-cli-9999.ebuild: -------------------------------------------------------------------------------- 1 | # Copyright 1999-2013 Gentoo Foundation 2 | # Distributed under the terms of the GNU General Public License v2 3 | # $Header: $ 4 | 5 | EAPI=5 6 | 7 | EGIT_REPO_URI="https://github.com/vysheng/tg.git" 8 | EGIT_BRANCH="master" 9 | EGIT_HAS_SUBMODULES=1 10 | inherit git-2 11 | IUSE="+lua +json +python" 12 | DESCRIPTION="Command line interface client for Telegram" 13 | HOMEPAGE="https://github.com/vysheng/tg" 14 | LICENSE="GPL-2" 15 | SLOT="0" 16 | KEYWORDS="~amd64 ~x86" 17 | 18 | DEPEND="sys-libs/zlib 19 | sys-libs/readline 20 | dev-libs/libconfig 21 | dev-libs/openssl 22 | dev-libs/libevent 23 | lua? ( dev-lang/lua ) 24 | json? ( dev-libs/jansson ) 25 | python? ( dev-lang/python )" 26 | 27 | src_unpack() { 28 | git-2_src_unpack 29 | cd $EGIT_SOURCEDIR 30 | git submodule update --init --recursive 31 | } 32 | 33 | src_configure() { 34 | econf $(use_enable lua liblua ) 35 | econf $(use_enable python python ) 36 | econf $(use_enable json json ) 37 | } 38 | 39 | src_install() { 40 | newbin bin/telegram-cli telegram-cli 41 | 42 | insinto /etc/telegram-cli/ 43 | newins tg-server.pub server.pub 44 | } 45 | -------------------------------------------------------------------------------- /interface.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of telegram-cli. 3 | 4 | Telegram-cli is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | Telegram-cli is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this telegram-cli. If not, see . 16 | 17 | Copyright Vitaly Valtman 2013-2015 18 | */ 19 | #ifndef __INTERFACE_H__ 20 | #define __INTERFACE_H__ 21 | #include 22 | #include 23 | 24 | #define COLOR_RED "\033[0;31m" 25 | #define COLOR_REDB "\033[1;31m" 26 | #define COLOR_NORMAL "\033[0m" 27 | #define COLOR_GREEN "\033[32;1m" 28 | #define COLOR_GREY "\033[37;1m" 29 | #define COLOR_YELLOW "\033[33;1m" 30 | #define COLOR_BLUE "\033[34;1m" 31 | #define COLOR_MAGENTA "\033[35;1m" 32 | #define COLOR_CYAN "\033[36;1m" 33 | #define COLOR_LCYAN "\033[0;36m" 34 | 35 | #define COLOR_INVERSE "\033[7m" 36 | 37 | char *get_default_prompt (void); 38 | char *complete_none (const char *text, int state); 39 | char **complete_text (char *text, int start, int end); 40 | void interpreter (char *line); 41 | void interpreter_ex (char *line, void *ex); 42 | 43 | void rprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))); 44 | void logprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))); 45 | 46 | #define vlogprintf(v,...) \ 47 | do { \ 48 | if (TLS->verbosity >= (v)) {\ 49 | logprintf (__VA_ARGS__);\ 50 | }\ 51 | } while (0);\ 52 | 53 | 54 | //void hexdump (int *in_ptr, int *in_end); 55 | 56 | struct bufferevent; 57 | struct in_ev { 58 | struct bufferevent *bev; 59 | char in_buf[4096]; 60 | int in_buf_pos; 61 | int refcnt; 62 | int error; 63 | int fd; 64 | }; 65 | 66 | 67 | struct tgl_message; 68 | struct in_ev; 69 | void print_message (struct in_ev *ev, struct tgl_message *M); 70 | void print_chat_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *C); 71 | void print_user_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *U); 72 | void print_encr_chat_name_full (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *C); 73 | void print_encr_chat_name (struct in_ev *ev, tgl_peer_id_t id, tgl_peer_t *C); 74 | //void print_media (struct tgl_message_media *M); 75 | // 76 | void pop_color (void); 77 | void push_color (const char *color); 78 | void print_start (void); 79 | void print_end (void); 80 | void print_date_full (struct in_ev *ev, long t); 81 | void print_date (struct in_ev *ev, long t); 82 | 83 | void play_sound (void); 84 | void update_prompt (void); 85 | void set_interface_callbacks (void); 86 | #endif 87 | -------------------------------------------------------------------------------- /json-tg.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #ifdef USE_JSON 3 | 4 | #include 5 | #include "json-tg.h" 6 | #include 7 | #include 8 | #include 9 | //format time: 10 | #include 11 | 12 | #ifndef json_boolean 13 | #define json_boolean(val) ((val) ? json_true() : json_false()) 14 | #endif 15 | 16 | extern struct tgl_state *TLS; 17 | 18 | void json_pack_peer_type (json_t *res, tgl_peer_id_t id) { 19 | int x = tgl_get_peer_type (id); 20 | switch (x) { 21 | case TGL_PEER_USER: 22 | assert (json_object_set (res, "type", json_string ("user")) >= 0); 23 | break; 24 | case TGL_PEER_CHAT: 25 | assert (json_object_set (res, "type", json_string ("chat")) >= 0); 26 | break; 27 | case TGL_PEER_ENCR_CHAT: 28 | assert (json_object_set (res, "type", json_string ("encr_chat")) >= 0); 29 | break; 30 | default: 31 | assert (0); 32 | } 33 | } 34 | 35 | int str_format_time(long when, char* string) 36 | { 37 | struct tm *tm = localtime ((void *)&when); 38 | return sprintf (string, "%04d-%02d-%02d %02d:%02d:%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); 39 | } 40 | 41 | void json_pack_user (json_t *res, tgl_peer_t *P) { 42 | if (P->user.first_name) { 43 | assert (json_object_set (res, "first_name", json_string (P->user.first_name)) >= 0); 44 | } 45 | 46 | if (P->user.status.when) { 47 | static char s[20]; 48 | str_format_time(P->user.status.when, s); 49 | assert (json_object_set (res, "when", json_string (s)) >= 0); 50 | } 51 | 52 | if (P->user.last_name) { 53 | assert (json_object_set (res, "last_name", json_string (P->user.last_name)) >= 0); 54 | } 55 | if (P->user.real_first_name) { 56 | assert (json_object_set (res, "real_first_name", json_string (P->user.real_first_name)) >= 0); 57 | } 58 | if (P->user.real_last_name) { 59 | assert (json_object_set (res, "real_last_name", json_string (P->user.real_last_name)) >= 0); 60 | } 61 | if (P->user.phone) { 62 | assert (json_object_set (res, "phone", json_string (P->user.phone)) >= 0); 63 | } 64 | if (P->user.username) { 65 | assert (json_object_set (res, "username", json_string (P->user.username)) >= 0); 66 | } 67 | } 68 | 69 | void json_pack_chat (json_t *res, tgl_peer_t *P) { 70 | assert (P->chat.title); 71 | assert (json_object_set (res, "title", json_string (P->chat.title)) >= 0); 72 | tgl_peer_id_t admin_id = TGL_MK_USER (P->chat.admin_id); 73 | assert (json_object_set (res, "admin", json_pack_peer (admin_id)) >= 0); 74 | assert (json_object_set (res, "members_num", json_integer (P->chat.users_num)) >= 0); 75 | if (P->chat.user_list) { 76 | json_t *m = json_array (); 77 | assert (m); 78 | 79 | int i; 80 | for (i = 0; i < P->chat.users_num; i++) { 81 | tgl_peer_id_t user_id = TGL_MK_USER (P->chat.user_list[i].user_id); 82 | tgl_peer_id_t inviter_id = TGL_MK_USER (P->chat.user_list[i].inviter_id); 83 | json_t *peer = json_pack_peer (user_id); 84 | assert (json_object_set (peer, "inviter", json_pack_peer (inviter_id)) >= 0); 85 | assert (json_array_append (m, peer) >= 0); 86 | } 87 | 88 | assert (json_object_set (res, "members", m) >= 0); 89 | } 90 | } 91 | 92 | 93 | void json_pack_encr_chat (json_t *res, tgl_peer_t *P) { 94 | assert (json_object_set (res, "user", json_pack_peer (TGL_MK_USER (P->encr_chat.user_id))) >= 0); 95 | } 96 | 97 | json_t *json_pack_peer (tgl_peer_id_t id) { 98 | tgl_peer_t *P = tgl_peer_get (TLS, id); 99 | //assert (P); 100 | json_t *res = json_object (); 101 | assert (json_object_set (res, "id", json_integer (tgl_get_peer_id (id))) >= 0); 102 | 103 | json_pack_peer_type (res, id); 104 | 105 | assert (res); 106 | 107 | if (!P || !(P->flags & TGLPF_CREATED)) { 108 | static char s[100]; 109 | switch (tgl_get_peer_type (id)) { 110 | case TGL_PEER_USER: 111 | sprintf (s, "user#%d", tgl_get_peer_id (id)); 112 | break; 113 | case TGL_PEER_CHAT: 114 | sprintf (s, "chat#%d", tgl_get_peer_id (id)); 115 | break; 116 | case TGL_PEER_ENCR_CHAT: 117 | sprintf (s, "encr_chat#%d", tgl_get_peer_id (id)); 118 | break; 119 | default: 120 | assert (0); 121 | } 122 | 123 | assert (json_object_set (res, "print_name", json_string (s)) >= 0); 124 | return res; 125 | } 126 | if(P->print_name != NULL){ 127 | assert (json_object_set (res, "print_name", json_string (P->print_name)) >= 0); 128 | } else { 129 | assert (json_object_set (res, "print_name", json_string ("")) >= 0); 130 | } 131 | assert (json_object_set (res, "flags", json_integer (P->flags)) >= 0); 132 | 133 | switch (tgl_get_peer_type (id)) { 134 | case TGL_PEER_USER: 135 | json_pack_user (res, P); 136 | break; 137 | case TGL_PEER_CHAT: 138 | json_pack_chat (res, P); 139 | break; 140 | case TGL_PEER_ENCR_CHAT: 141 | json_pack_encr_chat (res, P); 142 | break; 143 | default: 144 | assert (0); 145 | } 146 | return res; 147 | } 148 | 149 | json_t *json_pack_updates (unsigned flags) { 150 | json_t *a = json_array (); 151 | 152 | if (flags & TGL_UPDATE_CREATED) { 153 | assert (json_array_append (a, json_string ("created")) >= 0); 154 | } 155 | if (flags & TGL_UPDATE_DELETED) { 156 | assert (json_array_append (a, json_string ("deleted")) >= 0); 157 | } 158 | if (flags & TGL_UPDATE_PHONE) { 159 | assert (json_array_append (a, json_string ("phone")) >= 0); 160 | } 161 | if (flags & TGL_UPDATE_CONTACT) { 162 | assert (json_array_append (a, json_string ("contact")) >= 0); 163 | } 164 | if (flags & TGL_UPDATE_PHOTO) { 165 | assert (json_array_append (a, json_string ("photo")) >= 0); 166 | } 167 | if (flags & TGL_UPDATE_BLOCKED) { 168 | assert (json_array_append (a, json_string ("blocked")) >= 0); 169 | } 170 | if (flags & TGL_UPDATE_REAL_NAME) { 171 | assert (json_array_append (a, json_string ("real_name")) >= 0); 172 | } 173 | if (flags & TGL_UPDATE_NAME) { 174 | assert (json_array_append (a, json_string ("name")) >= 0); 175 | } 176 | if (flags & TGL_UPDATE_REQUESTED) { 177 | assert (json_array_append (a, json_string ("requested")) >= 0); 178 | } 179 | if (flags & TGL_UPDATE_WORKING) { 180 | assert (json_array_append (a, json_string ("working")) >= 0); 181 | } 182 | if (flags & TGL_UPDATE_FLAGS) { 183 | assert (json_array_append (a, json_string ("flags")) >= 0); 184 | } 185 | if (flags & TGL_UPDATE_TITLE) { 186 | assert (json_array_append (a, json_string ("title")) >= 0); 187 | } 188 | if (flags & TGL_UPDATE_ADMIN) { 189 | assert (json_array_append (a, json_string ("admin")) >= 0); 190 | } 191 | if (flags & TGL_UPDATE_MEMBERS) { 192 | assert (json_array_append (a, json_string ("members")) >= 0); 193 | } 194 | if (flags & TGL_UPDATE_USERNAME) { 195 | assert (json_array_append (a, json_string ("username")) >= 0); 196 | } 197 | 198 | return a; 199 | } 200 | 201 | 202 | json_t *json_pack_media (struct tgl_message_media *M) { 203 | json_t *res = json_object (); 204 | 205 | switch (M->type) { 206 | case tgl_message_media_photo: 207 | assert (json_object_set (res, "type", json_string ("photo")) >= 0); 208 | if (M->caption) { 209 | assert (json_object_set (res, "caption", json_string (M->caption)) >= 0); 210 | } 211 | break; 212 | case tgl_message_media_document: 213 | case tgl_message_media_document_encr: 214 | assert (json_object_set (res, "type", json_string ("document")) >= 0); 215 | break; 216 | case tgl_message_media_unsupported: 217 | assert (json_object_set (res, "type", json_string ("unsupported")) >= 0); 218 | break; 219 | case tgl_message_media_geo: 220 | assert (json_object_set (res, "type", json_string ("geo")) >= 0); 221 | assert (json_object_set (res, "longitude", json_real (M->geo.longitude)) >= 0); 222 | assert (json_object_set (res, "latitude", json_real (M->geo.latitude)) >= 0); 223 | break; 224 | case tgl_message_media_contact: 225 | assert (json_object_set (res, "type", json_string ("contact")) >= 0); 226 | assert (json_object_set (res, "phone", json_string (M->phone)) >= 0); 227 | assert (json_object_set (res, "first_name", json_string (M->first_name)) >= 0); 228 | assert (json_object_set (res, "last_name", json_string (M->last_name)) >= 0); 229 | assert (json_object_set (res, "user_id", json_integer (M->user_id)) >= 0); 230 | break; 231 | case tgl_message_media_webpage: 232 | assert (json_object_set (res, "type", json_string ("webpage")) >= 0); 233 | if (M->webpage->url) { 234 | assert (json_object_set (res, "url", json_string (M->webpage->url)) >= 0); 235 | } 236 | if (M->webpage->title) { 237 | assert (json_object_set (res, "title", json_string (M->webpage->title)) >= 0); 238 | } 239 | if (M->webpage->description) { 240 | assert (json_object_set (res, "description", json_string (M->webpage->description)) >= 0); 241 | } 242 | if (M->webpage->author) { 243 | assert (json_object_set (res, "author", json_string (M->webpage->author)) >= 0); 244 | } 245 | break; 246 | case tgl_message_media_venue: 247 | assert (json_object_set (res, "type", json_string ("venue")) >= 0); 248 | assert (json_object_set (res, "longitude", json_real (M->venue.geo.longitude)) >= 0); 249 | assert (json_object_set (res, "latitude", json_real (M->venue.geo.latitude)) >= 0); 250 | if (M->venue.title) { 251 | assert (json_object_set (res, "type", json_string (M->venue.title)) >= 0); 252 | } 253 | if (M->venue.address) { 254 | assert (json_object_set (res, "address", json_string (M->venue.address)) >= 0); 255 | } 256 | if (M->venue.provider) { 257 | assert (json_object_set (res, "provider", json_string (M->venue.provider)) >= 0); 258 | } 259 | if (M->venue.venue_id) { 260 | assert (json_object_set (res, "venue_id", json_string (M->venue.venue_id)) >= 0); 261 | } 262 | break; 263 | default: 264 | assert (json_object_set (res, "type", json_string ("???")) >= 0); 265 | } 266 | return res; 267 | } 268 | 269 | json_t *json_pack_typing (enum tgl_typing_status status) { 270 | json_t *res = json_object (); 271 | switch (status) { 272 | case tgl_typing_none: 273 | assert (json_object_set (res, "status", json_string ("doing nothing")) >= 0); 274 | break; 275 | case tgl_typing_typing: 276 | assert (json_object_set (res, "status", json_string ("typing")) >= 0); 277 | break; 278 | case tgl_typing_cancel: 279 | assert (json_object_set (res, "status", json_string ("deleting typed message")) >= 0); 280 | break; 281 | case tgl_typing_record_video: 282 | assert (json_object_set (res, "status", json_string ("recording video")) >= 0); 283 | break; 284 | case tgl_typing_upload_video: 285 | assert (json_object_set (res, "status", json_string ("uploading video")) >= 0); 286 | break; 287 | case tgl_typing_record_audio: 288 | assert (json_object_set (res, "status", json_string ("recording audio")) >= 0); 289 | break; 290 | case tgl_typing_upload_audio: 291 | assert (json_object_set (res, "status", json_string ("uploading audio")) >= 0); 292 | break; 293 | case tgl_typing_upload_photo: 294 | assert (json_object_set (res, "status", json_string ("uploading photo")) >= 0); 295 | break; 296 | case tgl_typing_upload_document: 297 | assert (json_object_set (res, "status", json_string ("uploading document")) >= 0); 298 | break; 299 | case tgl_typing_geo: 300 | assert (json_object_set (res, "status", json_string ("choosing location")) >= 0); 301 | break; 302 | case tgl_typing_choose_contact: 303 | assert (json_object_set (res, "status", json_string ("choosing contact")) >= 0); 304 | break; 305 | default: 306 | assert (json_object_set (res, "status", json_string ("???")) >= 0); 307 | break; 308 | } 309 | return res; 310 | } 311 | 312 | json_t *json_pack_service (struct tgl_message *M) { 313 | json_t *res = json_object (); 314 | switch (M->action.type) { 315 | case tgl_message_action_geo_chat_create: 316 | assert (json_object_set (res, "type", json_string ("geo_created")) >= 0); 317 | break; 318 | case tgl_message_action_geo_chat_checkin: 319 | assert (json_object_set (res, "type", json_string ("geo_checkin")) >= 0); 320 | break; 321 | case tgl_message_action_chat_create: 322 | assert (json_object_set (res, "type", json_string ("chat_created")) >= 0); 323 | assert (json_object_set (res, "title", json_string (M->action.title)) >= 0); 324 | break; 325 | case tgl_message_action_chat_edit_title: 326 | assert (json_object_set (res, "type", json_string ("chat_rename")) >= 0); 327 | assert (json_object_set (res, "title", json_string (M->action.title)) >= 0); 328 | break; 329 | case tgl_message_action_chat_edit_photo: 330 | assert (json_object_set (res, "type", json_string ("chat_change_photo")) >= 0); 331 | break; 332 | case tgl_message_action_chat_delete_photo: 333 | assert (json_object_set (res, "type", json_string ("chat_delete_photo")) >= 0); 334 | break; 335 | case tgl_message_action_chat_add_user: 336 | assert (json_object_set (res, "type", json_string ("chat_add_user")) >= 0); 337 | assert (json_object_set (res, "user", json_pack_peer (tgl_set_peer_id (TGL_PEER_USER, M->action.user))) >= 0); 338 | break; 339 | case tgl_message_action_chat_add_user_by_link: 340 | assert (json_object_set (res, "type", json_string ("chat_add_user_link")) >= 0); 341 | assert (json_object_set (res, "user", json_pack_peer (tgl_set_peer_id (TGL_PEER_USER, M->action.user))) >= 0); 342 | break; 343 | case tgl_message_action_chat_delete_user: 344 | assert (json_object_set (res, "type", json_string ("chat_del_user")) >= 0); 345 | assert (json_object_set (res, "user", json_pack_peer (tgl_set_peer_id (TGL_PEER_USER, M->action.user))) >= 0); 346 | break; 347 | case tgl_message_action_set_message_ttl: 348 | assert (json_object_set (res, "type", json_string ("set_ttl")) >= 0); 349 | assert (json_object_set (res, "ttl", json_integer (M->action.ttl)) >= 0); 350 | break; 351 | case tgl_message_action_read_messages: 352 | assert (json_object_set (res, "type", json_string ("read")) >= 0); 353 | assert (json_object_set (res, "count", json_integer (M->action.read_cnt)) >= 0); 354 | break; 355 | case tgl_message_action_delete_messages: 356 | assert (json_object_set (res, "type", json_string ("delete")) >= 0); 357 | assert (json_object_set (res, "count", json_integer (M->action.delete_cnt)) >= 0); 358 | break; 359 | case tgl_message_action_screenshot_messages: 360 | assert (json_object_set (res, "type", json_string ("screenshot")) >= 0); 361 | assert (json_object_set (res, "count", json_integer (M->action.screenshot_cnt)) >= 0); 362 | break; 363 | case tgl_message_action_flush_history: 364 | assert (json_object_set (res, "type", json_string ("flush")) >= 0); 365 | break; 366 | case tgl_message_action_resend: 367 | assert (json_object_set (res, "type", json_string ("resend")) >= 0); 368 | break; 369 | case tgl_message_action_notify_layer: 370 | assert (json_object_set (res, "type", json_string ("notify_layer")) >= 0); 371 | assert (json_object_set (res, "layer", json_integer (M->action.layer)) >= 0); 372 | break; 373 | case tgl_message_action_typing: 374 | assert (json_object_set (res, "type", json_string ("typing")) >= 0); 375 | assert (json_array_append (res, json_pack_typing (M->action.typing)) >= 0); 376 | break; 377 | case tgl_message_action_noop: 378 | assert (json_object_set (res, "type", json_string ("noop")) >= 0); 379 | break; 380 | case tgl_message_action_request_key: 381 | assert (json_object_set (res, "type", json_string ("request_key")) >= 0); 382 | break; 383 | case tgl_message_action_accept_key: 384 | assert (json_object_set (res, "type", json_string ("accept_key")) >= 0); 385 | break; 386 | case tgl_message_action_commit_key: 387 | assert (json_object_set (res, "type", json_string ("commit_key")) >= 0); 388 | break; 389 | case tgl_message_action_abort_key: 390 | assert (json_object_set (res, "type", json_string ("abort_key")) >= 0); 391 | break; 392 | default: 393 | assert (json_object_set (res, "type", json_string ("???")) >= 0); 394 | break; 395 | } 396 | return res; 397 | } 398 | 399 | json_t *json_pack_message (struct tgl_message *M) { 400 | json_t *res = json_object (); 401 | assert (json_object_set (res, "event", json_string ("message")) >= 0); 402 | //will overwriten to service, if service. 403 | 404 | assert (json_object_set (res, "id", json_integer (M->id)) >= 0); 405 | if (!(M->flags & TGLMF_CREATED)) { return res; } 406 | 407 | assert (json_object_set (res, "flags", json_integer (M->flags)) >= 0); 408 | 409 | if (tgl_get_peer_type (M->fwd_from_id)) { 410 | assert (json_object_set (res, "fwd_from", json_pack_peer (M->fwd_from_id)) >= 0); 411 | assert (json_object_set (res, "fwd_date", json_integer (M->fwd_date)) >= 0); 412 | } 413 | 414 | if (M->reply_id) { 415 | assert (json_object_set (res, "reply_id", json_integer (M->reply_id)) >= 0); 416 | } 417 | 418 | if (M->flags & TGLMF_MENTION) { 419 | assert (json_object_set (res, "mention", json_true ()) >= 0); 420 | } 421 | 422 | assert (json_object_set (res, "from", json_pack_peer (M->from_id)) >= 0); 423 | assert (json_object_set (res, "to", json_pack_peer (M->to_id)) >= 0); 424 | 425 | assert (json_object_set (res, "out", json_boolean (M->flags & TGLMF_OUT)) >= 0); 426 | assert (json_object_set (res, "unread", json_boolean (M->flags & TGLMF_UNREAD)) >= 0); 427 | assert (json_object_set (res, "service", json_boolean (M->flags & TGLMF_SERVICE)) >= 0); 428 | assert (json_object_set (res, "date", json_integer (M->date)) >= 0); 429 | 430 | if (!(M->flags & TGLMF_SERVICE)) { 431 | if (M->message_len && M->message) { 432 | assert (json_object_set (res, "text", json_string (M->message)) >= 0); 433 | } 434 | if (M->media.type && M->media.type != tgl_message_media_none) { 435 | assert (json_object_set (res, "media", json_pack_media (&M->media)) >= 0); 436 | } 437 | } else { 438 | assert (json_object_set (res, "event", json_string ("service")) >= 0); 439 | assert (json_object_set (res, "action", json_pack_service (M)) >= 0); 440 | } 441 | return res; 442 | } 443 | 444 | json_t *json_pack_read (struct tgl_message *M) { 445 | json_t *res = json_pack_message (M); 446 | assert (json_object_set (res, "event", json_string ("read")) >= 0); 447 | //this will overwrite "event":"message" to "event":"read". 448 | return res; 449 | } 450 | 451 | json_t *json_pack_user_status (struct tgl_user *U) { 452 | json_t *res = json_object (); 453 | assert (json_object_set (res, "user", json_pack_peer (U->id)) >= 0); 454 | struct tgl_user_status *S = &U->status; 455 | assert (json_object_set (res, "online", json_boolean (S->online == 1)) >= 0); 456 | assert (json_object_set (res, "state", json_integer (S->online)) >= 0); 457 | if (S->online > 0 || S->online == -1) { 458 | static char s[20]; 459 | str_format_time(S->when, s); 460 | assert (json_object_set (res, "when", json_string (s)) >= 0); 461 | } else if (S->online == 0) { 462 | assert (json_object_set(res, "when", json_string("long time ago")) >= 0); 463 | } else if (S->online == -2) { 464 | assert (json_object_set(res, "when", json_string("recently")) >= 0); 465 | } else if (S->online == -3) { 466 | assert (json_object_set(res, "when", json_string("last week")) >= 0); 467 | } else if (S->online == -4) { 468 | assert (json_object_set (res, "when", json_string ("last month")) >= 0); 469 | } 470 | assert (json_object_set (res, "event", json_string ("online-status")) >= 0); 471 | //this will overwrite "event":"message" to "event":"read". 472 | return res; 473 | } 474 | 475 | #endif 476 | -------------------------------------------------------------------------------- /json-tg.h: -------------------------------------------------------------------------------- 1 | #ifndef __JSON_TG_H__ 2 | #define __JSON_TG_H__ 3 | #include "config.h" 4 | #ifdef USE_JSON 5 | #include 6 | #include 7 | #include 8 | json_t *json_pack_message (struct tgl_message *M); 9 | json_t *json_pack_updates (unsigned flags); 10 | json_t *json_pack_peer (tgl_peer_id_t id); 11 | json_t *json_pack_read (struct tgl_message *M); 12 | json_t *json_pack_user_status (struct tgl_user *U); 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /loop.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of telegram-cli. 3 | 4 | Telegram-cli is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | Telegram-cli is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this telegram-cli. If not, see . 16 | 17 | Copyright Vitaly Valtman 2013-2015 18 | */ 19 | 20 | #ifdef HAVE_CONFIG_H 21 | #include "config.h" 22 | #endif 23 | 24 | #if USE_PYTHON 25 | #include "python-tg.h" 26 | #endif 27 | 28 | #ifndef _GNU_SOURCE 29 | #define _GNU_SOURCE 30 | #endif 31 | #define READLINE_CALLBACKS 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #ifdef READLINE_GNU 38 | #include 39 | #include 40 | #else 41 | #include 42 | #include 43 | #endif 44 | 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | 54 | #ifdef EVENT_V2 55 | #include 56 | #include 57 | #else 58 | #include 59 | #include "event-old.h" 60 | #endif 61 | 62 | #include "interface.h" 63 | #include "telegram.h" 64 | #include "loop.h" 65 | #if USE_LUA 66 | #include "lua-tg.h" 67 | #endif 68 | 69 | #include 70 | #include 71 | #include 72 | #include 73 | 74 | #include 75 | 76 | int verbosity; 77 | extern int readline_disabled; 78 | extern char *bot_hash; 79 | 80 | extern int bot_mode; 81 | int binlog_read; 82 | extern char *default_username; 83 | extern char *auth_token; 84 | void set_default_username (const char *s); 85 | extern int binlog_enabled; 86 | 87 | extern int unknown_user_list_pos; 88 | extern int unknown_user_list[]; 89 | int register_mode; 90 | extern int safe_quit; 91 | extern int sync_from_start; 92 | 93 | extern int disable_output; 94 | extern int reset_authorization; 95 | 96 | extern int sfd; 97 | extern int usfd; 98 | 99 | void got_it (char *line, int len); 100 | void write_state_file (void); 101 | 102 | static char *line_buffer; 103 | static int line_buffer_size; 104 | static int line_buffer_pos; 105 | static int delete_stdin_event; 106 | 107 | extern volatile int sigterm_cnt; 108 | 109 | extern char *start_command; 110 | extern struct tgl_state *TLS; 111 | extern int ipv6_enabled; 112 | 113 | struct event *term_ev = 0; 114 | int read_one_string; 115 | #define MAX_ONE_STRING_LEN 511 116 | char one_string[MAX_ONE_STRING_LEN + 1]; 117 | int one_string_len; 118 | void (*one_string_cb)(struct tgl_state *TLS, const char *string[], void *arg); 119 | enum tgl_value_type one_string_type; 120 | int one_string_num; 121 | int one_string_total_args; 122 | char *one_string_results[10]; 123 | 124 | void *string_cb_arg; 125 | char *one_string_prompt; 126 | int one_string_flags; 127 | extern int disable_link_preview; 128 | 129 | void deactivate_readline (void); 130 | void reactivate_readline (void); 131 | 132 | void do_get_string (struct tgl_state *TLS); 133 | static void one_string_read_end (void) { 134 | printf ("\n"); 135 | fflush (stdout); 136 | 137 | read_one_string = 0; 138 | tfree_str (one_string_prompt); 139 | one_string_prompt = NULL; 140 | reactivate_readline (); 141 | 142 | one_string_results[one_string_num] = tstrdup (one_string); 143 | ++one_string_num; 144 | 145 | if (one_string_num < one_string_total_args) { 146 | do_get_string (TLS); 147 | } else { 148 | one_string_cb (TLS, (void *)one_string_results, string_cb_arg); 149 | int i; 150 | for (i = 0; i < one_string_total_args; i++) { 151 | tfree_str (one_string_results[i]); 152 | } 153 | } 154 | } 155 | 156 | void generate_prompt (enum tgl_value_type type, int num) { 157 | switch (type) { 158 | case tgl_phone_number: 159 | assert (!num); 160 | one_string_prompt = tstrdup ("phone number: "); 161 | one_string_flags = 0; 162 | return; 163 | case tgl_code: 164 | assert (!num); 165 | one_string_prompt = tstrdup ("code ('CALL' for phone code): "); 166 | one_string_flags = 0; 167 | return; 168 | case tgl_register_info: 169 | one_string_flags = 0; 170 | switch (num) { 171 | case 0: 172 | one_string_prompt = tstrdup ("register (Y/n): "); 173 | return; 174 | case 1: 175 | one_string_prompt = tstrdup ("first name: "); 176 | return; 177 | case 2: 178 | one_string_prompt = tstrdup ("last name: "); 179 | return; 180 | default: 181 | assert (0); 182 | } 183 | return; 184 | case tgl_new_password: 185 | one_string_flags = 1; 186 | switch (num) { 187 | case 0: 188 | one_string_prompt = tstrdup ("new password: "); 189 | return; 190 | case 1: 191 | one_string_prompt = tstrdup ("retype new password: "); 192 | return; 193 | default: 194 | assert (0); 195 | } 196 | return; 197 | case tgl_cur_and_new_password: 198 | one_string_flags = 1; 199 | switch (num) { 200 | case 0: 201 | one_string_prompt = tstrdup ("old password: "); 202 | return; 203 | case 1: 204 | one_string_prompt = tstrdup ("new password: "); 205 | return; 206 | case 2: 207 | one_string_prompt = tstrdup ("retype new password: "); 208 | return; 209 | default: 210 | assert (0); 211 | } 212 | return; 213 | case tgl_cur_password: 214 | one_string_flags = 1; 215 | assert (!num); 216 | one_string_prompt = tstrdup ("password: "); 217 | return; 218 | case tgl_bot_hash: 219 | one_string_flags = 0; 220 | assert (!num); 221 | one_string_prompt = tstrdup ("hash: "); 222 | return; 223 | default: 224 | assert (0); 225 | } 226 | } 227 | 228 | void do_get_string (struct tgl_state *TLS) { 229 | deactivate_readline (); 230 | generate_prompt (one_string_type, one_string_num); 231 | printf ("%s", one_string_prompt); 232 | fflush (stdout); 233 | read_one_string = 1; 234 | one_string_len = 0; 235 | } 236 | 237 | void do_get_values (struct tgl_state *TLS, enum tgl_value_type type, const char *prompt, int num_values, 238 | void (*callback)(struct tgl_state *TLS, const char *string[], void *arg), void *arg) { 239 | if (type == tgl_bot_hash && bot_hash) { 240 | assert (num_values == 1); 241 | one_string_results[0] = bot_hash; 242 | callback (TLS, (void *)one_string_results, arg); 243 | return; 244 | } 245 | one_string_cb = callback; 246 | one_string_num = 0; 247 | one_string_total_args = num_values; 248 | one_string_type = type; 249 | string_cb_arg = arg; 250 | do_get_string (TLS); 251 | } 252 | 253 | static void stdin_read_callback (evutil_socket_t fd, short what, void *arg) { 254 | if (!readline_disabled && !read_one_string) { 255 | rl_callback_read_char (); 256 | return; 257 | } 258 | if (read_one_string) { 259 | char c; 260 | int r = read (0, &c, 1); 261 | if (r <= 0) { 262 | perror ("read"); 263 | delete_stdin_event = 1; 264 | return; 265 | } 266 | if (c == '\n' || c == '\r') { 267 | one_string[one_string_len] = 0; 268 | one_string_read_end (); 269 | return; 270 | } 271 | if (one_string_len < MAX_ONE_STRING_LEN) { 272 | one_string[one_string_len ++] = c; 273 | if (!(one_string_flags & 1)) { 274 | printf ("%c", c); 275 | fflush (stdout); 276 | } 277 | } 278 | return; 279 | } 280 | 281 | if (line_buffer_pos == line_buffer_size) { 282 | line_buffer = realloc (line_buffer, line_buffer_size * 2 + 100); 283 | assert (line_buffer); 284 | line_buffer_size = line_buffer_size * 2 + 100; 285 | assert (line_buffer); 286 | } 287 | int r = read (0, line_buffer + line_buffer_pos, line_buffer_size - line_buffer_pos); 288 | if (r <= 0) { 289 | perror ("read"); 290 | delete_stdin_event = 1; 291 | return; 292 | } 293 | line_buffer_pos += r; 294 | 295 | while (1) { 296 | int p = 0; 297 | while (p < line_buffer_pos && line_buffer[p] != '\n') { p ++; } 298 | if (p < line_buffer_pos) { 299 | line_buffer[p] = 0; 300 | interpreter (line_buffer); 301 | memmove (line_buffer, line_buffer + p + 1, line_buffer_pos - p - 1); 302 | line_buffer_pos -= (p + 1); 303 | } else { 304 | break; 305 | } 306 | } 307 | } 308 | 309 | 310 | void net_loop (void) { 311 | delete_stdin_event = 0; 312 | if (verbosity >= E_DEBUG) { 313 | logprintf ("Starting netloop\n"); 314 | } 315 | term_ev = event_new (TLS->ev_base, 0, EV_READ | EV_PERSIST, stdin_read_callback, 0); 316 | event_add (term_ev, 0); 317 | 318 | int last_get_state = time (0); 319 | while (1) { 320 | event_base_loop (TLS->ev_base, EVLOOP_ONCE); 321 | 322 | if (term_ev && delete_stdin_event) { 323 | logprintf ("delete stdin\n"); 324 | event_free (term_ev); 325 | term_ev = 0; 326 | } 327 | 328 | #ifdef USE_LUA 329 | lua_do_all (); 330 | #endif 331 | 332 | #ifdef USE_PYTHON 333 | py_do_all (); 334 | #endif 335 | 336 | if (safe_quit && !TLS->active_queries) { 337 | printf ("All done. Exit\n"); 338 | do_halt (0); 339 | safe_quit = 0; 340 | } 341 | if (sigterm_cnt > 0) { 342 | do_halt (0); 343 | } 344 | if (time (0) - last_get_state > 3600) { 345 | tgl_do_lookup_state (TLS); 346 | last_get_state = time (0); 347 | } 348 | 349 | write_state_file (); 350 | update_prompt (); 351 | 352 | if (unknown_user_list_pos) { 353 | int i; 354 | for (i = 0; i < unknown_user_list_pos; i++) { 355 | tgl_do_get_user_info (TLS, TGL_MK_USER (unknown_user_list[i]), 0, 0, 0); 356 | } 357 | unknown_user_list_pos = 0; 358 | } 359 | } 360 | 361 | if (term_ev) { 362 | event_free (term_ev); 363 | term_ev = 0; 364 | } 365 | 366 | if (verbosity >= E_DEBUG) { 367 | logprintf ("End of netloop\n"); 368 | } 369 | } 370 | 371 | struct tgl_dc *cur_a_dc; 372 | int is_authorized (void) { 373 | return tgl_authorized_dc (TLS, cur_a_dc); 374 | } 375 | 376 | int all_authorized (void) { 377 | int i; 378 | for (i = 0; i <= TLS->max_dc_num; i++) if (TLS->DC_list[i]) { 379 | if (!tgl_authorized_dc (TLS, TLS->DC_list[i])) { 380 | return 0; 381 | } 382 | } 383 | return 1; 384 | } 385 | 386 | int zero[512]; 387 | 388 | 389 | int readline_active; 390 | int new_dc_num; 391 | int wait_dialog_list; 392 | 393 | extern struct tgl_update_callback upd_cb; 394 | 395 | #define DC_SERIALIZED_MAGIC 0x868aa81d 396 | #define STATE_FILE_MAGIC 0x28949a93 397 | #define SECRET_CHAT_FILE_MAGIC 0x37a1988a 398 | 399 | char *get_auth_key_filename (void); 400 | char *get_state_filename (void); 401 | char *get_secret_chat_filename (void); 402 | 403 | void read_state_file (void) { 404 | if (binlog_enabled) { return; } 405 | int state_file_fd = open (get_state_filename (), O_CREAT | O_RDWR, 0600); 406 | if (state_file_fd < 0) { 407 | return; 408 | } 409 | int version, magic; 410 | if (read (state_file_fd, &magic, 4) < 4) { close (state_file_fd); return; } 411 | if (magic != (int)STATE_FILE_MAGIC) { close (state_file_fd); return; } 412 | if (read (state_file_fd, &version, 4) < 4) { close (state_file_fd); return; } 413 | assert (version >= 0); 414 | int x[4]; 415 | if (read (state_file_fd, x, 16) < 16) { 416 | close (state_file_fd); 417 | return; 418 | } 419 | int pts = x[0]; 420 | int qts = x[1]; 421 | int seq = x[2]; 422 | int date = x[3]; 423 | close (state_file_fd); 424 | bl_do_set_seq (TLS, seq); 425 | bl_do_set_pts (TLS, pts); 426 | bl_do_set_qts (TLS, qts); 427 | bl_do_set_date (TLS, date); 428 | } 429 | 430 | 431 | void write_state_file (void) { 432 | if (binlog_enabled) { return; } 433 | static int wseq; 434 | static int wpts; 435 | static int wqts; 436 | static int wdate; 437 | if (wseq >= TLS->seq && wpts >= TLS->pts && wqts >= TLS->qts && wdate >= TLS->date) { return; } 438 | wseq = TLS->seq; wpts = TLS->pts; wqts = TLS->qts; wdate = TLS->date; 439 | int state_file_fd = open (get_state_filename (), O_CREAT | O_RDWR, 0600); 440 | if (state_file_fd < 0) { 441 | logprintf ("Can not write state file '%s': %m\n", get_state_filename ()); 442 | do_halt (1); 443 | } 444 | int x[6]; 445 | x[0] = STATE_FILE_MAGIC; 446 | x[1] = 0; 447 | x[2] = wpts; 448 | x[3] = wqts; 449 | x[4] = wseq; 450 | x[5] = wdate; 451 | assert (write (state_file_fd, x, 24) == 24); 452 | close (state_file_fd); 453 | } 454 | 455 | void write_dc (struct tgl_dc *DC, void *extra) { 456 | int auth_file_fd = *(int *)extra; 457 | if (!DC) { 458 | int x = 0; 459 | assert (write (auth_file_fd, &x, 4) == 4); 460 | return; 461 | } else { 462 | int x = 1; 463 | assert (write (auth_file_fd, &x, 4) == 4); 464 | } 465 | 466 | assert (DC->flags & TGLDCF_LOGGED_IN); 467 | 468 | assert (write (auth_file_fd, &DC->options[0]->port, 4) == 4); 469 | int l = strlen (DC->options[0]->ip); 470 | assert (write (auth_file_fd, &l, 4) == 4); 471 | assert (write (auth_file_fd, DC->options[0]->ip, l) == l); 472 | assert (write (auth_file_fd, &DC->auth_key_id, 8) == 8); 473 | assert (write (auth_file_fd, DC->auth_key, 256) == 256); 474 | } 475 | 476 | void write_auth_file (void) { 477 | if (binlog_enabled) { return; } 478 | int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, 0600); 479 | assert (auth_file_fd >= 0); 480 | int x = DC_SERIALIZED_MAGIC; 481 | assert (write (auth_file_fd, &x, 4) == 4); 482 | assert (write (auth_file_fd, &TLS->max_dc_num, 4) == 4); 483 | assert (write (auth_file_fd, &TLS->dc_working_num, 4) == 4); 484 | 485 | tgl_dc_iterator_ex (TLS, write_dc, &auth_file_fd); 486 | 487 | assert (write (auth_file_fd, &TLS->our_id, 4) == 4); 488 | close (auth_file_fd); 489 | } 490 | 491 | void write_secret_chat (tgl_peer_t *Peer, void *extra) { 492 | struct tgl_secret_chat *P = (void *)Peer; 493 | if (tgl_get_peer_type (P->id) != TGL_PEER_ENCR_CHAT) { return; } 494 | if (P->state != sc_ok) { return; } 495 | int *a = extra; 496 | int fd = a[0]; 497 | a[1] ++; 498 | 499 | int id = tgl_get_peer_id (P->id); 500 | assert (write (fd, &id, 4) == 4); 501 | //assert (write (fd, &P->flags, 4) == 4); 502 | int l = strlen (P->print_name); 503 | assert (write (fd, &l, 4) == 4); 504 | assert (write (fd, P->print_name, l) == l); 505 | assert (write (fd, &P->user_id, 4) == 4); 506 | assert (write (fd, &P->admin_id, 4) == 4); 507 | assert (write (fd, &P->date, 4) == 4); 508 | assert (write (fd, &P->ttl, 4) == 4); 509 | assert (write (fd, &P->layer, 4) == 4); 510 | assert (write (fd, &P->access_hash, 8) == 8); 511 | assert (write (fd, &P->state, 4) == 4); 512 | assert (write (fd, &P->key_fingerprint, 8) == 8); 513 | assert (write (fd, &P->key, 256) == 256); 514 | assert (write (fd, &P->first_key_sha, 20) == 20); 515 | assert (write (fd, &P->in_seq_no, 4) == 4); 516 | assert (write (fd, &P->last_in_seq_no, 4) == 4); 517 | assert (write (fd, &P->out_seq_no, 4) == 4); 518 | } 519 | 520 | void write_secret_chat_file (void) { 521 | if (binlog_enabled) { return; } 522 | int secret_chat_fd = open (get_secret_chat_filename (), O_CREAT | O_RDWR, 0600); 523 | assert (secret_chat_fd >= 0); 524 | int x = SECRET_CHAT_FILE_MAGIC; 525 | assert (write (secret_chat_fd, &x, 4) == 4); 526 | x = 2; 527 | assert (write (secret_chat_fd, &x, 4) == 4); // version 528 | assert (write (secret_chat_fd, &x, 4) == 4); // num 529 | 530 | int y[2]; 531 | y[0] = secret_chat_fd; 532 | y[1] = 0; 533 | 534 | tgl_peer_iterator_ex (TLS, write_secret_chat, y); 535 | 536 | lseek (secret_chat_fd, 8, SEEK_SET); 537 | assert (write (secret_chat_fd, &y[1], 4) == 4); 538 | close (secret_chat_fd); 539 | } 540 | 541 | void read_dc (int auth_file_fd, int id, unsigned ver) { 542 | int port = 0; 543 | assert (read (auth_file_fd, &port, 4) == 4); 544 | int l = 0; 545 | assert (read (auth_file_fd, &l, 4) == 4); 546 | assert (l >= 0 && l < 100); 547 | char ip[100]; 548 | assert (read (auth_file_fd, ip, l) == l); 549 | ip[l] = 0; 550 | 551 | long long auth_key_id; 552 | static unsigned char auth_key[256]; 553 | assert (read (auth_file_fd, &auth_key_id, 8) == 8); 554 | assert (read (auth_file_fd, auth_key, 256) == 256); 555 | 556 | //bl_do_add_dc (id, ip, l, port, auth_key_id, auth_key); 557 | bl_do_dc_option (TLS, id, "DC", 2, ip, l, port); 558 | bl_do_set_auth_key (TLS, id, auth_key); 559 | bl_do_dc_signed (TLS, id); 560 | } 561 | 562 | void empty_auth_file (void) { 563 | if (TLS->test_mode) { 564 | bl_do_dc_option (TLS, 1, "", 0, TG_SERVER_TEST_1, strlen (TG_SERVER_TEST_1), 443); 565 | bl_do_dc_option (TLS, 2, "", 0, TG_SERVER_TEST_2, strlen (TG_SERVER_TEST_2), 443); 566 | bl_do_dc_option (TLS, 3, "", 0, TG_SERVER_TEST_3, strlen (TG_SERVER_TEST_3), 443); 567 | bl_do_set_working_dc (TLS, TG_SERVER_TEST_DEFAULT); 568 | } else { 569 | bl_do_dc_option (TLS, 1, "", 0, TG_SERVER_1, strlen (TG_SERVER_1), 443); 570 | bl_do_dc_option (TLS, 2, "", 0, TG_SERVER_2, strlen (TG_SERVER_2), 443); 571 | bl_do_dc_option (TLS, 3, "", 0, TG_SERVER_3, strlen (TG_SERVER_3), 443); 572 | bl_do_dc_option (TLS, 4, "", 0, TG_SERVER_4, strlen (TG_SERVER_4), 443); 573 | bl_do_dc_option (TLS, 5, "", 0, TG_SERVER_5, strlen (TG_SERVER_5), 443); 574 | bl_do_set_working_dc (TLS, TG_SERVER_DEFAULT); 575 | } 576 | } 577 | 578 | int need_dc_list_update; 579 | void read_auth_file (void) { 580 | if (binlog_enabled) { return; } 581 | int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, 0600); 582 | if (auth_file_fd < 0) { 583 | empty_auth_file (); 584 | return; 585 | } 586 | assert (auth_file_fd >= 0); 587 | unsigned x; 588 | unsigned m; 589 | if (read (auth_file_fd, &m, 4) < 4 || (m != DC_SERIALIZED_MAGIC)) { 590 | close (auth_file_fd); 591 | empty_auth_file (); 592 | return; 593 | } 594 | assert (read (auth_file_fd, &x, 4) == 4); 595 | assert (x > 0); 596 | int dc_working_num; 597 | assert (read (auth_file_fd, &dc_working_num, 4) == 4); 598 | 599 | int i; 600 | for (i = 0; i <= (int)x; i++) { 601 | int y; 602 | assert (read (auth_file_fd, &y, 4) == 4); 603 | if (y) { 604 | read_dc (auth_file_fd, i, m); 605 | } 606 | } 607 | bl_do_set_working_dc (TLS, dc_working_num); 608 | int our_id; 609 | int l = read (auth_file_fd, &our_id, 4); 610 | if (l < 4) { 611 | assert (!l); 612 | } 613 | if (our_id) { 614 | bl_do_set_our_id (TLS, our_id); 615 | } 616 | close (auth_file_fd); 617 | } 618 | 619 | void read_secret_chat (int fd, int v) { 620 | int id, l, user_id, admin_id, date, ttl, layer, state; 621 | long long access_hash, key_fingerprint; 622 | static char s[1000]; 623 | static unsigned char key[256]; 624 | static unsigned char sha[20]; 625 | assert (read (fd, &id, 4) == 4); 626 | //assert (read (fd, &flags, 4) == 4); 627 | assert (read (fd, &l, 4) == 4); 628 | assert (l > 0 && l < 1000); 629 | assert (read (fd, s, l) == l); 630 | assert (read (fd, &user_id, 4) == 4); 631 | assert (read (fd, &admin_id, 4) == 4); 632 | assert (read (fd, &date, 4) == 4); 633 | assert (read (fd, &ttl, 4) == 4); 634 | assert (read (fd, &layer, 4) == 4); 635 | assert (read (fd, &access_hash, 8) == 8); 636 | assert (read (fd, &state, 4) == 4); 637 | assert (read (fd, &key_fingerprint, 8) == 8); 638 | assert (read (fd, &key, 256) == 256); 639 | if (v >= 2) { 640 | assert (read (fd, sha, 20) == 20); 641 | } else { 642 | SHA1 ((void *)key, 256, sha); 643 | } 644 | int in_seq_no = 0, out_seq_no = 0, last_in_seq_no = 0; 645 | if (v >= 1) { 646 | assert (read (fd, &in_seq_no, 4) == 4); 647 | assert (read (fd, &last_in_seq_no, 4) == 4); 648 | assert (read (fd, &out_seq_no, 4) == 4); 649 | } 650 | 651 | bl_do_encr_chat_new (TLS, id, 652 | &access_hash, 653 | &date, 654 | &admin_id, 655 | &user_id, 656 | key, 657 | NULL, 658 | sha, 659 | &state, 660 | &ttl, 661 | &layer, 662 | &in_seq_no, 663 | &last_in_seq_no, 664 | &out_seq_no, 665 | &key_fingerprint, 666 | TGLECF_CREATE | TGLECF_CREATED 667 | ); 668 | 669 | } 670 | 671 | void read_secret_chat_file (void) { 672 | if (binlog_enabled) { return; } 673 | int secret_chat_fd = open (get_secret_chat_filename (), O_RDWR, 0600); 674 | if (secret_chat_fd < 0) { return; } 675 | //assert (secret_chat_fd >= 0); 676 | int x; 677 | if (read (secret_chat_fd, &x, 4) < 4) { close (secret_chat_fd); return; } 678 | if (x != SECRET_CHAT_FILE_MAGIC) { close (secret_chat_fd); return; } 679 | int v = 0; 680 | assert (read (secret_chat_fd, &v, 4) == 4); 681 | assert (v == 0 || v == 1 || v == 2); // version 682 | assert (read (secret_chat_fd, &x, 4) == 4); 683 | assert (x >= 0); 684 | while (x --> 0) { 685 | read_secret_chat (secret_chat_fd, v); 686 | } 687 | close (secret_chat_fd); 688 | } 689 | 690 | static void read_incoming (struct bufferevent *bev, void *_arg) { 691 | vlogprintf (E_WARNING, "Read from incoming connection\n"); 692 | struct in_ev *ev = _arg; 693 | assert (ev->bev == bev); 694 | ev->in_buf_pos += bufferevent_read (bev, ev->in_buf + ev->in_buf_pos, 4096 - ev->in_buf_pos); 695 | 696 | while (1) { 697 | int pos = 0; 698 | int ok = 0; 699 | while (pos < ev->in_buf_pos) { 700 | if (ev->in_buf[pos] == '\n') { 701 | if (!ev->error) { 702 | ev->in_buf[pos] = 0; 703 | interpreter_ex (ev->in_buf, ev); 704 | } else { 705 | ev->error = 0; 706 | } 707 | ok = 1; 708 | ev->in_buf_pos -= (pos + 1); 709 | memmove (ev->in_buf, ev->in_buf + pos + 1, ev->in_buf_pos); 710 | pos = 0; 711 | } else { 712 | pos ++; 713 | } 714 | } 715 | if (ok) { 716 | ev->in_buf_pos += bufferevent_read (bev, ev->in_buf + ev->in_buf_pos, 4096 - ev->in_buf_pos); 717 | } else { 718 | if (ev->in_buf_pos == 4096) { 719 | ev->error = 1; 720 | } 721 | break; 722 | } 723 | } 724 | } 725 | 726 | void event_incoming (struct bufferevent *bev, short what, void *_arg) { 727 | struct in_ev *ev = _arg; 728 | if (what & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) { 729 | vlogprintf (E_WARNING, "Closing incoming connection\n"); 730 | assert (ev->fd >= 0); 731 | close (ev->fd); 732 | bufferevent_free (bev); 733 | ev->bev = 0; 734 | if (!--ev->refcnt) { free (ev); } 735 | } 736 | } 737 | 738 | static void accept_incoming (evutil_socket_t efd, short what, void *arg) { 739 | vlogprintf (E_WARNING, "Accepting incoming connection\n"); 740 | socklen_t clilen = 0; 741 | struct sockaddr_in cli_addr; 742 | int fd = accept (efd, (struct sockaddr *)&cli_addr, &clilen); 743 | 744 | assert (fd >= 0); 745 | struct bufferevent *bev = bufferevent_socket_new (TLS->ev_base, fd, 0); 746 | struct in_ev *e = malloc (sizeof (*e)); 747 | e->bev = bev; 748 | e->refcnt = 1; 749 | e->in_buf_pos = 0; 750 | e->error = 0; 751 | e->fd = fd; 752 | bufferevent_setcb (bev, read_incoming, 0, event_incoming, e); 753 | bufferevent_enable (bev, EV_READ | EV_WRITE); 754 | } 755 | 756 | char *get_downloads_directory (void); 757 | void on_login (struct tgl_state *TLS) { 758 | write_auth_file (); 759 | } 760 | 761 | void on_started (struct tgl_state *TLS); 762 | void dlist_cb (struct tgl_state *TLSR, void *callback_extra, int success, int size, tgl_peer_id_t peers[], int last_msg_id[], int unread_count[]) { 763 | on_started (TLS); 764 | } 765 | 766 | void on_started (struct tgl_state *TLS) { 767 | if (wait_dialog_list) { 768 | wait_dialog_list = 0; 769 | tgl_do_get_dialog_list (TLS, 100, 0, dlist_cb, 0); 770 | return; 771 | } 772 | #ifdef USE_LUA 773 | lua_diff_end (); 774 | #endif 775 | 776 | #ifdef USE_PYTHON 777 | py_diff_end (); 778 | #endif 779 | 780 | if (start_command) { 781 | safe_quit = 1; 782 | while (*start_command) { 783 | char *start = start_command; 784 | while (*start_command && *start_command != '\n') { 785 | start_command ++; 786 | } 787 | if (*start_command) { 788 | *start_command = 0; 789 | start_command ++; 790 | } 791 | interpreter_ex (start, 0); 792 | } 793 | } 794 | } 795 | 796 | int loop (void) { 797 | tgl_set_callback (TLS, &upd_cb); 798 | struct event_base *ev = event_base_new (); 799 | tgl_set_ev_base (TLS, ev); 800 | tgl_set_net_methods (TLS, &tgl_conn_methods); 801 | tgl_set_timer_methods (TLS, &tgl_libevent_timers); 802 | assert (TLS->timer_methods); 803 | tgl_set_download_directory (TLS, get_downloads_directory ()); 804 | tgl_register_app_id (TLS, TELEGRAM_CLI_APP_ID, TELEGRAM_CLI_APP_HASH); 805 | tgl_set_app_version (TLS, "Telegram-cli " TELEGRAM_CLI_VERSION); 806 | if (ipv6_enabled) { 807 | tgl_enable_ipv6 (TLS); 808 | } 809 | if (bot_mode) { 810 | tgl_enable_bot (TLS); 811 | } 812 | if (disable_link_preview) { 813 | tgl_disable_link_preview (TLS); 814 | } 815 | tgl_init (TLS); 816 | 817 | if (binlog_enabled) { 818 | double t = tglt_get_double_time (); 819 | if (verbosity >= E_DEBUG) { 820 | logprintf ("replay log start\n"); 821 | } 822 | tgl_replay_log (TLS); 823 | if (verbosity >= E_DEBUG) { 824 | logprintf ("replay log end in %lf seconds\n", tglt_get_double_time () - t); 825 | } 826 | tgl_reopen_binlog_for_writing (TLS); 827 | } else { 828 | read_auth_file (); 829 | read_state_file (); 830 | read_secret_chat_file (); 831 | } 832 | 833 | binlog_read = 1; 834 | #ifdef USE_LUA 835 | lua_binlog_end (); 836 | #endif 837 | 838 | #ifdef USE_PYTHON 839 | py_binlog_end (); 840 | #endif 841 | 842 | if (sfd >= 0) { 843 | struct event *ev = event_new (TLS->ev_base, sfd, EV_READ | EV_PERSIST, accept_incoming, 0); 844 | event_add (ev, 0); 845 | } 846 | if (usfd >= 0) { 847 | struct event *ev = event_new (TLS->ev_base, usfd, EV_READ | EV_PERSIST, accept_incoming, 0); 848 | event_add (ev, 0); 849 | } 850 | update_prompt (); 851 | 852 | if (reset_authorization) { 853 | tgl_peer_t *P = tgl_peer_get (TLS, TGL_MK_USER (TLS->our_id)); 854 | if (P && P->user.phone && reset_authorization == 1) { 855 | set_default_username (P->user.phone); 856 | } 857 | bl_do_reset_authorization (TLS); 858 | } 859 | 860 | set_interface_callbacks (); 861 | tgl_login (TLS); 862 | net_loop (); 863 | return 0; 864 | } 865 | 866 | -------------------------------------------------------------------------------- /loop.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of telegram-cli. 3 | 4 | Telegram-cli is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | Telegram-cli is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this telegram-cli. If not, see . 16 | 17 | Copyright Vitaly Valtman 2013-2015 18 | */ 19 | #ifndef __LOOP_H__ 20 | #define __LOOP_H__ 21 | #define TELEGRAM_CLI_APP_HASH "36722c72256a24c1225de00eb6a1ca74" 22 | #define TELEGRAM_CLI_APP_ID 2899 23 | 24 | int loop (void); 25 | void do_halt (int error); 26 | void write_auth_file (void); 27 | void write_state_file (void); 28 | void write_secret_chat_file (void); 29 | #endif 30 | -------------------------------------------------------------------------------- /lua-tg.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of telegram-cli. 3 | 4 | Telegram-cli is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | Telegram-cli is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this telegram-cli. If not, see . 16 | 17 | Copyright Vitaly Valtman 2013-2015 18 | */ 19 | #ifndef __LUA_TG_H__ 20 | #define __LUA_TG_H__ 21 | 22 | #include 23 | #include 24 | 25 | void lua_init (const char *file); 26 | void lua_new_msg (struct tgl_message *M); 27 | void lua_our_id (int id); 28 | void lua_secret_chat_update (struct tgl_secret_chat *U, unsigned flags); 29 | void lua_user_update (struct tgl_user *U, unsigned flags); 30 | void lua_chat_update (struct tgl_chat *C, unsigned flags); 31 | void lua_binlog_end (void); 32 | void lua_diff_end (void); 33 | void lua_do_all (void); 34 | #endif 35 | -------------------------------------------------------------------------------- /m4-ax_gcc_builtin.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_gcc_builtin.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_GCC_BUILTIN(BUILTIN) 8 | # 9 | # DESCRIPTION 10 | # 11 | # This macro checks if the compiler supports one of GCC's built-in 12 | # functions; many other compilers also provide those same built-ins. 13 | # 14 | # The BUILTIN parameter is the name of the built-in function. 15 | # 16 | # If BUILTIN is supported define HAVE_. Keep in mind that since 17 | # builtins usually start with two underscores they will be copied over 18 | # into the HAVE_ definition (e.g. HAVE___BUILTIN_EXPECT for 19 | # __builtin_expect()). 20 | # 21 | # The macro caches its result in the ax_cv_have_ variable (e.g. 22 | # ax_cv_have___builtin_expect). 23 | # 24 | # The macro currently supports the following built-in functions: 25 | # 26 | # __builtin_assume_aligned 27 | # __builtin_bswap32 28 | # __builtin_bswap64 29 | # __builtin_choose_expr 30 | # __builtin___clear_cache 31 | # __builtin_clrsb 32 | # __builtin_clrsbl 33 | # __builtin_clrsbll 34 | # __builtin_clz 35 | # __builtin_clzl 36 | # __builtin_clzll 37 | # __builtin_complex 38 | # __builtin_constant_p 39 | # __builtin_ctz 40 | # __builtin_ctzl 41 | # __builtin_ctzll 42 | # __builtin_expect 43 | # __builtin_ffs 44 | # __builtin_ffsl 45 | # __builtin_ffsll 46 | # __builtin_fpclassify 47 | # __builtin_huge_val 48 | # __builtin_huge_valf 49 | # __builtin_huge_vall 50 | # __builtin_inf 51 | # __builtin_infd128 52 | # __builtin_infd32 53 | # __builtin_infd64 54 | # __builtin_inff 55 | # __builtin_infl 56 | # __builtin_isinf_sign 57 | # __builtin_nan 58 | # __builtin_nand128 59 | # __builtin_nand32 60 | # __builtin_nand64 61 | # __builtin_nanf 62 | # __builtin_nanl 63 | # __builtin_nans 64 | # __builtin_nansf 65 | # __builtin_nansl 66 | # __builtin_object_size 67 | # __builtin_parity 68 | # __builtin_parityl 69 | # __builtin_parityll 70 | # __builtin_popcount 71 | # __builtin_popcountl 72 | # __builtin_popcountll 73 | # __builtin_powi 74 | # __builtin_powif 75 | # __builtin_powil 76 | # __builtin_prefetch 77 | # __builtin_trap 78 | # __builtin_types_compatible_p 79 | # __builtin_unreachable 80 | # 81 | # Unsuppored built-ins will be tested with an empty parameter set and the 82 | # result of the check might be wrong or meaningless so use with care. 83 | # 84 | # LICENSE 85 | # 86 | # Copyright (c) 2013 Gabriele Svelto 87 | # 88 | # Copying and distribution of this file, with or without modification, are 89 | # permitted in any medium without royalty provided the copyright notice 90 | # and this notice are preserved. This file is offered as-is, without any 91 | # warranty. 92 | 93 | #serial 2 94 | 95 | AC_DEFUN([AX_GCC_BUILTIN], [ 96 | AS_VAR_PUSHDEF([ac_var], [ax_cv_have_$1]) 97 | 98 | AC_CACHE_CHECK([for $1], [ac_var], [ 99 | AC_LINK_IFELSE([AC_LANG_PROGRAM([], [ 100 | m4_case([$1], 101 | [__builtin_assume_aligned], [$1("", 0)], 102 | [__builtin_bswap32], [$1(0)], 103 | [__builtin_bswap64], [$1(0)], 104 | [__builtin_choose_expr], [$1(0, 0, 0)], 105 | [__builtin___clear_cache], [$1("", "")], 106 | [__builtin_clrsb], [$1(0)], 107 | [__builtin_clrsbl], [$1(0)], 108 | [__builtin_clrsbll], [$1(0)], 109 | [__builtin_clz], [$1(0)], 110 | [__builtin_clzl], [$1(0)], 111 | [__builtin_clzll], [$1(0)], 112 | [__builtin_complex], [$1(0.0, 0.0)], 113 | [__builtin_constant_p], [$1(0)], 114 | [__builtin_ctz], [$1(0)], 115 | [__builtin_ctzl], [$1(0)], 116 | [__builtin_ctzll], [$1(0)], 117 | [__builtin_expect], [$1(0, 0)], 118 | [__builtin_ffs], [$1(0)], 119 | [__builtin_ffsl], [$1(0)], 120 | [__builtin_ffsll], [$1(0)], 121 | [__builtin_fpclassify], [$1(0, 1, 2, 3, 4, 0.0)], 122 | [__builtin_huge_val], [$1()], 123 | [__builtin_huge_valf], [$1()], 124 | [__builtin_huge_vall], [$1()], 125 | [__builtin_inf], [$1()], 126 | [__builtin_infd128], [$1()], 127 | [__builtin_infd32], [$1()], 128 | [__builtin_infd64], [$1()], 129 | [__builtin_inff], [$1()], 130 | [__builtin_infl], [$1()], 131 | [__builtin_isinf_sign], [$1(0.0)], 132 | [__builtin_nan], [$1("")], 133 | [__builtin_nand128], [$1("")], 134 | [__builtin_nand32], [$1("")], 135 | [__builtin_nand64], [$1("")], 136 | [__builtin_nanf], [$1("")], 137 | [__builtin_nanl], [$1("")], 138 | [__builtin_nans], [$1("")], 139 | [__builtin_nansf], [$1("")], 140 | [__builtin_nansl], [$1("")], 141 | [__builtin_object_size], [$1("", 0)], 142 | [__builtin_parity], [$1(0)], 143 | [__builtin_parityl], [$1(0)], 144 | [__builtin_parityll], [$1(0)], 145 | [__builtin_popcount], [$1(0)], 146 | [__builtin_popcountl], [$1(0)], 147 | [__builtin_popcountll], [$1(0)], 148 | [__builtin_powi], [$1(0, 0)], 149 | [__builtin_powif], [$1(0, 0)], 150 | [__builtin_powil], [$1(0, 0)], 151 | [__builtin_prefetch], [$1("")], 152 | [__builtin_trap], [$1()], 153 | [__builtin_types_compatible_p], [$1(int, int)], 154 | [__builtin_unreachable], [$1()], 155 | [m4_warn([syntax], [Unsupported built-in $1, the test may fail]) 156 | $1()] 157 | ) 158 | ])], 159 | [AS_VAR_SET([ac_var], [yes])], 160 | [AS_VAR_SET([ac_var], [no])]) 161 | ]) 162 | 163 | AS_IF([test yes = AS_VAR_GET([ac_var])], 164 | [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_$1), 1, 165 | [Define to 1 if the system has the `$1' built-in function])], []) 166 | 167 | AS_VAR_POPDEF([ac_var]) 168 | ]) 169 | -------------------------------------------------------------------------------- /m4_ax_check_openssl.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_check_openssl.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CHECK_OPENSSL([action-if-found[, action-if-not-found]]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Look for OpenSSL in a number of default spots, or in a user-selected 12 | # spot (via --with-openssl). Sets 13 | # 14 | # OPENSSL_INCLUDES to the include directives required 15 | # OPENSSL_LIBS to the -l directives required 16 | # OPENSSL_LDFLAGS to the -L or -R flags required 17 | # 18 | # and calls ACTION-IF-FOUND or ACTION-IF-NOT-FOUND appropriately 19 | # 20 | # This macro sets OPENSSL_INCLUDES such that source files should use the 21 | # openssl/ directory in include directives: 22 | # 23 | # #include 24 | # 25 | # LICENSE 26 | # 27 | # Copyright (c) 2009,2010 Zmanda Inc. 28 | # Copyright (c) 2009,2010 Dustin J. Mitchell 29 | # 30 | # Copying and distribution of this file, with or without modification, are 31 | # permitted in any medium without royalty provided the copyright notice 32 | # and this notice are preserved. This file is offered as-is, without any 33 | # warranty. 34 | 35 | #serial 8 36 | 37 | AU_ALIAS([CHECK_SSL], [AX_CHECK_OPENSSL]) 38 | AC_DEFUN([AX_CHECK_OPENSSL], [ 39 | found=false 40 | AC_ARG_WITH([openssl], 41 | [AS_HELP_STRING([--with-openssl=DIR], 42 | [root of the OpenSSL directory])], 43 | [ 44 | case "$withval" in 45 | "" | y | ye | yes | n | no) 46 | AC_MSG_ERROR([Invalid --with-openssl value]) 47 | ;; 48 | *) ssldirs="$withval" 49 | ;; 50 | esac 51 | ], [ 52 | # if pkg-config is installed and openssl has installed a .pc file, 53 | # then use that information and don't search ssldirs 54 | AC_PATH_PROG([PKG_CONFIG], [pkg-config]) 55 | if test x"$PKG_CONFIG" != x""; then 56 | OPENSSL_LDFLAGS=`$PKG_CONFIG openssl --libs-only-L 2>/dev/null` 57 | if test $? = 0; then 58 | OPENSSL_LIBS=`$PKG_CONFIG openssl --libs-only-l 2>/dev/null` 59 | OPENSSL_INCLUDES=`$PKG_CONFIG openssl --cflags-only-I 2>/dev/null` 60 | found=true 61 | fi 62 | fi 63 | 64 | # no such luck; use some default ssldirs 65 | if ! $found; then 66 | ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr" 67 | fi 68 | ] 69 | ) 70 | 71 | 72 | # note that we #include , so the OpenSSL headers have to be in 73 | # an 'openssl' subdirectory 74 | 75 | if ! $found; then 76 | OPENSSL_INCLUDES= 77 | for ssldir in $ssldirs; do 78 | AC_MSG_CHECKING([for openssl/ssl.h in $ssldir]) 79 | if test -f "$ssldir/include/openssl/ssl.h"; then 80 | OPENSSL_INCLUDES="-I$ssldir/include" 81 | OPENSSL_LDFLAGS="-L$ssldir/lib" 82 | OPENSSL_LIBS="-lssl -lcrypto" 83 | found=true 84 | AC_MSG_RESULT([yes]) 85 | break 86 | else 87 | AC_MSG_RESULT([no]) 88 | fi 89 | done 90 | 91 | # if the file wasn't found, well, go ahead and try the link anyway -- maybe 92 | # it will just work! 93 | fi 94 | 95 | # try the preprocessor and linker with our new flags, 96 | # being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS 97 | 98 | AC_MSG_CHECKING([whether compiling and linking against OpenSSL works]) 99 | echo "Trying link with OPENSSL_LDFLAGS=$OPENSSL_LDFLAGS;" \ 100 | "OPENSSL_LIBS=$OPENSSL_LIBS; OPENSSL_INCLUDES=$OPENSSL_INCLUDES" >&AS_MESSAGE_LOG_FD 101 | 102 | save_LIBS="$LIBS" 103 | save_LDFLAGS="$LDFLAGS" 104 | save_CPPFLAGS="$CPPFLAGS" 105 | LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS" 106 | LIBS="$OPENSSL_LIBS $LIBS" 107 | CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS" 108 | AC_LINK_IFELSE( 109 | [AC_LANG_PROGRAM([#include ], [SSL_new(NULL)])], 110 | [ 111 | AC_MSG_RESULT([yes]) 112 | $1 113 | ], [ 114 | AC_MSG_RESULT([no]) 115 | $2 116 | ]) 117 | CPPFLAGS="$save_CPPFLAGS" 118 | LDFLAGS="$save_LDFLAGS" 119 | LIBS="$save_LIBS" 120 | 121 | AC_SUBST([OPENSSL_INCLUDES]) 122 | AC_SUBST([OPENSSL_LIBS]) 123 | AC_SUBST([OPENSSL_LDFLAGS]) 124 | ]) 125 | -------------------------------------------------------------------------------- /m4_ax_check_zlib.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_check_zlib.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CHECK_ZLIB([action-if-found], [action-if-not-found]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # This macro searches for an installed zlib library. If nothing was 12 | # specified when calling configure, it searches first in /usr/local and 13 | # then in /usr, /opt/local and /sw. If the --with-zlib=DIR is specified, 14 | # it will try to find it in DIR/include/zlib.h and DIR/lib/libz.a. If 15 | # --without-zlib is specified, the library is not searched at all. 16 | # 17 | # If either the header file (zlib.h) or the library (libz) is not found, 18 | # shell commands 'action-if-not-found' is run. If 'action-if-not-found' is 19 | # not specified, the configuration exits on error, asking for a valid zlib 20 | # installation directory or --without-zlib. 21 | # 22 | # If both header file and library are found, shell commands 23 | # 'action-if-found' is run. If 'action-if-found' is not specified, the 24 | # default action appends '-I${ZLIB_HOME}/include' to CPFLAGS, appends 25 | # '-L$ZLIB_HOME}/lib' to LDFLAGS, prepends '-lz' to LIBS, and calls 26 | # AC_DEFINE(HAVE_LIBZ). You should use autoheader to include a definition 27 | # for this symbol in a config.h file. Sample usage in a C/C++ source is as 28 | # follows: 29 | # 30 | # #ifdef HAVE_LIBZ 31 | # #include 32 | # #endif /* HAVE_LIBZ */ 33 | # 34 | # LICENSE 35 | # 36 | # Copyright (c) 2008 Loic Dachary 37 | # Copyright (c) 2010 Bastien Chevreux 38 | # 39 | # This program is free software; you can redistribute it and/or modify it 40 | # under the terms of the GNU General Public License as published by the 41 | # Free Software Foundation; either version 2 of the License, or (at your 42 | # option) any later version. 43 | # 44 | # This program is distributed in the hope that it will be useful, but 45 | # WITHOUT ANY WARRANTY; without even the implied warranty of 46 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 47 | # Public License for more details. 48 | # 49 | # You should have received a copy of the GNU General Public License along 50 | # with this program. If not, see . 51 | # 52 | # As a special exception, the respective Autoconf Macro's copyright owner 53 | # gives unlimited permission to copy, distribute and modify the configure 54 | # scripts that are the output of Autoconf when processing the Macro. You 55 | # need not follow the terms of the GNU General Public License when using 56 | # or distributing such scripts, even though portions of the text of the 57 | # Macro appear in them. The GNU General Public License (GPL) does govern 58 | # all other use of the material that constitutes the Autoconf Macro. 59 | # 60 | # This special exception to the GPL applies to versions of the Autoconf 61 | # Macro released by the Autoconf Archive. When you make and distribute a 62 | # modified version of the Autoconf Macro, you may extend this special 63 | # exception to the GPL to apply to your modified version as well. 64 | 65 | #serial 14 66 | 67 | AU_ALIAS([CHECK_ZLIB], [AX_CHECK_ZLIB]) 68 | AC_DEFUN([AX_CHECK_ZLIB], 69 | # 70 | # Handle user hints 71 | # 72 | [AC_MSG_CHECKING(if zlib is wanted) 73 | zlib_places="/usr/local /usr /opt/local /sw" 74 | AC_ARG_WITH([zlib], 75 | [ --with-zlib=DIR root directory path of zlib installation @<:@defaults to 76 | /usr/local or /usr if not found in /usr/local@:>@ 77 | --without-zlib to disable zlib usage completely], 78 | [if test "$withval" != no ; then 79 | AC_MSG_RESULT(yes) 80 | if test -d "$withval" 81 | then 82 | zlib_places="$withval $zlib_places" 83 | else 84 | AC_MSG_WARN([Sorry, $withval does not exist, checking usual places]) 85 | fi 86 | else 87 | zlib_places= 88 | AC_MSG_RESULT(no) 89 | fi], 90 | [AC_MSG_RESULT(yes)]) 91 | 92 | # 93 | # Locate zlib, if wanted 94 | # 95 | if test -n "${zlib_places}" 96 | then 97 | # check the user supplied or any other more or less 'standard' place: 98 | # Most UNIX systems : /usr/local and /usr 99 | # MacPorts / Fink on OSX : /opt/local respectively /sw 100 | for ZLIB_HOME in ${zlib_places} ; do 101 | if test -f "${ZLIB_HOME}/include/zlib.h"; then break; fi 102 | ZLIB_HOME="" 103 | done 104 | 105 | ZLIB_OLD_LDFLAGS=$LDFLAGS 106 | ZLIB_OLD_CPPFLAGS=$CPPFLAGS 107 | if test -n "${ZLIB_HOME}"; then 108 | LDFLAGS="$LDFLAGS -L${ZLIB_HOME}/lib" 109 | CPPFLAGS="$CPPFLAGS -I${ZLIB_HOME}/include" 110 | fi 111 | AC_LANG_SAVE 112 | AC_LANG_C 113 | AC_CHECK_LIB([z], [inflateEnd], [zlib_cv_libz=yes], [zlib_cv_libz=no]) 114 | AC_CHECK_HEADER([zlib.h], [zlib_cv_zlib_h=yes], [zlib_cv_zlib_h=no]) 115 | AC_LANG_RESTORE 116 | if test "$zlib_cv_libz" = "yes" && test "$zlib_cv_zlib_h" = "yes" 117 | then 118 | # 119 | # If both library and header were found, action-if-found 120 | # 121 | m4_ifblank([$1],[ 122 | CPPFLAGS="$CPPFLAGS -I${ZLIB_HOME}/include" 123 | LDFLAGS="$LDFLAGS -L${ZLIB_HOME}/lib" 124 | LIBS="-lz $LIBS" 125 | AC_DEFINE([HAVE_LIBZ], [1], 126 | [Define to 1 if you have `z' library (-lz)]) 127 | ],[ 128 | # Restore variables 129 | LDFLAGS="$ZLIB_OLD_LDFLAGS" 130 | CPPFLAGS="$ZLIB_OLD_CPPFLAGS" 131 | $1 132 | ]) 133 | else 134 | # 135 | # If either header or library was not found, action-if-not-found 136 | # 137 | m4_default([$2],[ 138 | AC_MSG_ERROR([either specify a valid zlib installation with --with-zlib=DIR or disable zlib usage with --without-zlib]) 139 | ]) 140 | fi 141 | fi 142 | ]) 143 | -------------------------------------------------------------------------------- /mime.types: -------------------------------------------------------------------------------- 1 | tgl/mime.types -------------------------------------------------------------------------------- /python-tg.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of telegram-cli. 3 | 4 | Telegram-cli is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | Telegram-cli is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this telegram-cli. If not, see . 16 | 17 | Copyright Vitaly Valtman 2013-2015 18 | Copyright Vincent Castellano 2015 19 | */ 20 | #ifndef __PYTHON_TG_H__ 21 | #define __PYTHON_TG_H__ 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | // Python functions 28 | void py_init (const char *file); 29 | void py_new_msg (struct tgl_message *M); 30 | void py_our_id (int id); 31 | void py_secret_chat_update (struct tgl_secret_chat *U, unsigned flags); 32 | void py_user_update (struct tgl_user *U, unsigned flags); 33 | void py_chat_update (struct tgl_chat *C, unsigned flags); 34 | void py_binlog_end (void); 35 | void py_diff_end (void); 36 | void py_do_all (void); 37 | 38 | // Binding functions 39 | PyObject* py_contact_list(PyObject *self, PyObject *args); 40 | PyObject* py_dialog_list(PyObject *self, PyObject *args); 41 | PyObject* py_rename_chat(PyObject *self, PyObject *args); 42 | PyObject* py_send_msg(PyObject *self, PyObject *args); 43 | PyObject* py_send_typing(PyObject *self, PyObject *args); 44 | PyObject* py_send_typing_abort(PyObject *self, PyObject *args); 45 | PyObject* py_send_photo(PyObject *self, PyObject *args); 46 | PyObject* py_send_video(PyObject *self, PyObject *args); 47 | PyObject* py_send_audio(PyObject *self, PyObject *args); 48 | PyObject* py_send_document(PyObject *self, PyObject *args); 49 | PyObject* py_send_file(PyObject *self, PyObject *args); 50 | PyObject* py_send_text(PyObject *self, PyObject *args); 51 | PyObject* py_chat_set_photo(PyObject *self, PyObject *args); 52 | PyObject* py_load_photo(PyObject *self, PyObject *args); 53 | PyObject* py_load_video(PyObject *self, PyObject *args); 54 | PyObject* py_load_video_thumb(PyObject *self, PyObject *args); 55 | PyObject* py_load_audio(PyObject *self, PyObject *args); 56 | PyObject* py_load_document(PyObject *self, PyObject *args); 57 | PyObject* py_load_document_thumb(PyObject *self, PyObject *args); 58 | PyObject* py_fwd(PyObject *self, PyObject *args); 59 | PyObject* py_fwd_media(PyObject *self, PyObject *args); 60 | PyObject* py_chat_info(PyObject *self, PyObject *args); 61 | PyObject* py_user_info(PyObject *self, PyObject *args); 62 | PyObject* py_history(PyObject *self, PyObject *args); 63 | PyObject* py_chat_add_user(PyObject *self, PyObject *args); 64 | PyObject* py_chat_del_user(PyObject *self, PyObject *args); 65 | PyObject* py_add_contact(PyObject *self, PyObject *args); 66 | PyObject* py_del_contact(PyObject *self, PyObject *args); 67 | PyObject* py_rename_contact(PyObject *self, PyObject *args); 68 | PyObject* py_search(PyObject *self, PyObject *args); 69 | PyObject* py_global_search(PyObject *self, PyObject *args); 70 | PyObject* py_mark_read(PyObject *self, PyObject *args); 71 | PyObject* py_set_profile_photo(PyObject *self, PyObject *args); 72 | PyObject* py_set_profile_name(PyObject *self, PyObject *args); 73 | PyObject* py_create_secret_chat(PyObject *self, PyObject *args); 74 | PyObject* py_create_group_chat(PyObject *self, PyObject *args); 75 | PyObject* py_delete_msg(PyObject *self, PyObject *args); 76 | PyObject* py_restore_msg(PyObject *self, PyObject *args); 77 | PyObject* py_accept_secret_chat(PyObject *self, PyObject *args); 78 | PyObject* py_send_contact(PyObject *self, PyObject *args); 79 | PyObject* py_status_online(PyObject *self, PyObject *args); 80 | PyObject* py_status_offline(PyObject *self, PyObject *args); 81 | PyObject* py_send_location(PyObject *self, PyObject *args); 82 | PyObject* py_extf(PyObject *self, PyObject *args); 83 | 84 | 85 | // Util Functions 86 | void py_add_string_field (PyObject* dict, char *name, const char *value); 87 | void py_add_string_field_arr (PyObject* list, int num, const char *value); 88 | void py_add_num_field (PyObject* dict, const char *name, double value); 89 | #endif 90 | -------------------------------------------------------------------------------- /python-types.h: -------------------------------------------------------------------------------- 1 | #ifndef __PYTHON_TYPES_H__ 2 | #define __PYTHON_TYPES_H__ 3 | 4 | #include 5 | #include 6 | 7 | typedef struct { 8 | PyObject_HEAD 9 | tgl_peer_t *peer; 10 | } tgl_Peer; 11 | 12 | typedef struct { 13 | PyObject_HEAD 14 | struct tgl_message *msg; 15 | } tgl_Msg; 16 | 17 | 18 | PyObject * tgl_Peer_FromTglPeer(tgl_peer_t *peer); 19 | PyObject * tgl_Msg_FromTglMsg(struct tgl_message *peer); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /rpm/telegram-cli-Beta-2.fc20.x86_64.rpm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEEDTEAM/tg/c841f197b7eb9ef829e499a3e8b283a2d45ae023/rpm/telegram-cli-Beta-2.fc20.x86_64.rpm -------------------------------------------------------------------------------- /server.pub: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PUBLIC KEY----- 2 | MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6 3 | lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS 4 | an9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTw 5 | Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+ 6 | 8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n 7 | Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB 8 | -----END RSA PUBLIC KEY----- 9 | -------------------------------------------------------------------------------- /start-telegram-daemon: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | # start-engine 4 | # derived from start-memcached 5 | # 2003/2004 - Jay Bonci 6 | # This script handles the parsing of the /etc/memcached.conf file 7 | # and was originally created for the Debian distribution. 8 | # Anyone may use this little script under the same terms as 9 | # memcached itself. 10 | 11 | # a bit changed it for telegram-daemon to generate config before start (Vitaly Valtman) 12 | 13 | use POSIX qw(strftime); 14 | use strict; 15 | 16 | my $id = defined($ARGV[0]) ? $ARGV[0] : ''; 17 | my $idx = $id eq '' ? '' : " '$id'"; 18 | my $idl = ($id =~ /^\.(.*)$/ ? "-$1" : $id); 19 | 20 | my $root = ""; 21 | 22 | my $params; my $etchandle; my $etcfile = "$root/etc/telegram-daemon/telegram-daemon$id.conf"; 23 | 24 | # This script assumes that engine is located at /usr/bin/engine, and 25 | # that the pidfile is writable at /var/run/engine.pid 26 | 27 | my $engine_pfx = "$root/usr/share/telegram-daemon/bin/"; 28 | my $pidfile = "$root/var/run/telegram-daemon$id.pid"; 29 | 30 | # If we don't get a valid logfile parameter in the /etc/engine.conf file, 31 | # we'll just throw away all of our in-daemon output. We need to re-tie it so 32 | # that non-bash shells will not hang on logout. Thanks to Michael Renner for 33 | # the tip 34 | my $fd_reopened = "/dev/null"; 35 | $fd_reopened = "$root/var/log/telegram-daemon/telegram-daemon$idl.log" if -d "$root/var/log/telegram-daemon/"; 36 | 37 | sub handle_logfile 38 | { 39 | my ($logfile) = @_; 40 | $logfile = "$root/var/log/telegram-daemon/$logfile" unless $logfile =~ /\//; 41 | $fd_reopened = $logfile; 42 | } 43 | 44 | sub reopen_logfile 45 | { 46 | my ($logfile) = @_; 47 | 48 | open *STDERR, ">>$logfile"; 49 | open *STDOUT, ">>$logfile"; 50 | open *STDIN, ">>/dev/null"; 51 | chown 239, 239, $logfile; 52 | $fd_reopened = $logfile; 53 | } 54 | 55 | sub adjust_arg 56 | { 57 | my ($arg) = @_; 58 | if ($arg =~ /^newest:(.*)$/) { 59 | my @L = split /:/, $1; 60 | my $x = $arg; 61 | my $xt = 0; 62 | for my $y (@L) { 63 | my @S = stat($y); 64 | if (scalar @S && $S[9] > $xt) { 65 | $x = $y; 66 | $xt = $S[9]; 67 | } 68 | } 69 | return $x; 70 | } 71 | return $arg; 72 | } 73 | 74 | # This is set up in place here to support other non -[a-z] directives 75 | 76 | my $conf_directives = { 77 | "logfile" => \&handle_logfile, 78 | }; 79 | 80 | my %Vars = ( 81 | "execute" => "msg-search-engine", 82 | "work_dir" => "$root/var/lib/telegram-daemon" 83 | ); 84 | 85 | my $have_c = 0; 86 | my $have_l = 0; 87 | my $have_u = 0; 88 | my $have_aes = 0; 89 | 90 | if(open $etchandle, $etcfile) 91 | { 92 | foreach my $line (<$etchandle>) 93 | { 94 | $line ||= ""; 95 | $line =~ s/\#.*//g; 96 | $line =~ s/\s+$//g; 97 | $line =~ s/^\s+//g; 98 | next unless $line; 99 | next if $line =~ /^\-[h]/; 100 | 101 | if($line =~ /^[^\-]/) 102 | { 103 | my ($directive, $int, $arg) = $line =~ /^(.*?)(\s+|\s*=\s*)(.*)/; 104 | next unless $directive; 105 | if (exists $conf_directives->{$directive}) { 106 | $conf_directives->{$directive}->($arg); 107 | } else { 108 | $Vars{$directive} = $arg; 109 | } 110 | next; 111 | } 112 | 113 | $have_l = 1 if $line =~ /^-L\s/; 114 | $have_c = 1 if $line =~ /^-c\s/; 115 | $have_u = 1 if $line =~ /^-U\s/; 116 | push @$params, $line; 117 | } 118 | 119 | }else{ 120 | $params = []; 121 | } 122 | 123 | push @$params, "-U telegramd" unless($have_u); 124 | push @$params, "-L $fd_reopened" unless($have_l); 125 | push @$params, "-c config$idl" unless($have_c); 126 | $params = join " ", @$params; 127 | 128 | if(-e $pidfile) 129 | { 130 | open PIDHANDLE, "$pidfile"; 131 | my $localpid = ; 132 | close PIDHANDLE; 133 | 134 | if ($localpid && $localpid =~ /(\d+)/) { $localpid = $1; } else { $localpid = -1; } 135 | if (-d "/proc/$localpid") 136 | { 137 | print STDERR "telegram-daemon$idl is already running.\n"; 138 | exit; 139 | } else { 140 | print STDERR "removing stale $pidfile.\n"; 141 | `rm -f $pidfile`; 142 | } 143 | 144 | } 145 | 146 | if (exists $Vars{'quit'}) { 147 | print STDERR "telegram-daemon$idl disabled\n"; 148 | exit(0); 149 | } 150 | 151 | my $engine = $engine_pfx.$Vars{'execute'}; 152 | my $wdir = $Vars{'work_dir'}; 153 | chdir $wdir if -d $wdir; 154 | 155 | unless (-x $engine) { 156 | print STDERR "executable $engine not found\n"; 157 | exit(1); 158 | } 159 | 160 | unless (-d $wdir) { 161 | print STDERR "work directory $wdir not found\n"; 162 | exit(1); 163 | } 164 | 165 | for my $x ('s', 0 .. 9) { 166 | if (defined($Vars{"arg$x"})) { 167 | $params .= " ".adjust_arg($Vars{"arg$x"}); 168 | } 169 | } 170 | 171 | my $pid = fork(); 172 | 173 | 174 | 175 | if (!$pid) { 176 | reopen_logfile ($fd_reopened); 177 | chdir $wdir; 178 | open(my $fh, '>', "config$idl"); 179 | 180 | my $text = <<"END_MSG" 181 | config_directory="$wdir"; 182 | test=false; 183 | msg_num=true; 184 | binlog_enabled=true; 185 | binlog="binlog$idl.bin"; 186 | pfs_enabled=true; 187 | log_level = 0; 188 | lua_script="script$idl.lua"; 189 | END_MSG 190 | ; 191 | print $fh $text; 192 | close $fh; 193 | my $t; 194 | $t = strftime ("%Y-%m-%d %H:%M:%S %Z", localtime); 195 | print STDERR "[$t] invoking telegram-daemon$idl: $engine $params\n"; 196 | exec "$engine $params"; 197 | exit (0); 198 | } else { 199 | if (open PIDHANDLE,">$pidfile") { 200 | print PIDHANDLE $pid; 201 | close PIDHANDLE; 202 | } else { 203 | print STDERR "Can't write pidfile to $pidfile.\n"; 204 | } 205 | } 206 | 207 | -------------------------------------------------------------------------------- /telegram-cli-cygwin.patch: -------------------------------------------------------------------------------- 1 | Binary files tg/.git/index and tg-cygwin/.git/index differ 2 | diff -urN tg/Makefile tg-cygwin/Makefile 3 | --- tg/Makefile 2015-06-16 12:39:34.931053900 +0900 4 | +++ tg-cygwin/Makefile 2015-06-16 12:44:12.584342300 +0900 5 | @@ -4,9 +4,9 @@ 6 | LDFLAGS= -L/usr/local/lib -L/usr/lib -L/usr/lib -L/usr/lib 7 | CPPFLAGS= -I/usr/local/include -I/usr/include -I/usr/include -I/usr/include/python3.4m -I/usr/include 8 | DEFS=-DHAVE_CONFIG_H 9 | -COMPILE_FLAGS=${CFLAGS} ${CPFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Werror -Wextra -Wno-missing-field-initializers -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb -Wno-unused-parameter -fPIC 10 | +COMPILE_FLAGS=${CFLAGS} ${CPFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Werror -Wextra -Wno-missing-field-initializers -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb -Wno-unused-parameter 11 | EXTRA_LIBS=-ljansson -lconfig -lz -levent -lm -lreadline -llua-5.2 -lpython3.4m -lssl -lcrypto 12 | -LOCAL_LDFLAGS=-rdynamic -ggdb -levent ${EXTRA_LIBS} -ldl -lpthread -lutil 13 | +LOCAL_LDFLAGS=-ggdb -levent ${EXTRA_LIBS} -ldl -lpthread -lutil 14 | LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} 15 | 16 | DEP=dep 17 | -------------------------------------------------------------------------------- /telegram-cli.spec: -------------------------------------------------------------------------------- 1 | Name: telegram-cli 2 | Version: Beta 3 | Release: 2%{?dist} 4 | Summary: Private fast and open platform for instant messaging 5 | 6 | Packager: Pablo Iranzo Gómez (Pablo.Iranzo@gmail.com) 7 | Group: Internet/Messaging 8 | License: GPL 9 | URL: https://github.com/vysheng/tg 10 | Source: master.zip 11 | 12 | BuildRequires: lua-devel, openssl-devel, libconfig-devel, readline-devel, wget 13 | #Requires: wget 14 | 15 | %description 16 | Telegram is an Open Source messaging platform for mobile, desktop focused on privacy. 17 | 18 | 19 | 20 | 21 | %prep 22 | [ -d %{name} ] && rm -Rfv %{name} 23 | mkdir %{name} 24 | cd %{name} 25 | wget -O master.zip https://github.com/vysheng/tg/archive/master.zip 26 | unzip master.zip 27 | cd tg-master 28 | ./configure 29 | make %{?_smp_mflags} 30 | 31 | 32 | %install 33 | cd %{name} 34 | cd tg-master 35 | %{__install} -D -m0755 telegram %{buildroot}/usr/bin/telegram 36 | %{__install} -D -m0644 tg-server.pub %{buildroot}/etc/telegram/server.pub 37 | 38 | %files 39 | /usr/bin/telegram 40 | /etc/telegram/server.pub 41 | 42 | %changelog 43 | * Tue Feb 4 2014 Pablo Iranzo Gómez (Pablo.Iranzo@gmail.com) 44 | - Add server key to /etc/telegram/ 45 | * Sat Feb 1 2014 Pablo Iranzo Gómez (Pablo.Iranzo@gmail.com) 46 | - Initial SPEC file 47 | -------------------------------------------------------------------------------- /telegram-daemon: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### BEGIN INIT INFO 4 | # Provides: engine 5 | # Required-Start: $local_fs $syslog 6 | # Required-Stop: $local_fs $syslog 7 | # Default-Start: 2 3 4 5 8 | # Default-Stop: 0 1 6 9 | # Short-Description: KittenDB Meta Engine 10 | ### END INIT INFO 11 | 12 | # 13 | # run script for KittenDB Engine 14 | # author: kot 15 | # author: burunduk 16 | # author: burunduk 17 | # 18 | # Version: 2013-06-06 19 | # 20 | 21 | # Features added: 22 | # -- flock to avoid parallel execution 23 | # -- checks to avoid creating empty engine configuration files 24 | 25 | 26 | # a bit changed it for telegram-daemon to use different folders 27 | # and to have posiiblilities to have fake root 28 | # Vitaly Valtman 29 | 30 | ROOT="" 31 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 32 | DAEMONDIR=$ROOT/usr/share/telegram-daemon/bin 33 | DAEMONBOOTSTRAP=$ROOT/usr/share/telegram-daemon/bin/start-telegram-daemon 34 | NAME=telegram-daemon 35 | DESC="KOT's meta engine" 36 | PIDFILE=$ROOT/var/run/$NAME 37 | LOCKFILE=$ROOT/var/lock/$NAME 38 | CONFFILE=$ROOT/etc/telegram-daemon/$NAME 39 | LOCK_WAIT=5 40 | STOP_TIMEOUT=5 41 | KILL_TIMEOUT=5 42 | 43 | test -x $DAEMONDIR || exit 0 44 | test -x $DAEMONBOOTSTRAP || exit 0 45 | 46 | set -e 47 | 48 | ## Utilitary functions 49 | 50 | # Send information to stderr 51 | function echo_stderr() { 52 | echo "$*" 1>&2 53 | } 54 | 55 | # Get engine status. Returns 0 on running engine, 1 otherwise. 56 | function engine_status() { 57 | local id="$1" 58 | local pif="$PIDFILE.$id.pid" 59 | if ! [ -f "$pif" ] ; then 60 | echo "stopped" 61 | return 1 62 | fi 63 | local pid="$(<$pif)" 64 | if [ -z "$pid" ]; then 65 | echo "corrupt pid file" 66 | return 1 67 | fi 68 | if [ -d "/proc/$pid/" ]; then 69 | echo "$pid" 70 | return 0 71 | else 72 | echo "failed (pid $pid)" 73 | return 1 74 | fi 75 | } 76 | 77 | # Start engine. Usage: engine_start 78 | function engine_start() { 79 | local eid="$1" 80 | local r='' 81 | local pid='' 82 | pid="$(engine_status "$eid")" && r='ok' || r='fail' 83 | if [ "$r" == 'ok' ] ; then 84 | echo_stderr "telegram-daemon-$eid: already running ($pid)" 85 | else 86 | start-stop-daemon --start --quiet --exec $DAEMONBOOTSTRAP -- .$eid 100> /dev/null 87 | fi 88 | return 0 89 | } 90 | 91 | # Stop engine. Usage: engine_stop 92 | function engine_stop() { 93 | local eid="$1" 94 | local r='' 95 | local status="$(engine_status "$eid")" && r='ok' || r='fail' 96 | local pif="$PIDFILE.$eid.pid" 97 | if [ "$r" == 'ok' ] ; then 98 | start-stop-daemon --stop --quiet --oknodo --pidfile "$pif" 99 | local ti=0 100 | while [ $ti -lt $((10 * $STOP_TIMEOUT)) ] ; do 101 | status="$(engine_status "$eid")" && r='ok' || r='fail' 102 | if [ "$r" == 'fail' ]; then 103 | break 104 | fi 105 | sleep 0.1 106 | ti=$(($ti + 1)) 107 | done 108 | if [ "$r" == 'ok' ] ; then 109 | echo_stderr "telegram-daemon-$eid: not stopped, sending SIGKILL..." 110 | start-stop-daemon --stop --quiet --oknodo --pidfile "$pif" --signal KILL 111 | ti=0 112 | while [ $ti -lt $((10 * $KILL_TIMEOUT)) ] ; do 113 | status="$(engine_status "$eid")" && r='ok' || r='fail' 114 | if [ "$r" == 'fail' ]; then 115 | break 116 | fi 117 | sleep 0.1 118 | ti=$(($ti + 1)) 119 | done 120 | fi 121 | if [ "$r" == 'ok' ] ; then 122 | echo_stderr "telegram-daemon-$eid: not stopped with SIGKILL, giving up" 123 | return 1 124 | else 125 | if [ -f "$pif" ] ; then 126 | rm "$pif" 127 | fi 128 | echo "telegram-daemon-$eid: stopped" 129 | fi 130 | else 131 | echo_stderr "telegram-daemon-$eid: not running: $status" 132 | fi 133 | return 0 134 | } 135 | 136 | # usage: engine_disable 137 | function engine_disable() { 138 | local eid="$1" 139 | local conf="$CONFFILE.$eid.conf" 140 | [ -e "$conf" ] || return 1 # work only with existing engines 141 | if grep -E '^quit 1$' "$conf" > /dev/null ; then 142 | echo_stderr "telegram-daemon-$eid: already disabled" 143 | else 144 | echo 'quit 1' >> "$conf" 145 | fi 146 | return 0 147 | } 148 | 149 | # usage: engine_enable 150 | function engine_enable() { 151 | local eid="$1" 152 | local conf="$CONFFILE.$eid.conf" 153 | [ -e "$conf" ] || return 1 # work only with existing engines 154 | if ! grep -E '^quit' "$conf" > /dev/null ; then 155 | echo_stderr "telegram-daemon-$eid: already enabled" 156 | else 157 | sed -i~ -e '/^quit/d' -- "$conf" 158 | fi 159 | return 0 160 | } 161 | 162 | # Wait for engine's command to be completed 163 | function engine_wait() { 164 | local eid="$1" 165 | ( 166 | flock -x -w $(($LOCK_WAIT + $STOP_TIMEOUT + $KILL_TIMEOUT)) 100 || exit 1 167 | ) 100> $LOCKFILE.$eid.lock || echo "Unable to wait for $eid" 168 | return 0 169 | } 170 | 171 | # Run a single command 172 | # Only one instance of this command per engine is supposed to work 173 | function run_one() { 174 | local eid="$1" 175 | shift 176 | local command="$*" 177 | [ "${#eid}" -gt 5 ] && return 0 # avoid long engine ids 178 | ( 179 | flock -x -w $LOCK_WAIT 100 || exit 1 180 | $command "$eid" 181 | ) 100> $LOCKFILE.$eid.lock 182 | return 0 183 | } 184 | 185 | # Run commands 186 | function run() { 187 | local mode="$1" 188 | shift 189 | local command="$*" 190 | local eid='' 191 | if [ "$mode" == 'parallel' ] ; then 192 | for eid in $arguments ; do 193 | run_one "$eid" "$command" & 194 | done 195 | sleep 0.1 196 | for eid in $arguments ; do 197 | engine_wait "$eid" 198 | done 199 | else 200 | for eid in $arguments ; do 201 | run_one "$eid" "$command" 202 | done 203 | fi 204 | return 0 205 | } 206 | 207 | # Get all actual engine ids 208 | function arguments_all() { 209 | local file='' 210 | local id='' 211 | local list='' 212 | for file in $(ls $CONFFILE.?*.conf 2> /dev/null) ; do 213 | id=${file#$CONFFILE.} 214 | id=${id%.conf} 215 | list="$list $id" 216 | done 217 | for file in $(ls $PIDFILE.?*.pid 2> /dev/null) ; do 218 | id=${file#$PIDFILE.} 219 | id=${id%.pid} 220 | list="$list $id" 221 | done 222 | local f='' 223 | for f in $list ; do echo "$f" ; done | sort -u 224 | return 0 225 | } 226 | 227 | ## Commands 228 | 229 | # Start engine. 230 | function engine_command_start() { 231 | local eid="$1" 232 | engine_start "$eid" 233 | } 234 | 235 | # Stop engine. 236 | function engine_command_stop() { 237 | local eid="$1" 238 | engine_stop "$eid" 239 | } 240 | 241 | # Enable engine. 242 | function engine_command_enable() { 243 | local eid="$1" 244 | engine_enable "$eid" 245 | engine_start "$eid" 246 | } 247 | 248 | # Disable engine. 249 | function engine_command_disable() { 250 | local eid="$1" 251 | engine_disable "$eid" 252 | engine_stop "$eid" 253 | } 254 | 255 | # Restart engine. 256 | function engine_command_restart() { 257 | local eid="$1" 258 | engine_stop "$eid" 259 | echo "restarting telegram-daemon-$eid..." 260 | engine_start "$eid" 261 | } 262 | 263 | # Send signal to engine. Usage: engine_command_signal 264 | function engine_command_signal() { 265 | local id="$2" 266 | local signal="$1" 267 | local r='' 268 | local comment="$(engine_status "$id")" && r='ok' || r='fail' 269 | local res='' 270 | if [ "$r" == 'ok' ]; then 271 | start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE.$id.pid --signal "$signal" 272 | else 273 | echo_stderr "telegram-daemon-$id: not running: $comment" 274 | fi 275 | return 0 276 | } 277 | 278 | # Get engine status 279 | function engine_command_status() { 280 | local id="$1" 281 | local res="telegram-daemon-$id: " 282 | local r='' 283 | local pid='' 284 | pid="$(engine_status "$id")" && r='ok' || r='fail' 285 | if [ "$r" == 'ok' ]; then 286 | res="$res $(COLUMNS=10000 ps -o pid,c,stime,time,cmd --no-header --pid $pid | sed -e 's/\/usr\/share\/telegram-daemon\/bin\///')" 287 | else 288 | res="$res $pid" 289 | fi 290 | echo "$res" 291 | return 0 292 | } 293 | 294 | ## Entry point 295 | 296 | command="$1" 297 | shift 298 | 299 | arguments="$*" 300 | if [ -z "$arguments" ] ; then 301 | if [ "$command" == "status" -o "$command" == "start" -o "$command" == "rotate-logs" -o "$command" == "stop" ] ; then 302 | arguments="$(arguments_all)" 303 | fi 304 | elif [ "$arguments" == "all" ] ; then 305 | arguments="$(arguments_all)" 306 | fi 307 | if [ -z "$arguments" ] ; then 308 | echo "nothing to do" 309 | exit 0 310 | fi 311 | 312 | case "$command" in 313 | ('disable') run parallel engine_command_disable ;; 314 | ('enable') run parallel engine_command_enable ;; 315 | # 316 | ('start') run parallel engine_command_start ;; 317 | ('status') run normal engine_command_status ;; 318 | ('stop') run parallel engine_command_stop ;; 319 | # 320 | ('rotate-logs') run parallel engine_command_signal USR1 ;; 321 | # 322 | ('restart'|'force-reload') run parallel engine_command_restart ;; 323 | (*) 324 | N=/etc/init.d/$NAME 325 | echo "Usage: $N {start|stop|restart|rotate-logs|status} [|all]" >&2 326 | echo " additional commands: disable , enable , reindex (use with caution)" >&2 327 | exit 1 328 | ;; 329 | esac 330 | 331 | exit 0 332 | 333 | -------------------------------------------------------------------------------- /telegram.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of telegram-cli. 3 | 4 | Telegram-cli is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | Telegram-cli is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this telegram-cli. If not, see . 16 | 17 | Copyright Vitaly Valtman 2013-2015 18 | */ 19 | 20 | #ifndef PROG_NAME 21 | #define PROG_NAME "telegram-cli" 22 | #endif 23 | 24 | #define TELEGRAM_CLI_VERSION "1.3.3" 25 | -------------------------------------------------------------------------------- /test.lua: -------------------------------------------------------------------------------- 1 | started = 0 2 | our_id = 0 3 | 4 | function vardump(value, depth, key) 5 | local linePrefix = "" 6 | local spaces = "" 7 | 8 | if key ~= nil then 9 | linePrefix = "["..key.."] = " 10 | end 11 | 12 | if depth == nil then 13 | depth = 0 14 | else 15 | depth = depth + 1 16 | for i=1, depth do spaces = spaces .. " " end 17 | end 18 | 19 | if type(value) == 'table' then 20 | mTable = getmetatable(value) 21 | if mTable == nil then 22 | print(spaces ..linePrefix.."(table) ") 23 | else 24 | print(spaces .."(metatable) ") 25 | value = mTable 26 | end 27 | for tableKey, tableValue in pairs(value) do 28 | vardump(tableValue, depth, tableKey) 29 | end 30 | elseif type(value) == 'function' or 31 | type(value) == 'thread' or 32 | type(value) == 'userdata' or 33 | value == nil 34 | then 35 | print(spaces..tostring(value)) 36 | else 37 | print(spaces..linePrefix.."("..type(value)..") "..tostring(value)) 38 | end 39 | end 40 | 41 | print ("HI, this is lua script") 42 | 43 | function ok_cb(extra, success, result) 44 | end 45 | 46 | -- Notification code {{{ 47 | 48 | function get_title (P, Q) 49 | if (Q.type == 'user') then 50 | return P.first_name .. " " .. P.last_name 51 | elseif (Q.type == 'chat') then 52 | return Q.title 53 | elseif (Q.type == 'encr_chat') then 54 | return 'Secret chat with ' .. P.first_name .. ' ' .. P.last_name 55 | else 56 | return '' 57 | end 58 | end 59 | 60 | local lgi = require ('lgi') 61 | local notify = lgi.require('Notify') 62 | notify.init ("Telegram updates") 63 | local icon = os.getenv("HOME") .. "/.telegram-cli/telegram-pics/telegram_64.png" 64 | 65 | function do_notify (user, msg) 66 | local n = notify.Notification.new(user, msg, icon) 67 | n:show () 68 | end 69 | 70 | -- }}} 71 | 72 | function on_msg_receive (msg) 73 | if started == 0 then 74 | return 75 | end 76 | if msg.out then 77 | return 78 | end 79 | do_notify (get_title (msg.from, msg.to), msg.text) 80 | 81 | if (msg.text == 'ping') then 82 | if (msg.to.id == our_id) then 83 | send_msg (msg.from.print_name, 'pong', ok_cb, false) 84 | else 85 | send_msg (msg.to.print_name, 'pong', ok_cb, false) 86 | end 87 | return 88 | end 89 | if (msg.text == 'PING') then 90 | if (msg.to.id == our_id) then 91 | fwd_msg (msg.from.print_name, msg.id, ok_cb, false) 92 | else 93 | fwd_msg (msg.to.print_name, msg.id, ok_cb, false) 94 | end 95 | return 96 | end 97 | end 98 | 99 | function on_our_id (id) 100 | our_id = id 101 | end 102 | 103 | function on_user_update (user, what) 104 | --vardump (user) 105 | end 106 | 107 | function on_chat_update (chat, what) 108 | --vardump (chat) 109 | end 110 | 111 | function on_secret_chat_update (schat, what) 112 | --vardump (schat) 113 | end 114 | 115 | function on_get_difference_end () 116 | end 117 | 118 | function cron() 119 | -- do something 120 | postpone (cron, false, 1.0) 121 | end 122 | 123 | function on_binlog_replay_end () 124 | started = 1 125 | postpone (cron, false, 1.0) 126 | end 127 | -------------------------------------------------------------------------------- /tg-server.pub: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PUBLIC KEY----- 2 | MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6 3 | lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS 4 | an9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTw 5 | Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+ 6 | 8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n 7 | Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB 8 | -----END RSA PUBLIC KEY----- 9 | 10 | -------------------------------------------------------------------------------- /tg-test.py: -------------------------------------------------------------------------------- 1 | import tgl 2 | import pprint 3 | from functools import partial 4 | 5 | 6 | our_id = 0 7 | pp = pprint.PrettyPrinter(indent=4) 8 | 9 | binlog_done = False; 10 | 11 | def on_binlog_replay_end(): 12 | binlog_done = True; 13 | 14 | def on_get_difference_end(): 15 | pass 16 | 17 | def on_our_id(id): 18 | our_id = id 19 | return "Set ID: " + str(our_id) 20 | 21 | def msg_cb(success, msg): 22 | pp.pprint(success) 23 | pp.pprint(msg) 24 | 25 | HISTORY_QUERY_SIZE = 100 26 | 27 | def history_cb(msg_list, peer, success, msgs): 28 | print(len(msgs)) 29 | msg_list.extend(msgs) 30 | print(len(msg_list)) 31 | if len(msgs) == HISTORY_QUERY_SIZE: 32 | tgl.get_history(peer, len(msg_list), HISTORY_QUERY_SIZE, partial(history_cb, msg_list, peer)); 33 | 34 | 35 | def cb(success): 36 | print(success) 37 | 38 | def on_msg_receive(msg): 39 | if msg.out and not binlog_done: 40 | return; 41 | 42 | if msg.dest.id == our_id: # direct message 43 | peer = msg.src 44 | else: # chatroom 45 | peer = msg.dest 46 | 47 | pp.pprint(msg) 48 | if msg.text.startswith("!ping"): 49 | peer.send_msg("PONG! google.com", preview=False, reply=msg.id) 50 | 51 | 52 | def on_secret_chat_update(peer, types): 53 | return "on_secret_chat_update" 54 | 55 | def on_user_update(): 56 | pass 57 | 58 | def on_chat_update(): 59 | pass 60 | 61 | # Set callbacks 62 | tgl.set_on_binlog_replay_end(on_binlog_replay_end) 63 | tgl.set_on_get_difference_end(on_get_difference_end) 64 | tgl.set_on_our_id(on_our_id) 65 | tgl.set_on_msg_receive(on_msg_receive) 66 | tgl.set_on_secret_chat_update(on_secret_chat_update) 67 | tgl.set_on_user_update(on_user_update) 68 | tgl.set_on_chat_update(on_chat_update) 69 | 70 | --------------------------------------------------------------------------------