More psalm fixes

This commit is contained in:
Daniil Gentili 2020-04-05 22:22:47 +02:00
parent a4d094d4c9
commit 77a955c25e
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
119 changed files with 559 additions and 136156 deletions

@ -1 +1 @@
Subproject commit 9e80b4cedd4d6d27722cbce371ed072d6c1ceba2 Subproject commit 945a5ca6fb6411ddcad077d78018150983f53ede

View File

@ -126,7 +126,7 @@ class API extends InternalDoc
public function __construct_async(string $session, array $settings = []): \Generator public function __construct_async(string $session, array $settings = []): \Generator
{ {
Logger::constructorFromSettings($settings); Logger::constructorFromSettings($settings);
$this->session = $session = Absolute::absolute($session); $this->session = $session = Tools::absolute($session);
if ($unserialized = yield from Serialization::legacyUnserialize($session)) { if ($unserialized = yield from Serialization::legacyUnserialize($session)) {
$unserialized->storage = $unserialized->storage ?? []; $unserialized->storage = $unserialized->storage ?? [];
$unserialized->session = $session; $unserialized->session = $session;

View File

@ -1,34 +0,0 @@
<?php
/**
* Absolute module.
*
* This file is part of MadelineProto.
* MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
* You should have received a copy of the GNU General Public License along with MadelineProto.
* If not, see <http://www.gnu.org/licenses/>.
*
* @author Daniil Gentili <daniil@daniil.it>
* @copyright 2016-2020 Daniil Gentili <daniil@daniil.it>
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
*
* @link https://docs.madelineproto.xyz MadelineProto documentation
*/
namespace danog\MadelineProto;
/**
* Manages serialization of the MadelineProto instance.
*/
class Absolute
{
public static function absolute($file)
{
if (($file[0] ?? '') !== '/' && ($file[1] ?? '') !== ':' && !\in_array(\substr($file, 0, 4), ['phar', 'http'])) {
$file = Magic::getcwd() . '/' . $file;
}
return $file;
}
}

View File

@ -40,7 +40,7 @@ trait Start
if (PHP_SAPI === 'cli') { if (PHP_SAPI === 'cli') {
$stdout = getStdout(); $stdout = getStdout();
yield $stdout->write('You did not define a valid API ID/API hash. Do you want to define it now manually, or automatically? (m/a) yield $stdout->write('You did not define a valid API ID/API hash. Do you want to define it now manually, or automatically? (m/a)
Note that you can also provide the API parameters directly in the code using the settings: https://docs.madelineproto.xyz/docs/SETTINGS.html#settingsapp_infoapi_id' . PHP_EOL); Note that you can also provide the API parameters directly in the code using the settings: https://docs.madelineproto.xyz/docs/SETTINGS.html#settingsapp_infoapi_id'.PHP_EOL);
if (\strpos(yield Tools::readLine('Your choice (m/a): '), 'm') !== false) { if (\strpos(yield Tools::readLine('Your choice (m/a): '), 'm') !== false) {
yield $stdout->write('1) Login to my.telegram.org yield $stdout->write('1) Login to my.telegram.org
2) Go to API development tools 2) Go to API development tools
@ -49,7 +49,7 @@ Note that you can also provide the API parameters directly in the code using the
URL: your app/website\'s URL, or t.me/yourusername URL: your app/website\'s URL, or t.me/yourusername
Platform: anything Platform: anything
Description: Describe your app here Description: Describe your app here
4) Click on create application' . PHP_EOL); 4) Click on create application'.PHP_EOL);
$app['api_id'] = yield Tools::readLine('5) Enter your API ID: '); $app['api_id'] = yield Tools::readLine('5) Enter your API ID: ');
$app['api_hash'] = yield Tools::readLine('6) Enter your API hash: '); $app['api_hash'] = yield Tools::readLine('6) Enter your API hash: ');
return $app; return $app;
@ -115,7 +115,7 @@ Note that you can also provide the API parameters directly in the code using the
yield from $this->myTelegramOrgWrapper->login($_POST['phone_number']); yield from $this->myTelegramOrgWrapper->login($_POST['phone_number']);
yield from $this->webAPIEcho(); yield from $this->webAPIEcho();
} catch (\Throwable $e) { } catch (\Throwable $e) {
yield from $this->webAPIEcho('ERROR: ' . $e->getMessage() . '. Try again.'); yield from $this->webAPIEcho('ERROR: '.$e->getMessage().'. Try again.');
} }
} }
private function webAPICompleteLogin(): \Generator private function webAPICompleteLogin(): \Generator
@ -123,9 +123,9 @@ Note that you can also provide the API parameters directly in the code using the
try { try {
yield from $this->myTelegramOrgWrapper->completeLogin($_POST['code']); yield from $this->myTelegramOrgWrapper->completeLogin($_POST['code']);
} catch (\danog\MadelineProto\RPCErrorException $e) { } catch (\danog\MadelineProto\RPCErrorException $e) {
yield from $this->webAPIEcho('ERROR: ' . $e->getMessage() . '. Try again.'); yield from $this->webAPIEcho('ERROR: '.$e->getMessage().'. Try again.');
} catch (\danog\MadelineProto\Exception $e) { } catch (\danog\MadelineProto\Exception $e) {
yield from $this->webAPIEcho('ERROR: ' . $e->getMessage() . '. Try again.'); yield from $this->webAPIEcho('ERROR: '.$e->getMessage().'. Try again.');
} }
} }
private function webAPICreateApp(): \Generator private function webAPICreateApp(): \Generator
@ -136,9 +136,9 @@ Note that you can also provide the API parameters directly in the code using the
$app = (yield from $this->myTelegramOrgWrapper->createApp($params)); $app = (yield from $this->myTelegramOrgWrapper->createApp($params));
return $app; return $app;
} catch (\danog\MadelineProto\RPCErrorException $e) { } catch (\danog\MadelineProto\RPCErrorException $e) {
yield from $this->webAPIEcho('ERROR: ' . $e->getMessage() . ' Try again.'); yield from $this->webAPIEcho('ERROR: '.$e->getMessage().' Try again.');
} catch (\danog\MadelineProto\Exception $e) { } catch (\danog\MadelineProto\Exception $e) {
yield from $this->webAPIEcho('ERROR: ' . $e->getMessage() . ' Try again.'); yield from $this->webAPIEcho('ERROR: '.$e->getMessage().' Try again.');
} }
} }
} }

View File

@ -325,7 +325,7 @@ class Connection extends Session
{ {
$this->ctx = $ctx->getCtx(); $this->ctx = $ctx->getCtx();
$this->datacenter = $ctx->getDc(); $this->datacenter = $ctx->getDc();
$this->datacenterId = $this->datacenter . '.' . $this->id; $this->datacenterId = $this->datacenter.'.'.$this->id;
$this->API->logger->logger("Connecting to DC {$this->datacenterId}", \danog\MadelineProto\Logger::WARNING); $this->API->logger->logger("Connecting to DC {$this->datacenterId}", \danog\MadelineProto\Logger::WARNING);
$this->createSession(); $this->createSession();
$ctx->setReadCallback([$this, 'haveRead']); $ctx->setReadCallback([$this, 'haveRead']);

View File

@ -55,13 +55,13 @@ class ContextConnector implements Connector
$this->logger->logger('OK!', \danog\MadelineProto\Logger::WARNING); $this->logger->logger('OK!', \danog\MadelineProto\Logger::WARNING);
return $result->getSocket(); return $result->getSocket();
} catch (\Throwable $e) { } catch (\Throwable $e) {
if (\constant("MADELINEPROTO_TEST") === 'pony') { if (@\constant("MADELINEPROTO_TEST") === 'pony') {
throw $e; throw $e;
} }
$this->logger->logger('Connection failed: ' . $e, \danog\MadelineProto\Logger::ERROR); $this->logger->logger('Connection failed: '.$e, \danog\MadelineProto\Logger::ERROR);
if ($e instanceof MultiReasonException) { if ($e instanceof MultiReasonException) {
foreach ($e->getReasons() as $reason) { foreach ($e->getReasons() as $reason) {
$this->logger->logger('Multireason: ' . $reason, \danog\MadelineProto\Logger::ERROR); $this->logger->logger('Multireason: '.$reason, \danog\MadelineProto\Logger::ERROR);
} }
} }
} }

View File

@ -264,7 +264,7 @@ class DataCenter
$this->API->logger->logger('OK!', \danog\MadelineProto\Logger::WARNING); $this->API->logger->logger('OK!', \danog\MadelineProto\Logger::WARNING);
return true; return true;
} catch (\Throwable $e) { } catch (\Throwable $e) {
if (\constant("MADELINEPROTO_TEST") === 'pony') { if (@\constant("MADELINEPROTO_TEST") === 'pony') {
throw $e; throw $e;
} }
$this->API->logger->logger("Connection failed ({$dc_number}): ".$e->getMessage(), \danog\MadelineProto\Logger::ERROR); $this->API->logger->logger("Connection failed ({$dc_number}): ".$e->getMessage(), \danog\MadelineProto\Logger::ERROR);
@ -272,6 +272,9 @@ class DataCenter
} }
throw new Exception("Could not connect to DC {$dc_number}"); throw new Exception("Could not connect to DC {$dc_number}");
} }
/**
* @param int|string $dc_number
*/
public function generateContexts($dc_number = 0, string $uri = '', ConnectContext $context = null) public function generateContexts($dc_number = 0, string $uri = '', ConnectContext $context = null)
{ {
$ctxs = []; $ctxs = [];
@ -488,7 +491,7 @@ class DataCenter
if (empty($ctxs)) { if (empty($ctxs)) {
unset($this->sockets[$dc_number]); unset($this->sockets[$dc_number]);
$this->API->logger->logger("No info for DC {$dc_number}", \danog\MadelineProto\Logger::ERROR); $this->API->logger->logger("No info for DC {$dc_number}", \danog\MadelineProto\Logger::ERROR);
} elseif (\constant("MADELINEPROTO_TEST") === 'pony') { } elseif (@\constant("MADELINEPROTO_TEST") === 'pony') {
return [$ctxs[0]]; return [$ctxs[0]];
} }
return $ctxs; return $ctxs;

View File

@ -117,7 +117,7 @@ class DoHConnector implements Connector
try { try {
$streamContext = \stream_context_create($socketContext->withoutTlsContext()->toStreamContextArray()); $streamContext = \stream_context_create($socketContext->withoutTlsContext()->toStreamContextArray());
if (!($socket = @\stream_socket_client($builtUri, $errno, $errstr, null, $flags, $streamContext))) { if (!($socket = @\stream_socket_client($builtUri, $errno, $errstr, null, $flags, $streamContext))) {
throw new ConnectException(\sprintf('Connection to %s failed: [Error #%d] %s%s', $uri, $errno, $errstr, $failures ? '; previous attempts: ' . \implode($failures) : ''), $errno); throw new ConnectException(\sprintf('Connection to %s failed: [Error #%d] %s%s', $uri, $errno, $errstr, $failures ? '; previous attempts: '.\implode($failures) : ''), $errno);
} }
\stream_set_blocking($socket, false); \stream_set_blocking($socket, false);
$deferred = new Deferred(); $deferred = new Deferred();
@ -126,7 +126,7 @@ class DoHConnector implements Connector
try { try {
yield Promise\timeout($deferred->promise(), $timeout); yield Promise\timeout($deferred->promise(), $timeout);
} catch (TimeoutException $e) { } catch (TimeoutException $e) {
throw new ConnectException(\sprintf('Connecting to %s failed: timeout exceeded (%d ms)%s', $uri, $timeout, $failures ? '; previous attempts: ' . \implode($failures) : ''), 110); throw new ConnectException(\sprintf('Connecting to %s failed: timeout exceeded (%d ms)%s', $uri, $timeout, $failures ? '; previous attempts: '.\implode($failures) : ''), 110);
// See ETIMEDOUT in http://www.virtsync.com/c-error-codes-include-errno // See ETIMEDOUT in http://www.virtsync.com/c-error-codes-include-errno
} finally { } finally {
Loop::cancel($watcher); Loop::cancel($watcher);
@ -135,7 +135,7 @@ class DoHConnector implements Connector
// The following hack looks like the only way to detect connection refused errors with PHP's stream sockets. // The following hack looks like the only way to detect connection refused errors with PHP's stream sockets.
if (\stream_socket_get_name($socket, true) === false) { if (\stream_socket_get_name($socket, true) === false) {
\fclose($socket); \fclose($socket);
throw new ConnectException(\sprintf('Connection to %s refused%s', $uri, $failures ? '; previous attempts: ' . \implode($failures) : ''), 111); throw new ConnectException(\sprintf('Connection to %s refused%s', $uri, $failures ? '; previous attempts: '.\implode($failures) : ''), 111);
// See ECONNREFUSED in http://www.virtsync.com/c-error-codes-include-errno // See ECONNREFUSED in http://www.virtsync.com/c-error-codes-include-errno
} }
} catch (ConnectException $e) { } catch (ConnectException $e) {
@ -143,7 +143,7 @@ class DoHConnector implements Connector
// In fact, this might show a confusing error message on OS families that return 110 or 111 by itself. // In fact, this might show a confusing error message on OS families that return 110 or 111 by itself.
$knownReasons = [110 => 'connection timeout', 111 => 'connection refused']; $knownReasons = [110 => 'connection timeout', 111 => 'connection refused'];
$code = $e->getCode(); $code = $e->getCode();
$reason = $knownReasons[$code] ?? 'Error #' . $code; $reason = $knownReasons[$code] ?? 'Error #'.$code;
if (++$attempt === $socketContext->getMaxAttempts()) { if (++$attempt === $socketContext->getMaxAttempts()) {
break; break;
} }

View File

@ -54,11 +54,11 @@ class DocsBuilder
{ {
\danog\MadelineProto\Logger::log('Generating documentation index...', \danog\MadelineProto\Logger::NOTICE); \danog\MadelineProto\Logger::log('Generating documentation index...', \danog\MadelineProto\Logger::NOTICE);
\file_put_contents($this->index, '--- \file_put_contents($this->index, '---
title: ' . $this->settings['title'] . ' title: '.$this->settings['title'].'
description: ' . $this->settings['description'] . ' description: '.$this->settings['description'].'
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
--- ---
# ' . $this->settings['description'] . ' # '.$this->settings['description'].'
[Back to main documentation](..) [Back to main documentation](..)
@ -86,14 +86,14 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
//$br = $new_namespace != $last_namespace ? '***<br><br>' : ''; //$br = $new_namespace != $last_namespace ? '***<br><br>' : '';
$type = \str_replace(['<', '>'], ['_of_', ''], $otype); $type = \str_replace(['<', '>'], ['_of_', ''], $otype);
$type = \preg_replace('/.*_of_/', '', $type); $type = \preg_replace('/.*_of_/', '', $type);
$index .= '[' . \str_replace('_', '\\_', $type) . '](' . $type . '.md)<a name="' . $type . '"></a> $index .= '['.\str_replace('_', '\\_', $type).']('.$type.'.md)<a name="'.$type.'"></a>
'; ';
$constructors = ''; $constructors = '';
foreach ($keys['constructors'] as $data) { foreach ($keys['constructors'] as $data) {
$predicate = $data['predicate'] . (isset($data['layer']) && $data['layer'] !== '' ? '_' . $data['layer'] : ''); $predicate = $data['predicate'].(isset($data['layer']) && $data['layer'] !== '' ? '_'.$data['layer'] : '');
$md_predicate = \str_replace('_', '\\_', $predicate); $md_predicate = \str_replace('_', '\\_', $predicate);
$constructors .= '[' . $md_predicate . '](../constructors/' . $predicate . '.md) $constructors .= '['.$md_predicate.'](../constructors/'.$predicate.'.md)
'; ';
} }
@ -101,25 +101,25 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
foreach ($keys['methods'] as $data) { foreach ($keys['methods'] as $data) {
$name = $data['method']; $name = $data['method'];
$md_name = \str_replace(['.', '_'], ['->', '\\_'], $name); $md_name = \str_replace(['.', '_'], ['->', '\\_'], $name);
$methods .= '[$MadelineProto->' . $md_name . '](../methods/' . $name . '.md) $methods .= '[$MadelineProto->'.$md_name.'](../methods/'.$name.'.md)
'; ';
} }
$description = isset($this->td_descriptions['types'][$otype]) ? $this->td_descriptions['types'][$otype] : 'constructors and methods of type ' . $type; $description = isset($this->td_descriptions['types'][$otype]) ? $this->td_descriptions['types'][$otype] : 'constructors and methods of type '.$type;
$symFile = \str_replace('.', '_', $type); $symFile = \str_replace('.', '_', $type);
$redir = $symFile !== $type ? "\nredirect_from: /API_docs/types/{$symFile}.html" : ''; $redir = $symFile !== $type ? "\nredirect_from: /API_docs/types/{$symFile}.html" : '';
$header = '--- $header = '---
title: ' . $type . ' title: '.$type.'
description: constructors and methods of type ' . $type . ' description: constructors and methods of type '.$type.'
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png' . $redir . ' image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png'.$redir.'
--- ---
# Type: ' . \str_replace('_', '\\_', $type) . ' # Type: '.\str_replace('_', '\\_', $type).'
[Back to types index](index.md) [Back to types index](index.md)
'; ';
$header .= isset($this->td_descriptions['types'][$otype]) ? $this->td_descriptions['types'][$otype] . PHP_EOL . PHP_EOL : ''; $header .= isset($this->td_descriptions['types'][$otype]) ? $this->td_descriptions['types'][$otype].PHP_EOL.PHP_EOL : '';
if (!isset($this->settings['td'])) { if (!isset($this->settings['td'])) {
if (\in_array($type, ['User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputDialogPeer', 'DialogPeer', 'InputPeer', 'NotifyPeer', 'InputNotifyPeer'])) { if (\in_array($type, ['User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputDialogPeer', 'DialogPeer', 'InputPeer', 'NotifyPeer', 'InputNotifyPeer'])) {
$header .= 'You can directly provide the [Update](Update.md) or [Message](Message.md) object here, MadelineProto will automatically extract the destination chat id. $header .= 'You can directly provide the [Update](Update.md) or [Message](Message.md) object here, MadelineProto will automatically extract the destination chat id.
@ -127,11 +127,11 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png' . $re
The following syntaxes can also be used: The following syntaxes can also be used:
``` ```
$' . $type . " = '@username'; // Username\n\n\$" . $type . " = 'me'; // The currently logged-in user\n\n\$" . $type . ' = 44700; // bot API id (users) $'.$type." = '@username'; // Username\n\n\$".$type." = 'me'; // The currently logged-in user\n\n\$".$type.' = 44700; // bot API id (users)
$' . $type . ' = -492772765; // bot API id (chats) $'.$type.' = -492772765; // bot API id (chats)
$' . $type . ' = -10038575794; // bot API id (channels) $'.$type.' = -10038575794; // bot API id (channels)
$' . $type . " = 'https://t.me/danogentili'; // t.me URLs\n\$" . $type . " = 'https://t.me/joinchat/asfln1-21fa_'; // t.me invite links\n\n\$" . $type . " = 'user#44700'; // tg-cli style id (users)\n\$" . $type . " = 'chat#492772765'; // tg-cli style id (chats)\n\$" . $type . " = 'channel#38575794'; // tg-cli style id (channels)\n```\n\nA [Chat](Chat.md), a [User](User.md), an [InputPeer](InputPeer.md), an [InputDialogPeer](InputDialogPeer.md), an [InputNotifyPeer](InputNotifyPeer.md), an [InputUser](InputUser.md), an [InputChannel](InputChannel.md), a [Peer](Peer.md), an [DialogPeer](DialogPeer.md), [NotifyPeer](NotifyPeer.md), or a [Chat](Chat.md) object can also be used.\n\n\n"; $'.$type." = 'https://t.me/danogentili'; // t.me URLs\n\$".$type." = 'https://t.me/joinchat/asfln1-21fa_'; // t.me invite links\n\n\$".$type." = 'user#44700'; // tg-cli style id (users)\n\$".$type." = 'chat#492772765'; // tg-cli style id (chats)\n\$".$type." = 'channel#38575794'; // tg-cli style id (channels)\n```\n\nA [Chat](Chat.md), a [User](User.md), an [InputPeer](InputPeer.md), an [InputDialogPeer](InputDialogPeer.md), an [InputNotifyPeer](InputNotifyPeer.md), an [InputUser](InputUser.md), an [InputChannel](InputChannel.md), a [Peer](Peer.md), an [DialogPeer](DialogPeer.md), [NotifyPeer](NotifyPeer.md), or a [Chat](Chat.md) object can also be used.\n\n\n";
} }
if (\in_array($type, ['InputEncryptedChat'])) { if (\in_array($type, ['InputEncryptedChat'])) {
$header .= 'You can directly provide the [Update](Update.md) or [EncryptedMessage](EncryptedMessage.md) object here, MadelineProto will automatically extract the destination chat id. $header .= 'You can directly provide the [Update](Update.md) or [EncryptedMessage](EncryptedMessage.md) object here, MadelineProto will automatically extract the destination chat id.
@ -139,7 +139,7 @@ $' . $type . " = 'https://t.me/danogentili'; // t.me URLs\n\$" . $type . " = 'ht
The following syntax can also be used: The following syntax can also be used:
``` ```
$' . $type . ' = -147286699; // Numeric chat id returned by requestSecretChat, can be positive or negative $'.$type.' = -147286699; // Numeric chat id returned by requestSecretChat, can be positive or negative
``` ```
@ -149,7 +149,7 @@ $' . $type . ' = -147286699; // Numeric chat id returned by requestSecretChat, c
$header .= 'The following syntax can also be used: $header .= 'The following syntax can also be used:
``` ```
$' . $type . ' = \'filename.mp4\'; // The file path can also be used $'.$type.' = \'filename.mp4\'; // The file path can also be used
``` ```
@ -174,7 +174,7 @@ $' . $type . ' = \'filename.mp4\'; // The file path can also be used
$header .= 'The following syntax can also be used: $header .= 'The following syntax can also be used:
``` ```
$' . $type . ' = 142; // Numeric message ID $'.$type.' = 142; // Numeric message ID
``` ```
@ -186,7 +186,7 @@ $' . $type . ' = 142; // Numeric message ID
To click these buttons simply run the `click` method: To click these buttons simply run the `click` method:
``` ```
$result = $' . $type . '->click(); $result = $'.$type.'->click();
``` ```
`$result` can be one of the following: `$result` can be one of the following:
@ -207,12 +207,12 @@ You can also access the properties of the constructor as a normal array, for exa
} }
$constructors = '### Possible values (constructors): $constructors = '### Possible values (constructors):
' . $constructors . ' '.$constructors.'
'; ';
$methods = '### Methods that return an object of this type (methods): $methods = '### Methods that return an object of this type (methods):
' . $methods . ' '.$methods.'
'; ';
if (!isset($this->settings['td'])) { if (!isset($this->settings['td'])) {
@ -399,14 +399,14 @@ After modifying it, you must always parse the new configuration with a call to `
'; ';
} }
} }
if (\file_exists('types/' . $type . '.md')) { if (\file_exists('types/'.$type.'.md')) {
\danog\MadelineProto\Logger::log($type); \danog\MadelineProto\Logger::log($type);
} }
\file_put_contents('types/' . $type . '.md', $header . $constructors . $methods); \file_put_contents('types/'.$type.'.md', $header.$constructors.$methods);
$last_namespace = $new_namespace; $last_namespace = $new_namespace;
} }
\danog\MadelineProto\Logger::log('Generating types index...', \danog\MadelineProto\Logger::NOTICE); \danog\MadelineProto\Logger::log('Generating types index...', \danog\MadelineProto\Logger::NOTICE);
\file_put_contents('types/' . $this->index, '--- \file_put_contents('types/'.$this->index, '---
title: Types title: Types
description: List of types description: List of types
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
@ -415,7 +415,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
[Back to API documentation index](..) [Back to API documentation index](..)
' . $index); '.$index);
\danog\MadelineProto\Logger::log('Generating additional types...', \danog\MadelineProto\Logger::NOTICE); \danog\MadelineProto\Logger::log('Generating additional types...', \danog\MadelineProto\Logger::NOTICE);
\file_put_contents('types/string.md', '--- \file_put_contents('types/string.md', '---
title: string title: string
@ -621,7 +621,7 @@ class Lang
{ {
if (!isset(\danog\MadelineProto\Lang::$lang['en'][$key]) || $force) { if (!isset(\danog\MadelineProto\Lang::$lang['en'][$key]) || $force) {
\danog\MadelineProto\Lang::$lang['en'][$key] = $value; \danog\MadelineProto\Lang::$lang['en'][$key] = $value;
\file_put_contents(__DIR__ . '/Lang.php', \sprintf(self::$template, \var_export(\danog\MadelineProto\Lang::$lang, true), \var_export(\danog\MadelineProto\Lang::$lang['en'], true))); \file_put_contents(__DIR__.'/Lang.php', \sprintf(self::$template, \var_export(\danog\MadelineProto\Lang::$lang, true), \var_export(\danog\MadelineProto\Lang::$lang['en'], true)));
} }
} }
} }

View File

@ -25,7 +25,7 @@ trait Constructors
{ {
public function mkConstructors() public function mkConstructors()
{ {
foreach (\glob('constructors/' . $this->any) as $unlink) { foreach (\glob('constructors/'.$this->any) as $unlink) {
\unlink($unlink); \unlink($unlink);
} }
if (\file_exists('constructors')) { if (\file_exists('constructors')) {
@ -45,7 +45,7 @@ trait Constructors
if (preg_match('/%/', $type)) { if (preg_match('/%/', $type)) {
$type = $this->TL->getConstructors($this->td)->findByType(str_replace('%', '', $type))['predicate']; $type = $this->TL->getConstructors($this->td)->findByType(str_replace('%', '', $type))['predicate'];
}*/ }*/
$layer = isset($data['layer']) && $data['layer'] !== '' ? '_' . $data['layer'] : ''; $layer = isset($data['layer']) && $data['layer'] !== '' ? '_'.$data['layer'] : '';
$type = \str_replace(['<', '>'], ['_of_', ''], $data['type']); $type = \str_replace(['<', '>'], ['_of_', ''], $data['type']);
$php_type = \preg_replace('/.*_of_/', '', $type); $php_type = \preg_replace('/.*_of_/', '', $type);
$constructor = \str_replace(['<', '>'], ['_of_', ''], $data['predicate']); $constructor = \str_replace(['<', '>'], ['_of_', ''], $data['predicate']);
@ -74,12 +74,12 @@ trait Constructors
if (\substr($param[$type_or_subtype], -1) === '>') { if (\substr($param[$type_or_subtype], -1) === '>') {
$param[$type_or_subtype] = \substr($param[$type_or_subtype], 0, -1); $param[$type_or_subtype] = \substr($param[$type_or_subtype], 0, -1);
} }
$params .= "'" . $param['name'] . "' => "; $params .= "'".$param['name']."' => ";
$param[$type_or_subtype] = '[' . Tools::markdownEscape($param[$type_or_subtype]) . '](../' . $type_or_bare_type . '/' . $param[$type_or_subtype] . '.md)'; $param[$type_or_subtype] = '['.Tools::markdownEscape($param[$type_or_subtype]).'](../'.$type_or_bare_type.'/'.$param[$type_or_subtype].'.md)';
$params .= (isset($param['subtype']) ? '\\[' . $param[$type_or_subtype] . '\\]' : $param[$type_or_subtype]) . ', '; $params .= (isset($param['subtype']) ? '\\['.$param[$type_or_subtype].'\\]' : $param[$type_or_subtype]).', ';
} }
$md_constructor = \str_replace('_', '\\_', $constructor . $layer); $md_constructor = \str_replace('_', '\\_', $constructor.$layer);
$this->docs_constructors[$constructor] = '[$' . $md_constructor . '](../constructors/' . $php_constructor . $layer . '.md) = \\[' . $params . '\\];<a name="' . $constructor . $layer . '"></a> $this->docs_constructors[$constructor] = '[$'.$md_constructor.'](../constructors/'.$php_constructor.$layer.'.md) = \\['.$params.'\\];<a name="'.$constructor.$layer.'"></a>
'; ';
$table = empty($data['params']) ? '' : '### Attributes: $table = empty($data['params']) ? '' : '### Attributes:
@ -88,9 +88,9 @@ trait Constructors
|----------|---------------|----------| |----------|---------------|----------|
'; ';
if (!isset($this->TL->getDescriptions()['constructors'][$data['predicate']])) { if (!isset($this->TL->getDescriptions()['constructors'][$data['predicate']])) {
$this->addToLang('object_' . $data['predicate']); $this->addToLang('object_'.$data['predicate']);
if (\danog\MadelineProto\Lang::$lang['en']['object_' . $data['predicate']] !== '') { if (\danog\MadelineProto\Lang::$lang['en']['object_'.$data['predicate']] !== '') {
$this->TL->getDescriptions()['constructors'][$data['predicate']]['description'] = \danog\MadelineProto\Lang::$lang['en']['object_' . $data['predicate']]; $this->TL->getDescriptions()['constructors'][$data['predicate']]['description'] = \danog\MadelineProto\Lang::$lang['en']['object_'.$data['predicate']];
} }
} }
if (isset($this->TL->getDescriptions()['constructors'][$data['predicate']]) && !empty($data['params'])) { if (isset($this->TL->getDescriptions()['constructors'][$data['predicate']]) && !empty($data['params'])) {
@ -114,7 +114,7 @@ trait Constructors
$param['type'] = 'DecryptedMessage'; $param['type'] = 'DecryptedMessage';
} }
if ($type === 'DecryptedMessageMedia' && \in_array($param['name'], ['key', 'iv'])) { if ($type === 'DecryptedMessageMedia' && \in_array($param['name'], ['key', 'iv'])) {
unset(\danog\MadelineProto\Lang::$lang['en']['object_' . $data['predicate'] . '_param_' . $param['name'] . '_type_' . $param['type']]); unset(\danog\MadelineProto\Lang::$lang['en']['object_'.$data['predicate'].'_param_'.$param['name'].'_type_'.$param['type']]);
continue; continue;
} }
$ptype = $param[isset($param['subtype']) ? 'subtype' : 'type']; $ptype = $param[isset($param['subtype']) ? 'subtype' : 'type'];
@ -138,58 +138,58 @@ trait Constructors
} }
$human_ptype = $ptype; $human_ptype = $ptype;
if (\strpos($type, 'Input') === 0 && \in_array($ptype, ['User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputDialogPeer', 'DialogPeer', 'NotifyPeer', 'InputNotifyPeer', 'InputPeer']) && !isset($this->settings['td'])) { if (\strpos($type, 'Input') === 0 && \in_array($ptype, ['User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputDialogPeer', 'DialogPeer', 'NotifyPeer', 'InputNotifyPeer', 'InputPeer']) && !isset($this->settings['td'])) {
$human_ptype = 'Username, chat ID, Update, Message or ' . $ptype; $human_ptype = 'Username, chat ID, Update, Message or '.$ptype;
} }
if (\strpos($type, 'Input') === 0 && \in_array($ptype, ['InputMedia', 'InputDocument', 'InputPhoto']) && !isset($this->settings['td'])) { if (\strpos($type, 'Input') === 0 && \in_array($ptype, ['InputMedia', 'InputDocument', 'InputPhoto']) && !isset($this->settings['td'])) {
$human_ptype = 'MessageMedia, Message, Update or ' . $ptype; $human_ptype = 'MessageMedia, Message, Update or '.$ptype;
} }
if (\in_array($ptype, ['InputMessage']) && !isset($this->settings['td'])) { if (\in_array($ptype, ['InputMessage']) && !isset($this->settings['td'])) {
$human_ptype = 'Message ID or ' . $ptype; $human_ptype = 'Message ID or '.$ptype;
} }
if (\in_array($ptype, ['InputEncryptedChat']) && !isset($this->settings['td'])) { if (\in_array($ptype, ['InputEncryptedChat']) && !isset($this->settings['td'])) {
$human_ptype = 'Secret chat ID, Update, EncryptedMessage or ' . $ptype; $human_ptype = 'Secret chat ID, Update, EncryptedMessage or '.$ptype;
} }
if (\in_array($ptype, ['InputFile']) && !isset($this->settings['td'])) { if (\in_array($ptype, ['InputFile']) && !isset($this->settings['td'])) {
$human_ptype = 'File path or ' . $ptype; $human_ptype = 'File path or '.$ptype;
} }
if (\in_array($ptype, ['InputEncryptedFile']) && !isset($this->settings['td'])) { if (\in_array($ptype, ['InputEncryptedFile']) && !isset($this->settings['td'])) {
$human_ptype = 'File path or ' . $ptype; $human_ptype = 'File path or '.$ptype;
} }
$table .= '|' . \str_replace('_', '\\_', $param['name']) . '|' . (isset($param['subtype']) ? 'Array of ' : '') . '[' . \str_replace('_', '\\_', $human_ptype) . '](../' . $type_or_bare_type . '/' . $ptype . '.md) | ' . (isset($param['pow']) || $this->TL->getConstructors($this->td)->findByPredicate(\lcfirst($param['type']) . 'Empty') || $data['type'] === 'InputMedia' && $param['name'] === 'mime_type' || $data['type'] === 'DocumentAttribute' && \in_array($param['name'], ['w', 'h', 'duration']) ? 'Optional' : 'Yes') . '|'; $table .= '|'.\str_replace('_', '\\_', $param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.\str_replace('_', '\\_', $human_ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.(isset($param['pow']) || $this->TL->getConstructors($this->td)->findByPredicate(\lcfirst($param['type']).'Empty') || $data['type'] === 'InputMedia' && $param['name'] === 'mime_type' || $data['type'] === 'DocumentAttribute' && \in_array($param['name'], ['w', 'h', 'duration']) ? 'Optional' : 'Yes').'|';
if (!isset($this->TL->getDescriptions()['constructors'][$data['predicate']]['params'][$param['name']])) { if (!isset($this->TL->getDescriptions()['constructors'][$data['predicate']]['params'][$param['name']])) {
$this->addToLang('object_' . $data['predicate'] . '_param_' . $param['name'] . '_type_' . $param['type']); $this->addToLang('object_'.$data['predicate'].'_param_'.$param['name'].'_type_'.$param['type']);
if (isset($this->TL->getDescriptions()['constructors'][$data['predicate']]['description'])) { if (isset($this->TL->getDescriptions()['constructors'][$data['predicate']]['description'])) {
$this->TL->getDescriptions()['constructors'][$data['predicate']]['params'][$param['name']] = \danog\MadelineProto\Lang::$lang['en']['object_' . $data['predicate'] . '_param_' . $param['name'] . '_type_' . $param['type']]; $this->TL->getDescriptions()['constructors'][$data['predicate']]['params'][$param['name']] = \danog\MadelineProto\Lang::$lang['en']['object_'.$data['predicate'].'_param_'.$param['name'].'_type_'.$param['type']];
} }
} }
if (isset($this->TL->getDescriptions()['constructors'][$data['predicate']]['params'][$param['name']])) { if (isset($this->TL->getDescriptions()['constructors'][$data['predicate']]['params'][$param['name']])) {
$table .= $this->TL->getDescriptions()['constructors'][$data['predicate']]['params'][$param['name']] . '|'; $table .= $this->TL->getDescriptions()['constructors'][$data['predicate']]['params'][$param['name']].'|';
} }
$table .= PHP_EOL; $table .= PHP_EOL;
$pptype = \in_array($ptype, ['string', 'bytes']) ? "'" . $ptype . "'" : $ptype; $pptype = \in_array($ptype, ['string', 'bytes']) ? "'".$ptype."'" : $ptype;
$ppptype = \in_array($ptype, ['string']) ? '"' . $ptype . '"' : $ptype; $ppptype = \in_array($ptype, ['string']) ? '"'.$ptype.'"' : $ptype;
$ppptype = \in_array($ptype, ['bytes']) ? '{"_": "bytes", "bytes":"base64 encoded ' . $ptype . '"}' : $ppptype; $ppptype = \in_array($ptype, ['bytes']) ? '{"_": "bytes", "bytes":"base64 encoded '.$ptype.'"}' : $ppptype;
$params .= ", '" . $param['name'] . "' => "; $params .= ", '".$param['name']."' => ";
$params .= isset($param['subtype']) ? '[' . $pptype . ', ' . $pptype . ']' : $pptype; $params .= isset($param['subtype']) ? '['.$pptype.', '.$pptype.']' : $pptype;
$lua_params .= ', ' . $param['name'] . '='; $lua_params .= ', '.$param['name'].'=';
$lua_params .= isset($param['subtype']) ? '{' . $pptype . '}' : $pptype; $lua_params .= isset($param['subtype']) ? '{'.$pptype.'}' : $pptype;
$pwr_params .= ', "' . $param['name'] . '": ' . (isset($param['subtype']) ? '[' . $ppptype . ']' : $ppptype); $pwr_params .= ', "'.$param['name'].'": '.(isset($param['subtype']) ? '['.$ppptype.']' : $ppptype);
if ($param['name'] === 'reply_markup') { if ($param['name'] === 'reply_markup') {
$hasreplymarkup = true; $hasreplymarkup = true;
} }
} }
$params = "['_' => '" . $data['predicate'] . "'" . $params . ']'; $params = "['_' => '".$data['predicate']."'".$params.']';
$lua_params = "{_='" . $data['predicate'] . "'" . $lua_params . '}'; $lua_params = "{_='".$data['predicate']."'".$lua_params.'}';
$pwr_params = '{"_": "' . $data['predicate'] . '"' . $pwr_params . '}'; $pwr_params = '{"_": "'.$data['predicate'].'"'.$pwr_params.'}';
$description = isset($this->TL->getDescriptions()['constructors'][$data['predicate']]) ? $this->TL->getDescriptions()['constructors'][$data['predicate']]['description'] : $constructor . ' attributes, type and example'; $description = isset($this->TL->getDescriptions()['constructors'][$data['predicate']]) ? $this->TL->getDescriptions()['constructors'][$data['predicate']]['description'] : $constructor.' attributes, type and example';
$symFile = \str_replace('.', '_', $constructor . $layer); $symFile = \str_replace('.', '_', $constructor.$layer);
$redir = $symFile !== $constructor . $layer ? "\nredirect_from: /API_docs/constructors/{$symFile}.html" : ''; $redir = $symFile !== $constructor.$layer ? "\nredirect_from: /API_docs/constructors/{$symFile}.html" : '';
$header = '--- $header = '---
title: ' . $data['predicate'] . ' title: '.$data['predicate'].'
description: ' . $description . ' description: '.$description.'
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png' . $redir . ' image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png'.$redir.'
--- ---
# Constructor: ' . \str_replace('_', '\\_', $data['predicate'] . $layer) . ' # Constructor: '.\str_replace('_', '\\_', $data['predicate'].$layer).'
[Back to constructors index](index.md) [Back to constructors index](index.md)
@ -200,9 +200,9 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png' . $re
'; ';
if (isset($this->TL->getDescriptions()['constructors'][$data['predicate']])) { if (isset($this->TL->getDescriptions()['constructors'][$data['predicate']])) {
$header .= $this->TL->getDescriptions()['constructors'][$data['predicate']]['description'] . PHP_EOL . PHP_EOL; $header .= $this->TL->getDescriptions()['constructors'][$data['predicate']]['description'].PHP_EOL.PHP_EOL;
} }
$type = '### Type: [' . \str_replace('_', '\\_', $php_type) . '](../types/' . $php_type . '.md) $type = '### Type: ['.\str_replace('_', '\\_', $php_type).'](../types/'.$php_type.'.md)
'; ';
@ -211,14 +211,14 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png' . $re
$example = '### Example: $example = '### Example:
```php ```php
$' . $constructor . $layer . ' = ' . $params . '; $'.$constructor.$layer.' = '.$params.';
``` ```
Or, if you\'re into Lua: Or, if you\'re into Lua:
```lua ```lua
' . $constructor . $layer . '=' . $lua_params . ' '.$constructor.$layer.'='.$lua_params.'
``` ```
@ -268,7 +268,7 @@ MadelineProto supports all html entities supported by [html_entity_decode](http:
'; ';
} }
} }
\file_put_contents('constructors/' . $constructor . $layer . '.md', $header . $table . $type . $example); \file_put_contents('constructors/'.$constructor.$layer.'.md', $header.$table.$type.$example);
} }
$this->logger->logger('Generating constructors index...', \danog\MadelineProto\Logger::NOTICE); $this->logger->logger('Generating constructors index...', \danog\MadelineProto\Logger::NOTICE);
\ksort($this->docs_constructors); \ksort($this->docs_constructors);
@ -277,10 +277,10 @@ MadelineProto supports all html entities supported by [html_entity_decode](http:
$new_namespace = \preg_replace('/_.*/', '', $constructor); $new_namespace = \preg_replace('/_.*/', '', $constructor);
$br = $new_namespace != $last_namespace ? '*** $br = $new_namespace != $last_namespace ? '***
<br><br>' : ''; <br><br>' : '';
$value = $br . $value; $value = $br.$value;
$last_namespace = $new_namespace; $last_namespace = $new_namespace;
} }
\file_put_contents('constructors/' . $this->index, '--- \file_put_contents('constructors/'.$this->index, '---
title: Constructors title: Constructors
description: List of constructors description: List of constructors
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
@ -288,6 +288,6 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
# Constructors # Constructors
[Back to API documentation index](..) [Back to API documentation index](..)
' . \implode('', $this->docs_constructors)); '.\implode('', $this->docs_constructors));
} }
} }

View File

@ -44,7 +44,7 @@ trait Methods
} }
} }
} }
foreach (\glob('methods/' . $this->any) as $unlink) { foreach (\glob('methods/'.$this->any) as $unlink) {
\unlink($unlink); \unlink($unlink);
} }
if (\file_exists('methods')) { if (\file_exists('methods')) {
@ -80,17 +80,17 @@ trait Methods
$type_or_subtype = isset($param['subtype']) ? 'subtype' : 'type'; $type_or_subtype = isset($param['subtype']) ? 'subtype' : 'type';
$type_or_bare_type = \ctype_upper(Tools::end(\explode('.', $param[$type_or_subtype]))[0]) || \in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int', 'long', 'int128', 'int256', 'int512', 'int53']) ? 'types' : 'constructors'; $type_or_bare_type = \ctype_upper(Tools::end(\explode('.', $param[$type_or_subtype]))[0]) || \in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int', 'long', 'int128', 'int256', 'int512', 'int53']) ? 'types' : 'constructors';
$param[$type_or_subtype] = \str_replace(['true', 'false'], ['Bool', 'Bool'], $param[$type_or_subtype]); $param[$type_or_subtype] = \str_replace(['true', 'false'], ['Bool', 'Bool'], $param[$type_or_subtype]);
$param[$type_or_subtype] = '[' . Tools::markdownEscape($param[$type_or_subtype]) . '](../' . $type_or_bare_type . '/' . $param[$type_or_subtype] . '.md)'; $param[$type_or_subtype] = '['.Tools::markdownEscape($param[$type_or_subtype]).'](../'.$type_or_bare_type.'/'.$param[$type_or_subtype].'.md)';
$params .= "'" . $param['name'] . "' => " . (isset($param['subtype']) ? '\\[' . $param[$type_or_subtype] . '\\]' : $param[$type_or_subtype]) . ', '; $params .= "'".$param['name']."' => ".(isset($param['subtype']) ? '\\['.$param[$type_or_subtype].'\\]' : $param[$type_or_subtype]).', ';
} }
if (!isset($this->td_descriptions['methods'][$data['method']])) { if (!isset($this->td_descriptions['methods'][$data['method']])) {
$this->addToLang('method_' . $data['method']); $this->addToLang('method_'.$data['method']);
if (\danog\MadelineProto\Lang::$lang['en']['method_' . $data['method']] !== '') { if (\danog\MadelineProto\Lang::$lang['en']['method_'.$data['method']] !== '') {
$this->td_descriptions['methods'][$data['method']]['description'] = \danog\MadelineProto\Lang::$lang['en']['method_' . $data['method']]; $this->td_descriptions['methods'][$data['method']]['description'] = \danog\MadelineProto\Lang::$lang['en']['method_'.$data['method']];
} }
} }
$md_method = '[' . $php_method . '](' . $method . '.md)'; $md_method = '['.$php_method.']('.$method.'.md)';
$this->docs_methods[$method] = '$MadelineProto->' . $md_method . '(\\[' . $params . '\\]) === [$' . \str_replace('_', '\\_', $type) . '](../types/' . $php_type . '.md)<a name="' . $method . '"></a> $this->docs_methods[$method] = '$MadelineProto->'.$md_method.'(\\['.$params.'\\]) === [$'.\str_replace('_', '\\_', $type).'](../types/'.$php_type.'.md)<a name="'.$method.'"></a>
'; ';
if (isset($this->td_descriptions['methods'][$data['method']])) { if (isset($this->td_descriptions['methods'][$data['method']])) {
@ -98,7 +98,7 @@ trait Methods
$dom = new \DOMDocument(); $dom = new \DOMDocument();
$dom->loadHTML(\mb_convert_encoding($desc, 'HTML-ENTITIES', 'UTF-8')); $dom->loadHTML(\mb_convert_encoding($desc, 'HTML-ENTITIES', 'UTF-8'));
$desc = $dom->textContent; $desc = $dom->textContent;
$this->human_docs_methods[$this->td_descriptions['methods'][$data['method']]['description'] . ': ' . $data['method']] = '* <a href="' . $method . '.html" name="' . $method . '">' . $desc . ': ' . $data['method'] . '</a> $this->human_docs_methods[$this->td_descriptions['methods'][$data['method']]['description'].': '.$data['method']] = '* <a href="'.$method.'.html" name="'.$method.'">'.$desc.': '.$data['method'].'</a>
'; ';
} }
@ -145,45 +145,45 @@ trait Methods
} }
$human_ptype = $ptype; $human_ptype = $ptype;
if (\in_array($ptype, ['InputDialogPeer', 'DialogPeer', 'NotifyPeer', 'InputNotifyPeer', 'User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputPeer']) && !isset($this->settings['td'])) { if (\in_array($ptype, ['InputDialogPeer', 'DialogPeer', 'NotifyPeer', 'InputNotifyPeer', 'User', 'InputUser', 'Chat', 'InputChannel', 'Peer', 'InputPeer']) && !isset($this->settings['td'])) {
$human_ptype = 'Username, chat ID, Update, Message or ' . $ptype; $human_ptype = 'Username, chat ID, Update, Message or '.$ptype;
} }
if (\in_array($ptype, ['InputMedia', 'InputPhoto', 'InputDocument']) && !isset($this->settings['td'])) { if (\in_array($ptype, ['InputMedia', 'InputPhoto', 'InputDocument']) && !isset($this->settings['td'])) {
$human_ptype = 'MessageMedia, Update, Message or ' . $ptype; $human_ptype = 'MessageMedia, Update, Message or '.$ptype;
} }
if (\in_array($ptype, ['InputMessage']) && !isset($this->settings['td'])) { if (\in_array($ptype, ['InputMessage']) && !isset($this->settings['td'])) {
$human_ptype = 'Message ID or ' . $ptype; $human_ptype = 'Message ID or '.$ptype;
} }
if (\in_array($ptype, ['InputEncryptedChat']) && !isset($this->settings['td'])) { if (\in_array($ptype, ['InputEncryptedChat']) && !isset($this->settings['td'])) {
$human_ptype = 'Secret chat ID, Update, EncryptedMessage or ' . $ptype; $human_ptype = 'Secret chat ID, Update, EncryptedMessage or '.$ptype;
} }
if (\in_array($ptype, ['InputFile']) && !isset($this->settings['td'])) { if (\in_array($ptype, ['InputFile']) && !isset($this->settings['td'])) {
$human_ptype = 'File path or ' . $ptype; $human_ptype = 'File path or '.$ptype;
} }
if (\in_array($ptype, ['InputEncryptedFile']) && !isset($this->settings['td'])) { if (\in_array($ptype, ['InputEncryptedFile']) && !isset($this->settings['td'])) {
$human_ptype = 'File path or ' . $ptype; $human_ptype = 'File path or '.$ptype;
} }
$type_or_bare_type = \ctype_upper(Tools::end(\explode('.', $param[$type_or_subtype]))[0]) || \in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int', 'long', 'int128', 'int256', 'int512', 'int53']) ? 'types' : 'constructors'; $type_or_bare_type = \ctype_upper(Tools::end(\explode('.', $param[$type_or_subtype]))[0]) || \in_array($param[$type_or_subtype], ['!X', 'X', 'bytes', 'true', 'false', 'double', 'string', 'Bool', 'int', 'long', 'int128', 'int256', 'int512', 'int53']) ? 'types' : 'constructors';
if (!isset($this->td_descriptions['methods'][$data['method']]['params'][$param['name']])) { if (!isset($this->td_descriptions['methods'][$data['method']]['params'][$param['name']])) {
$this->addToLang('method_' . $data['method'] . '_param_' . $param['name'] . '_type_' . $param['type']); $this->addToLang('method_'.$data['method'].'_param_'.$param['name'].'_type_'.$param['type']);
if (isset($this->td_descriptions['methods'][$data['method']]['description'])) { if (isset($this->td_descriptions['methods'][$data['method']]['description'])) {
$this->td_descriptions['methods'][$data['method']]['params'][$param['name']] = \danog\MadelineProto\Lang::$lang['en']['method_' . $data['method'] . '_param_' . $param['name'] . '_type_' . $param['type']]; $this->td_descriptions['methods'][$data['method']]['params'][$param['name']] = \danog\MadelineProto\Lang::$lang['en']['method_'.$data['method'].'_param_'.$param['name'].'_type_'.$param['type']];
} }
} }
if (isset($this->td_descriptions['methods'][$data['method']])) { if (isset($this->td_descriptions['methods'][$data['method']])) {
$table .= '|' . \str_replace('_', '\\_', $param['name']) . '|' . (isset($param['subtype']) ? 'Array of ' : '') . '[' . \str_replace('_', '\\_', $human_ptype) . '](../' . $type_or_bare_type . '/' . $ptype . '.md) | ' . $this->td_descriptions['methods'][$data['method']]['params'][$param['name']] . ' | ' . (isset($param['pow']) || ($id = $this->TL->getConstructors($this->td)->findByPredicate(\lcfirst($param['type']) . 'Empty')) && $id['type'] === $param['type'] || ($id = $this->TL->getConstructors($this->td)->findByPredicate('input' . $param['type'] . 'Empty')) && $id['type'] === $param['type'] ? 'Optional' : 'Yes') . '|'; $table .= '|'.\str_replace('_', '\\_', $param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.\str_replace('_', '\\_', $human_ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.$this->td_descriptions['methods'][$data['method']]['params'][$param['name']].' | '.(isset($param['pow']) || ($id = $this->TL->getConstructors($this->td)->findByPredicate(\lcfirst($param['type']).'Empty')) && $id['type'] === $param['type'] || ($id = $this->TL->getConstructors($this->td)->findByPredicate('input'.$param['type'].'Empty')) && $id['type'] === $param['type'] ? 'Optional' : 'Yes').'|';
} else { } else {
$table .= '|' . \str_replace('_', '\\_', $param['name']) . '|' . (isset($param['subtype']) ? 'Array of ' : '') . '[' . \str_replace('_', '\\_', $human_ptype) . '](../' . $type_or_bare_type . '/' . $ptype . '.md) | ' . (isset($param['pow']) || ($id = $this->TL->getConstructors($this->td)->findByPredicate(\lcfirst($param['type']) . 'Empty')) && $id['type'] === $param['type'] || ($id = $this->TL->getConstructors($this->td)->findByPredicate('input' . $param['type'] . 'Empty')) && $id['type'] === $param['type'] ? 'Optional' : 'Yes') . '|'; $table .= '|'.\str_replace('_', '\\_', $param['name']).'|'.(isset($param['subtype']) ? 'Array of ' : '').'['.\str_replace('_', '\\_', $human_ptype).'](../'.$type_or_bare_type.'/'.$ptype.'.md) | '.(isset($param['pow']) || ($id = $this->TL->getConstructors($this->td)->findByPredicate(\lcfirst($param['type']).'Empty')) && $id['type'] === $param['type'] || ($id = $this->TL->getConstructors($this->td)->findByPredicate('input'.$param['type'].'Empty')) && $id['type'] === $param['type'] ? 'Optional' : 'Yes').'|';
} }
$table .= PHP_EOL; $table .= PHP_EOL;
$pptype = \in_array($ptype, ['string', 'bytes']) ? "'" . $ptype . "'" : $ptype; $pptype = \in_array($ptype, ['string', 'bytes']) ? "'".$ptype."'" : $ptype;
$ppptype = \in_array($ptype, ['string']) ? '"' . $ptype . '"' : $ptype; $ppptype = \in_array($ptype, ['string']) ? '"'.$ptype.'"' : $ptype;
$ppptype = \in_array($ptype, ['bytes']) ? '{"_": "bytes", "bytes":"base64 encoded ' . $ptype . '"}' : $ppptype; $ppptype = \in_array($ptype, ['bytes']) ? '{"_": "bytes", "bytes":"base64 encoded '.$ptype.'"}' : $ppptype;
$params .= "'" . $param['name'] . "' => "; $params .= "'".$param['name']."' => ";
$params .= (isset($param['subtype']) ? '[' . $pptype . ', ' . $pptype . ']' : $pptype) . ', '; $params .= (isset($param['subtype']) ? '['.$pptype.', '.$pptype.']' : $pptype).', ';
$json_params .= '"' . $param['name'] . '": ' . (isset($param['subtype']) ? '[' . $ppptype . ']' : $ppptype) . ', '; $json_params .= '"'.$param['name'].'": '.(isset($param['subtype']) ? '['.$ppptype.']' : $ppptype).', ';
$pwr_params .= $param['name'] . ' - Json encoded ' . (isset($param['subtype']) ? ' array of ' . $ptype : $ptype) . "\n\n"; $pwr_params .= $param['name'].' - Json encoded '.(isset($param['subtype']) ? ' array of '.$ptype : $ptype)."\n\n";
$lua_params .= $param['name'] . '='; $lua_params .= $param['name'].'=';
$lua_params .= (isset($param['subtype']) ? '{' . $pptype . '}' : $pptype) . ', '; $lua_params .= (isset($param['subtype']) ? '{'.$pptype.'}' : $pptype).', ';
if ($param['name'] === 'reply_markup') { if ($param['name'] === 'reply_markup') {
$hasreplymarkup = true; $hasreplymarkup = true;
} }
@ -200,15 +200,15 @@ trait Methods
$pwr_params = "parseMode - string\n"; $pwr_params = "parseMode - string\n";
} }
} }
$description = isset($this->td_descriptions['methods'][$data['method']]) ? $this->td_descriptions['methods'][$data['method']]['description'] : $data['method'] . ' parameters, return type and example'; $description = isset($this->td_descriptions['methods'][$data['method']]) ? $this->td_descriptions['methods'][$data['method']]['description'] : $data['method'].' parameters, return type and example';
$symFile = \str_replace('.', '_', $method); $symFile = \str_replace('.', '_', $method);
$redir = $symFile !== $method ? "\nredirect_from: /API_docs/methods/{$symFile}.html" : ''; $redir = $symFile !== $method ? "\nredirect_from: /API_docs/methods/{$symFile}.html" : '';
$header = '--- $header = '---
title: ' . $data['method'] . ' title: '.$data['method'].'
description: ' . $description . ' description: '.$description.'
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png' . $redir . ' image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png'.$redir.'
--- ---
# Method: ' . \str_replace('_', '\\_', $data['method']) . ' # Method: '.\str_replace('_', '\\_', $data['method']).'
[Back to methods index](index.md) [Back to methods index](index.md)
@ -225,17 +225,17 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png' . $re
'; ';
} }
$header .= isset($this->td_descriptions['methods'][$data['method']]) ? $this->td_descriptions['methods'][$data['method']]['description'] . PHP_EOL . PHP_EOL : ''; $header .= isset($this->td_descriptions['methods'][$data['method']]) ? $this->td_descriptions['methods'][$data['method']]['description'].PHP_EOL.PHP_EOL : '';
$table .= ' $table .= '
'; ';
$return = '### Return type: [' . \str_replace('_', '\\_', $type) . '](../types/' . $php_type . '.md) $return = '### Return type: ['.\str_replace('_', '\\_', $type).'](../types/'.$php_type.'.md)
'; ';
$bot = !\in_array($data['method'], $bots); $bot = !\in_array($data['method'], $bots);
$example = ''; $example = '';
if (!isset($this->settings['td'])) { if (!isset($this->settings['td'])) {
$example .= '### Can bots use this method: **' . ($bot ? 'YES' : 'NO') . "**\n\n\n"; $example .= '### Can bots use this method: **'.($bot ? 'YES' : 'NO')."**\n\n\n";
$example .= \str_replace('[]', '', '### MadelineProto Example ([now async for huge speed and parallelism!](https://docs.madelineproto.xyz/docs/ASYNC.html)): $example .= \str_replace('[]', '', '### MadelineProto Example ([now async for huge speed and parallelism!](https://docs.madelineproto.xyz/docs/ASYNC.html)):
@ -248,13 +248,13 @@ include \'madeline.php\';
$MadelineProto = new \\danog\\MadelineProto\\API(\'session.madeline\'); $MadelineProto = new \\danog\\MadelineProto\\API(\'session.madeline\');
$MadelineProto->start(); $MadelineProto->start();
$' . $type . ' = $MadelineProto->' . $php_method . '([' . $params . ']); $'.$type.' = $MadelineProto->'.$php_method.'(['.$params.']);
``` ```
Or, if you\'re into Lua: Or, if you\'re into Lua:
```lua ```lua
' . $type . ' = ' . $data['method'] . '({' . $lua_params . '}) '.$type.' = '.$data['method'].'({'.$lua_params.'})
``` ```
'); ');
@ -271,7 +271,7 @@ You can provide bot API reply_markup objects here.
$example .= ' $example .= '
## Return value ## Return value
If the length of the provided message is bigger than 4096, the message will be split in chunks and the method will be called multiple times, with the same parameters (except for the message), and an array of [' . \str_replace('_', '\\_', $type) . '](../types/' . $php_type . '.md) will be returned instead. If the length of the provided message is bigger than 4096, the message will be split in chunks and the method will be called multiple times, with the same parameters (except for the message), and an array of ['.\str_replace('_', '\\_', $type).'](../types/'.$php_type.'.md) will be returned instead.
'; ';
@ -323,12 +323,12 @@ MadelineProto supports all html entities supported by [html_entity_decode](http:
'; ';
foreach ($new['result'][$data['method']] as $error) { foreach ($new['result'][$data['method']] as $error) {
[$error, $code] = $error; [$error, $code] = $error;
$example .= "|{$code}|{$error}|" . $errors['human_result'][$error][0] . '|' . "\n"; $example .= "|{$code}|{$error}|".$errors['human_result'][$error][0].'|'."\n";
} }
$example .= "\n\n"; $example .= "\n\n";
} }
} }
\file_put_contents('methods/' . $method . '.md', $header . $table . $return . $example); \file_put_contents('methods/'.$method.'.md', $header.$table.$return.$example);
} }
$this->logger->logger('Generating methods index...', \danog\MadelineProto\Logger::NOTICE); $this->logger->logger('Generating methods index...', \danog\MadelineProto\Logger::NOTICE);
\ksort($this->docs_methods); \ksort($this->docs_methods);
@ -339,10 +339,10 @@ MadelineProto supports all html entities supported by [html_entity_decode](http:
$br = $new_namespace != $last_namespace ? '*** $br = $new_namespace != $last_namespace ? '***
<br><br> <br><br>
' : ''; ' : '';
$value = $br . $value; $value = $br.$value;
$last_namespace = $new_namespace; $last_namespace = $new_namespace;
} }
\file_put_contents('methods/api_' . $this->index, '--- \file_put_contents('methods/api_'.$this->index, '---
title: Methods title: Methods
description: List of methods description: List of methods
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
@ -350,7 +350,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
# Methods # Methods
[Back to API documentation index](..) [Back to API documentation index](..)
[Go to the new description-version method index](' . $this->index . ') [Go to the new description-version method index]('.$this->index.')
$MadelineProto->[logout](https://docs.madelineproto.xyz/logout.html)(); $MadelineProto->[logout](https://docs.madelineproto.xyz/logout.html)();
@ -378,8 +378,8 @@ $MadelineProto->[requestCall](https://docs.madelineproto.xyz/requestCall.html)($
$MadelineProto->[requestSecretChat](https://docs.madelineproto.xyz/requestSecretChat.html)($id); $MadelineProto->[requestSecretChat](https://docs.madelineproto.xyz/requestSecretChat.html)($id);
' . \implode('', $this->docs_methods)); '.\implode('', $this->docs_methods));
\file_put_contents('methods/' . $this->index, '--- \file_put_contents('methods/'.$this->index, '---
title: Methods title: Methods
description: What do you want to do? description: What do you want to do?
image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
@ -387,7 +387,7 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
# What do you want to do? # What do you want to do?
[Go back to API documentation index](..) [Go back to API documentation index](..)
[Go to the old code-version method index](api_' . $this->index . ') [Go to the old code-version method index](api_'.$this->index.')
* [Logout](https://docs.madelineproto.xyz/logout.html) * [Logout](https://docs.madelineproto.xyz/logout.html)
@ -411,6 +411,6 @@ image: https://docs.madelineproto.xyz/favicons/android-chrome-256x256.png
* [Create a secret chat bot](https://docs.madelineproto.xyz/docs/SECRET_CHATS.html) * [Create a secret chat bot](https://docs.madelineproto.xyz/docs/SECRET_CHATS.html)
' . \implode('', $this->human_docs_methods)); '.\implode('', $this->human_docs_methods));
} }
} }

View File

@ -126,7 +126,7 @@ class Logger
$settings['logger']['logger_param'] = $settings['logger']['param']; $settings['logger']['logger_param'] = $settings['logger']['param'];
} }
if (PHP_SAPI !== 'cli' && isset($settings['logger']['logger_param']) && $settings['logger']['logger_param'] === 'MadelineProto.log') { if (PHP_SAPI !== 'cli' && isset($settings['logger']['logger_param']) && $settings['logger']['logger_param'] === 'MadelineProto.log') {
$settings['logger']['logger_param'] = Magic::$script_cwd . '/MadelineProto.log'; $settings['logger']['logger_param'] = Magic::$script_cwd.'/MadelineProto.log';
} }
$logger = new self($settings['logger']['logger'], $settings['logger']['logger_param'] ?? '', $prefix, $settings['logger']['logger_level'] ?? Logger::VERBOSE, $settings['logger']['max_size'] ?? 100 * 1024 * 1024); $logger = new self($settings['logger']['logger'], $settings['logger']['logger_param'] ?? '', $prefix, $settings['logger']['logger_level'] ?? Logger::VERBOSE, $settings['logger']['max_size'] ?? 100 * 1024 * 1024);
if (!self::$default) { if (!self::$default) {
@ -136,7 +136,7 @@ class Logger
try { try {
\error_reporting(E_ALL); \error_reporting(E_ALL);
\ini_set('log_errors', 1); \ini_set('log_errors', 1);
\ini_set('error_log', $settings['logger']['logger'] === self::FILE_LOGGER ? $settings['logger']['logger_param'] : Magic::$script_cwd . '/MadelineProto.log'); \ini_set('error_log', $settings['logger']['logger'] === self::FILE_LOGGER ? $settings['logger']['logger_param'] : Magic::$script_cwd.'/MadelineProto.log');
\error_log('Enabled PHP logging'); \error_log('Enabled PHP logging');
} catch (\danog\MadelineProto\Exception $e) { } catch (\danog\MadelineProto\Exception $e) {
$logger->logger('Could not enable PHP logging'); $logger->logger('Could not enable PHP logging');
@ -176,11 +176,11 @@ class Logger
throw new Exception(\danog\MadelineProto\Lang::$current_lang['no_mode_specified']); throw new Exception(\danog\MadelineProto\Lang::$current_lang['no_mode_specified']);
} }
$this->mode = $mode; $this->mode = $mode;
$this->optional = $mode == 2 ? Absolute::absolute($optional) : $optional; $this->optional = $mode == 2 ? Tools::absolute($optional) : $optional;
$this->prefix = $prefix === '' ? '' : ', ' . $prefix; $this->prefix = $prefix === '' ? '' : ', '.$prefix;
$this->level = $level; $this->level = $level;
if ($this->mode === 2 && !\file_exists(\pathinfo($this->optional, PATHINFO_DIRNAME))) { if ($this->mode === 2 && !\file_exists(\pathinfo($this->optional, PATHINFO_DIRNAME))) {
$this->optional = Magic::$script_cwd . '/MadelineProto.log'; $this->optional = Magic::$script_cwd.'/MadelineProto.log';
} }
if ($this->mode === 2 && !\preg_match('/\\.log$/', $this->optional)) { if ($this->mode === 2 && !\preg_match('/\\.log$/', $this->optional)) {
$this->optional .= '.log'; $this->optional .= '.log';
@ -198,7 +198,7 @@ class Logger
if ($this->mode === 3) { if ($this->mode === 3) {
$this->stdout = getStdout(); $this->stdout = getStdout();
if (PHP_SAPI !== 'cli') { if (PHP_SAPI !== 'cli') {
$this->newline = '<br>' . $this->newline; $this->newline = '<br>'.$this->newline;
} }
} elseif ($this->mode === 2) { } elseif ($this->mode === 2) {
$this->stdout = new ResourceOutputStream(\fopen($this->optional, 'a+')); $this->stdout = new ResourceOutputStream(\fopen($this->optional, 'a+'));
@ -226,7 +226,7 @@ class Logger
if (!\is_null(self::$default)) { if (!\is_null(self::$default)) {
self::$default->logger($param, $level, \basename(\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php')); self::$default->logger($param, $level, \basename(\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php'));
} else { } else {
echo $param . PHP_EOL; echo $param.PHP_EOL;
} }
} }
/** /**
@ -265,15 +265,15 @@ class Logger
if (empty($file)) { if (empty($file)) {
$file = \basename(\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php'); $file = \basename(\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php');
} }
$param = \str_pad($file . $prefix . ': ', 16 + \strlen($prefix)) . "\t" . $param; $param = \str_pad($file.$prefix.': ', 16 + \strlen($prefix))."\t".$param;
switch ($this->mode) { switch ($this->mode) {
case 1: case 1:
if ($this->stdout->write($param . $this->newline) instanceof Failure) { if ($this->stdout->write($param.$this->newline) instanceof Failure) {
\error_log($param); \error_log($param);
} }
break; break;
default: default:
$param = Magic::$isatty ? "\33[" . $this->colors[$level] . 'm' . $param . "\33[0m" . $this->newline : $param . $this->newline; $param = Magic::$isatty ? "\33[".$this->colors[$level].'m'.$param."\33[0m".$this->newline : $param.$this->newline;
if ($this->stdout->write($param) instanceof Failure) { if ($this->stdout->write($param) instanceof Failure) {
switch ($this->mode) { switch ($this->mode) {
case 3: case 3:

View File

@ -90,17 +90,17 @@ class CheckLoop extends ResumableSignalLoop
foreach (\str_split($result['info']) as $key => $chr) { foreach (\str_split($result['info']) as $key => $chr) {
$message_id = $message_ids[$key]; $message_id = $message_ids[$key];
if (!isset($connection->outgoing_messages[$message_id])) { if (!isset($connection->outgoing_messages[$message_id])) {
$API->logger->logger('Already got response for and forgot about message ID ' . $message_id); $API->logger->logger('Already got response for and forgot about message ID '.$message_id);
continue; continue;
} }
if (!isset($connection->new_outgoing[$message_id])) { if (!isset($connection->new_outgoing[$message_id])) {
$API->logger->logger('Already got response for ' . $connection->outgoing_messages[$message_id]['_'] . ' with message ID ' . $message_id); $API->logger->logger('Already got response for '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.$message_id);
continue; continue;
} }
$chr = \ord($chr); $chr = \ord($chr);
switch ($chr & 7) { switch ($chr & 7) {
case 0: case 0:
$API->logger->logger('Wrong message status 0 for ' . $connection->outgoing_messages[$message_id]['_'], \danog\MadelineProto\Logger::FATAL_ERROR); $API->logger->logger('Wrong message status 0 for '.$connection->outgoing_messages[$message_id]['_'], \danog\MadelineProto\Logger::FATAL_ERROR);
break; break;
case 1: case 1:
case 2: case 2:
@ -109,25 +109,25 @@ class CheckLoop extends ResumableSignalLoop
$connection->gotResponseForOutgoingMessageId($message_id); $connection->gotResponseForOutgoingMessageId($message_id);
break; break;
} }
$API->logger->logger('Message ' . $connection->outgoing_messages[$message_id]['_'] . ' with message ID ' . $message_id . ' not received by server, resending...', \danog\MadelineProto\Logger::ERROR); $API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.$message_id.' not received by server, resending...', \danog\MadelineProto\Logger::ERROR);
$connection->methodRecall('watcherId', ['message_id' => $message_id, 'postpone' => true]); $connection->methodRecall('watcherId', ['message_id' => $message_id, 'postpone' => true]);
break; break;
case 4: case 4:
if ($chr & 32) { if ($chr & 32) {
if ($connection->outgoing_messages[$message_id]['sent'] + $timeoutResend < \time()) { if ($connection->outgoing_messages[$message_id]['sent'] + $timeoutResend < \time()) {
$API->logger->logger('Message ' . $connection->outgoing_messages[$message_id]['_'] . ' with message ID ' . $message_id . ' received by server and is being processed for way too long, resending request...', \danog\MadelineProto\Logger::ERROR); $API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.$message_id.' received by server and is being processed for way too long, resending request...', \danog\MadelineProto\Logger::ERROR);
$connection->methodRecall('', ['message_id' => $message_id, 'postpone' => true]); $connection->methodRecall('', ['message_id' => $message_id, 'postpone' => true]);
} else { } else {
$API->logger->logger('Message ' . $connection->outgoing_messages[$message_id]['_'] . ' with message ID ' . $message_id . ' received by server and is being processed, waiting...', \danog\MadelineProto\Logger::ERROR); $API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.$message_id.' received by server and is being processed, waiting...', \danog\MadelineProto\Logger::ERROR);
} }
} elseif ($chr & 64) { } elseif ($chr & 64) {
$API->logger->logger('Message ' . $connection->outgoing_messages[$message_id]['_'] . ' with message ID ' . $message_id . ' received by server and was already processed, requesting reply...', \danog\MadelineProto\Logger::ERROR); $API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.$message_id.' received by server and was already processed, requesting reply...', \danog\MadelineProto\Logger::ERROR);
$reply[] = $message_id; $reply[] = $message_id;
} elseif ($chr & 128) { } elseif ($chr & 128) {
$API->logger->logger('Message ' . $connection->outgoing_messages[$message_id]['_'] . ' with message ID ' . $message_id . ' received by server and was already sent, requesting reply...', \danog\MadelineProto\Logger::ERROR); $API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.$message_id.' received by server and was already sent, requesting reply...', \danog\MadelineProto\Logger::ERROR);
$reply[] = $message_id; $reply[] = $message_id;
} else { } else {
$API->logger->logger('Message ' . $connection->outgoing_messages[$message_id]['_'] . ' with message ID ' . $message_id . ' received by server, requesting reply...', \danog\MadelineProto\Logger::ERROR); $API->logger->logger('Message '.$connection->outgoing_messages[$message_id]['_'].' with message ID '.$message_id.' received by server, requesting reply...', \danog\MadelineProto\Logger::ERROR);
$reply[] = $message_id; $reply[] = $message_id;
} }
} }
@ -140,7 +140,7 @@ class CheckLoop extends ResumableSignalLoop
$list = ''; $list = '';
// Don't edit this here pls // Don't edit this here pls
foreach ($message_ids as $message_id) { foreach ($message_ids as $message_id) {
$list .= $connection->outgoing_messages[$message_id]['_'] . ', '; $list .= $connection->outgoing_messages[$message_id]['_'].', ';
} }
$API->logger->logger("Still missing {$list} on DC {$datacenter}, sending state request", \danog\MadelineProto\Logger::ERROR); $API->logger->logger("Still missing {$list} on DC {$datacenter}, sending state request", \danog\MadelineProto\Logger::ERROR);
yield from $connection->objectCall('msgs_state_req', ['msg_ids' => $message_ids], ['promise' => $deferred]); yield from $connection->objectCall('msgs_state_req', ['msg_ids' => $message_ids], ['promise' => $deferred]);
@ -148,7 +148,7 @@ class CheckLoop extends ResumableSignalLoop
} else { } else {
foreach ($connection->new_outgoing as $message_id) { foreach ($connection->new_outgoing as $message_id) {
if (isset($connection->outgoing_messages[$message_id]['sent']) && $connection->outgoing_messages[$message_id]['sent'] + $timeout < \time() && $connection->outgoing_messages[$message_id]['unencrypted']) { if (isset($connection->outgoing_messages[$message_id]['sent']) && $connection->outgoing_messages[$message_id]['sent'] + $timeout < \time() && $connection->outgoing_messages[$message_id]['unencrypted']) {
$API->logger->logger('Still missing ' . $connection->outgoing_messages[$message_id]['_'] . ' with message id ' . $message_id . " on DC {$datacenter}, resending", \danog\MadelineProto\Logger::ERROR); $API->logger->logger('Still missing '.$connection->outgoing_messages[$message_id]['_'].' with message id '.$message_id." on DC {$datacenter}, resending", \danog\MadelineProto\Logger::ERROR);
$connection->methodRecall('', ['message_id' => $message_id, 'postpone' => true]); $connection->methodRecall('', ['message_id' => $message_id, 'postpone' => true]);
} }
} }

View File

@ -26,6 +26,7 @@ use Amp\Websocket\ClosedException;
use danog\MadelineProto\Connection; use danog\MadelineProto\Connection;
use danog\MadelineProto\Logger; use danog\MadelineProto\Logger;
use danog\MadelineProto\Loop\Impl\SignalLoop; use danog\MadelineProto\Loop\Impl\SignalLoop;
use danog\MadelineProto\MTProtoTools\Crypt;
use danog\MadelineProto\NothingInTheSocketException; use danog\MadelineProto\NothingInTheSocketException;
use danog\MadelineProto\Tools; use danog\MadelineProto\Tools;
@ -168,13 +169,13 @@ class ReadLoop extends SignalLoop
$connection->incoming_messages[$message_id] = []; $connection->incoming_messages[$message_id] = [];
} elseif ($auth_key_id === $shared->getTempAuthKey()->getID()) { } elseif ($auth_key_id === $shared->getTempAuthKey()->getID()) {
$message_key = yield $buffer->bufferRead(16); $message_key = yield $buffer->bufferRead(16);
list($aes_key, $aes_iv) = $this->aesCalculate($message_key, $shared->getTempAuthKey()->getAuthKey(), false); list($aes_key, $aes_iv) = Crypt::aesCalculate($message_key, $shared->getTempAuthKey()->getAuthKey(), false);
$encrypted_data = yield $buffer->bufferRead($payload_length - 24); $encrypted_data = yield $buffer->bufferRead($payload_length - 24);
$protocol_padding = \strlen($encrypted_data) % 16; $protocol_padding = \strlen($encrypted_data) % 16;
if ($protocol_padding) { if ($protocol_padding) {
$encrypted_data = \substr($encrypted_data, 0, -$protocol_padding); $encrypted_data = \substr($encrypted_data, 0, -$protocol_padding);
} }
$decrypted_data = $this->igeDecrypt($encrypted_data, $aes_key, $aes_iv); $decrypted_data = Crypt::igeDecrypt($encrypted_data, $aes_key, $aes_iv);
/* /*
$server_salt = substr($decrypted_data, 0, 8); $server_salt = substr($decrypted_data, 0, 8);
if ($server_salt != $shared->getTempAuthKey()->getServerSalt()) { if ($server_salt != $shared->getTempAuthKey()->getServerSalt()) {

View File

@ -23,6 +23,7 @@ use Amp\ByteStream\StreamException;
use danog\MadelineProto\Connection; use danog\MadelineProto\Connection;
use danog\MadelineProto\Logger; use danog\MadelineProto\Logger;
use danog\MadelineProto\Loop\Impl\ResumableSignalLoop; use danog\MadelineProto\Loop\Impl\ResumableSignalLoop;
use danog\MadelineProto\MTProtoTools\Crypt;
use danog\MadelineProto\Tools; use danog\MadelineProto\Tools;
/** /**
@ -284,8 +285,8 @@ class WriteLoop extends ResumableSignalLoop
} }
$padding = \danog\MadelineProto\Tools::random($padding); $padding = \danog\MadelineProto\Tools::random($padding);
$message_key = \substr(\hash('sha256', \substr($shared->getTempAuthKey()->getAuthKey(), 88, 32).$plaintext.$padding, true), 8, 16); $message_key = \substr(\hash('sha256', \substr($shared->getTempAuthKey()->getAuthKey(), 88, 32).$plaintext.$padding, true), 8, 16);
list($aes_key, $aes_iv) = $this->aesCalculate($message_key, $shared->getTempAuthKey()->getAuthKey()); list($aes_key, $aes_iv) = Crypt::aesCalculate($message_key, $shared->getTempAuthKey()->getAuthKey());
$message = $shared->getTempAuthKey()->getID().$message_key.$this->igeEncrypt($plaintext.$padding, $aes_key, $aes_iv); $message = $shared->getTempAuthKey()->getID().$message_key.Crypt::igeEncrypt($plaintext.$padding, $aes_key, $aes_iv);
$buffer = yield $connection->stream->getWriteBuffer($len = \strlen($message)); $buffer = yield $connection->stream->getWriteBuffer($len = \strlen($message));
//$t = \microtime(true); //$t = \microtime(true);
yield $buffer->bufferWrite($message); yield $buffer->bufferWrite($message);

View File

@ -32,6 +32,13 @@ use danog\MadelineProto\Loop\SignalLoopInterface;
abstract class SignalLoop extends Loop implements SignalLoopInterface abstract class SignalLoop extends Loop implements SignalLoopInterface
{ {
private $signalDeferred; private $signalDeferred;
/**
* Send signal to loop.
*
* @param mixed $what Data to signal
*
* @return void
*/
public function signal($what): void public function signal($what): void
{ {
if ($this->signalDeferred) { if ($this->signalDeferred) {

View File

@ -131,7 +131,7 @@ class FeedLoop extends ResumableSignalLoop
$this->save($update); $this->save($update);
} }
} }
public function feed($updates): \Generator public function feed(array $updates): \Generator
{ {
$result = []; $result = [];
foreach ($updates as $update) { foreach ($updates as $update) {
@ -143,7 +143,7 @@ class FeedLoop extends ResumableSignalLoop
} }
return $result; return $result;
} }
public function feedSingle($update): \Generator public function feedSingle(array $update): \Generator
{ {
$channelId = false; $channelId = false;
switch ($update['_']) { switch ($update['_']) {
@ -191,13 +191,13 @@ class FeedLoop extends ResumableSignalLoop
$log .= "from_id {$update['message']['from_id']}, "; $log .= "from_id {$update['message']['from_id']}, ";
} }
if ($to) { if ($to) {
$log .= 'to_id ' . \json_encode($update['message']['to_id']) . ', '; $log .= 'to_id '.\json_encode($update['message']['to_id']).', ';
} }
if ($via_bot) { if ($via_bot) {
$log .= "via_bot {$update['message']['via_bot_id']}, "; $log .= "via_bot {$update['message']['via_bot_id']}, ";
} }
if ($entities) { if ($entities) {
$log .= 'entities ' . \json_encode($update['message']['entities']) . ', '; $log .= 'entities '.\json_encode($update['message']['entities']).', ';
} }
$this->API->logger->logger("Not enough data: for message update {$log}, getting difference...", \danog\MadelineProto\Logger::VERBOSE); $this->API->logger->logger("Not enough data: for message update {$log}, getting difference...", \danog\MadelineProto\Logger::VERBOSE);
$update = ['_' => 'updateChannelTooLong']; $update = ['_' => 'updateChannelTooLong'];
@ -208,7 +208,7 @@ class FeedLoop extends ResumableSignalLoop
break; break;
default: default:
if ($channelId && !(yield from $this->API->peerIsset($this->API->toSupergroup($channelId)))) { if ($channelId && !(yield from $this->API->peerIsset($this->API->toSupergroup($channelId)))) {
$this->API->logger->logger('Skipping update, I do not have the channel id ' . $channelId, \danog\MadelineProto\Logger::ERROR); $this->API->logger->logger('Skipping update, I do not have the channel id '.$channelId, \danog\MadelineProto\Logger::ERROR);
return false; return false;
} }
break; break;
@ -220,7 +220,7 @@ class FeedLoop extends ResumableSignalLoop
return yield from $this->API->feeders[false]->feedSingle($update); return yield from $this->API->feeders[false]->feedSingle($update);
} }
} }
$this->API->logger->logger('Was fed an update of type ' . $update['_'] . " in {$this}...", \danog\MadelineProto\Logger::VERBOSE); $this->API->logger->logger('Was fed an update of type '.$update['_']." in {$this}...", \danog\MadelineProto\Logger::VERBOSE);
$this->incomingUpdates[] = $update; $this->incomingUpdates[] = $update;
return $this->channelId; return $this->channelId;
} }
@ -236,7 +236,7 @@ class FeedLoop extends ResumableSignalLoop
continue; continue;
} }
if ($message['_'] !== 'messageEmpty') { if ($message['_'] !== 'messageEmpty') {
$this->API->logger->logger('Getdiff fed me message of type ' . $message['_'] . " in {$this}...", \danog\MadelineProto\Logger::VERBOSE); $this->API->logger->logger('Getdiff fed me message of type '.$message['_']." in {$this}...", \danog\MadelineProto\Logger::VERBOSE);
} }
$this->parsedUpdates[] = ['_' => $this->channelId === false ? 'updateNewMessage' : 'updateNewChannelMessage', 'message' => $message, 'pts' => -1, 'pts_count' => -1]; $this->parsedUpdates[] = ['_' => $this->channelId === false ? 'updateNewMessage' : 'updateNewChannelMessage', 'message' => $message, 'pts' => -1, 'pts_count' => -1];
} }

View File

@ -89,7 +89,7 @@ class SeqLoop extends ResumableSignalLoop
$seq_end = $options['seq_end']; $seq_end = $options['seq_end'];
$result = $this->state->checkSeq($seq_start); $result = $this->state->checkSeq($seq_start);
if ($result > 0) { if ($result > 0) {
$this->API->logger->logger('Seq hole. seq_start: ' . $seq_start . ' != cur seq: ' . ($this->state->seq() + 1), \danog\MadelineProto\Logger::ERROR); $this->API->logger->logger('Seq hole. seq_start: '.$seq_start.' != cur seq: '.($this->state->seq() + 1), \danog\MadelineProto\Logger::ERROR);
yield $this->pause(1.0); yield $this->pause(1.0);
if (!$this->incomingUpdates) { if (!$this->incomingUpdates) {
yield $this->API->updaters[false]->resume(); yield $this->API->updaters[false]->resume();
@ -98,7 +98,7 @@ class SeqLoop extends ResumableSignalLoop
continue; continue;
} }
if ($result < 0) { if ($result < 0) {
$this->API->logger->logger('Seq too old. seq_start: ' . $seq_start . ' != cur seq: ' . ($this->state->seq() + 1), \danog\MadelineProto\Logger::ERROR); $this->API->logger->logger('Seq too old. seq_start: '.$seq_start.' != cur seq: '.($this->state->seq() + 1), \danog\MadelineProto\Logger::ERROR);
continue; continue;
} }
$this->state->seq($seq_end); $this->state->seq($seq_end);
@ -110,7 +110,7 @@ class SeqLoop extends ResumableSignalLoop
} }
public function feed($updates) public function feed($updates)
{ {
$this->API->logger->logger('Was fed updates of type ' . $updates['_'] . '...', \danog\MadelineProto\Logger::VERBOSE); $this->API->logger->logger('Was fed updates of type '.$updates['_'].'...', \danog\MadelineProto\Logger::VERBOSE);
$this->incomingUpdates[] = $updates; $this->incomingUpdates[] = $updates;
} }
public function save($updates): \Generator public function save($updates): \Generator

View File

@ -64,7 +64,7 @@ class UpdateLoop extends ResumableSignalLoop
$this->toPts = null; $this->toPts = null;
while (true) { while (true) {
if ($this->channelId) { if ($this->channelId) {
$API->logger->logger('Resumed and fetching ' . $this->channelId . ' difference...', \danog\MadelineProto\Logger::ULTRA_VERBOSE); $API->logger->logger('Resumed and fetching '.$this->channelId.' difference...', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
if ($state->pts() <= 1) { if ($state->pts() <= 1) {
$limit = 10; $limit = 10;
} elseif ($API->authorization['user']['bot']) { } elseif ($API->authorization['user']['bot']) {
@ -74,7 +74,7 @@ class UpdateLoop extends ResumableSignalLoop
} }
$request_pts = $state->pts(); $request_pts = $state->pts();
try { try {
$difference = yield from $API->methodCallAsyncRead('updates.getChannelDifference', ['channel' => 'channel#' . $this->channelId, 'filter' => ['_' => 'channelMessagesFilterEmpty'], 'pts' => $request_pts, 'limit' => $limit, 'force' => true], ['datacenter' => $API->datacenter->curdc, 'postpone' => $first]); $difference = yield from $API->methodCallAsyncRead('updates.getChannelDifference', ['channel' => 'channel#'.$this->channelId, 'filter' => ['_' => 'channelMessagesFilterEmpty'], 'pts' => $request_pts, 'limit' => $limit, 'force' => true], ['datacenter' => $API->datacenter->curdc, 'postpone' => $first]);
} catch (RPCErrorException $e) { } catch (RPCErrorException $e) {
if (\in_array($e->rpc, ['CHANNEL_PRIVATE', 'CHAT_FORBIDDEN', 'CHANNEL_INVALID'])) { if (\in_array($e->rpc, ['CHANNEL_PRIVATE', 'CHAT_FORBIDDEN', 'CHANNEL_INVALID'])) {
$feeder->signal(true); $feeder->signal(true);
@ -97,7 +97,7 @@ class UpdateLoop extends ResumableSignalLoop
if (isset($difference['timeout'])) { if (isset($difference['timeout'])) {
$timeout = $difference['timeout']; $timeout = $difference['timeout'];
} }
$API->logger->logger('Got ' . $difference['_'], \danog\MadelineProto\Logger::VERBOSE); $API->logger->logger('Got '.$difference['_'], \danog\MadelineProto\Logger::VERBOSE);
switch ($difference['_']) { switch ($difference['_']) {
case 'updates.channelDifferenceEmpty': case 'updates.channelDifferenceEmpty':
$state->update($difference); $state->update($difference);
@ -105,7 +105,7 @@ class UpdateLoop extends ResumableSignalLoop
break 2; break 2;
case 'updates.channelDifference': case 'updates.channelDifference':
if ($request_pts >= $difference['pts'] && $request_pts > 1) { if ($request_pts >= $difference['pts'] && $request_pts > 1) {
$API->logger->logger("The PTS ({$difference['pts']}) I got with getDifference is smaller than the PTS I requested " . $state->pts() . ', using ' . ($state->pts() + 1), \danog\MadelineProto\Logger::VERBOSE); $API->logger->logger("The PTS ({$difference['pts']}) I got with getDifference is smaller than the PTS I requested ".$state->pts().', using '.($state->pts() + 1), \danog\MadelineProto\Logger::VERBOSE);
$difference['pts'] = $request_pts + 1; $difference['pts'] = $request_pts + 1;
} }
$result += (yield from $feeder->feed($difference['other_updates'])); $result += (yield from $feeder->feed($difference['other_updates']));
@ -130,12 +130,12 @@ class UpdateLoop extends ResumableSignalLoop
unset($difference); unset($difference);
break; break;
default: default:
throw new \danog\MadelineProto\Exception('Unrecognized update difference received: ' . \var_export($difference, true)); throw new \danog\MadelineProto\Exception('Unrecognized update difference received: '.\var_export($difference, true));
} }
} else { } else {
$API->logger->logger('Resumed and fetching normal difference...', \danog\MadelineProto\Logger::ULTRA_VERBOSE); $API->logger->logger('Resumed and fetching normal difference...', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
$difference = yield from $API->methodCallAsyncRead('updates.getDifference', ['pts' => $state->pts(), 'date' => $state->date(), 'qts' => $state->qts()], ['datacenter' => $API->settings['connection_settings']['default_dc']]); $difference = yield from $API->methodCallAsyncRead('updates.getDifference', ['pts' => $state->pts(), 'date' => $state->date(), 'qts' => $state->qts()], ['datacenter' => $API->settings['connection_settings']['default_dc']]);
$API->logger->logger('Got ' . $difference['_'], \danog\MadelineProto\Logger::ULTRA_VERBOSE); $API->logger->logger('Got '.$difference['_'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
switch ($difference['_']) { switch ($difference['_']) {
case 'updates.differenceEmpty': case 'updates.differenceEmpty':
$state->update($difference); $state->update($difference);
@ -172,7 +172,7 @@ class UpdateLoop extends ResumableSignalLoop
unset($difference); unset($difference);
break; break;
default: default:
throw new \danog\MadelineProto\Exception('Unrecognized update difference received: ' . \var_export($difference, true)); throw new \danog\MadelineProto\Exception('Unrecognized update difference received: '.\var_export($difference, true));
} }
} }
} }

View File

@ -872,7 +872,7 @@ class MTProto extends AsyncConstruct implements TLCallback
yield from $this->updateSettings($backtrace['args'][1], false); yield from $this->updateSettings($backtrace['args'][1], false);
} }
} }
if (($this->settings['tl_schema']['src']['botAPI'] ?? '') !== __DIR__.'/TL_botAPI.tl') { if (($this->settings['tl_schema']['src']['botAPI'] ?? '') !== __DIR__.'/../../../schemas/TL_botAPI.tl') {
unset($this->v); unset($this->v);
} }
if (!\file_exists($this->settings['tl_schema']['src']['telegram'])) { if (!\file_exists($this->settings['tl_schema']['src']['telegram'])) {
@ -1183,16 +1183,15 @@ class MTProto extends AsyncConstruct implements TLCallback
'layer' => 111, 'layer' => 111,
// layer version // layer version
'src' => [ 'src' => [
'mtproto' => __DIR__.'/TL_mtproto_v1.tl', 'mtproto' => __DIR__.'/../../../schemas/TL_mtproto_v1.tl',
// mtproto TL scheme // mtproto TL scheme
'telegram' => __DIR__.'/TL_telegram_v111.tl', 'telegram' => __DIR__.'/../../../schemas/TL_telegram_v111.tl',
// telegram TL scheme // telegram TL scheme
'secret' => __DIR__.'/TL_secret.tl', 'secret' => __DIR__.'/../../../schemas/TL_secret.tl',
// secret chats TL scheme // secret chats TL scheme
'calls' => __DIR__.'/TL_calls.tl', 'calls' => __DIR__.'/../../../schemas/TL_calls.tl',
// calls TL scheme // calls TL scheme
//'td' => __DIR__.'/TL_td.tl', // telegram-cli TL scheme 'botAPI' => __DIR__.'/../../../schemas/TL_botAPI.tl',
'botAPI' => __DIR__.'/TL_botAPI.tl',
], ],
], 'logger' => [ ], 'logger' => [
// Logger settings // Logger settings

View File

@ -69,7 +69,7 @@ class PermAuthKey extends AuthKey
*/ */
public function jsonSerialize(): array public function jsonSerialize(): array
{ {
return ['auth_key' => 'pony' . \base64_encode($this->authKey), 'server_salt' => $this->serverSalt, 'authorized' => $this->authorized]; return ['auth_key' => 'pony'.\base64_encode($this->authKey), 'server_salt' => $this->serverSalt, 'authorized' => $this->authorized];
} }
/** /**
* Sleep function. * Sleep function.

View File

@ -152,7 +152,7 @@ class TempAuthKey extends AuthKey implements JsonSerializable
*/ */
public function jsonSerialize(): array public function jsonSerialize(): array
{ {
return ['auth_key' => 'pony' . \base64_encode($this->authKey), 'server_salt' => $this->serverSalt, 'bound' => $this->isBound(), 'expires' => $this->expires, 'connection_inited' => $this->inited]; return ['auth_key' => 'pony'.\base64_encode($this->authKey), 'server_salt' => $this->serverSalt, 'bound' => $this->isBound(), 'expires' => $this->expires, 'connection_inited' => $this->inited];
} }
/** /**
* Sleep function. * Sleep function.

View File

@ -28,7 +28,7 @@ trait AckHandler
{ {
// The server acknowledges that it received my message // The server acknowledges that it received my message
if (!isset($this->outgoing_messages[$message_id])) { if (!isset($this->outgoing_messages[$message_id])) {
$this->logger->logger("WARNING: Couldn't find message id " . $message_id . ' in the array of outgoing messages. Maybe try to increase its size?', \danog\MadelineProto\Logger::WARNING); $this->logger->logger("WARNING: Couldn't find message id ".$message_id.' in the array of outgoing messages. Maybe try to increase its size?', \danog\MadelineProto\Logger::WARNING);
return false; return false;
} }
//$this->logger->logger("Ack-ed ".$this->outgoing_messages[$message_id]['_']." with message ID $message_id on DC $datacenter"); //$this->logger->logger("Ack-ed ".$this->outgoing_messages[$message_id]['_']." with message ID $message_id on DC $datacenter");
@ -48,7 +48,7 @@ trait AckHandler
unset($this->new_outgoing[$message_id]); unset($this->new_outgoing[$message_id]);
} }
if (!isset($this->outgoing_messages[$message_id])) { if (!isset($this->outgoing_messages[$message_id])) {
$this->logger->logger("WARNING: Couldn't find message id " . $message_id . ' in the array of outgoing messages. Maybe try to increase its size?', \danog\MadelineProto\Logger::WARNING); $this->logger->logger("WARNING: Couldn't find message id ".$message_id.' in the array of outgoing messages. Maybe try to increase its size?', \danog\MadelineProto\Logger::WARNING);
return false; return false;
} }
if (isset($this->outgoing_messages[$message_id]['body'])) { if (isset($this->outgoing_messages[$message_id]['body'])) {
@ -63,7 +63,7 @@ trait AckHandler
{ {
// I let the server know that I received its message // I let the server know that I received its message
if (!isset($this->incoming_messages[$message_id])) { if (!isset($this->incoming_messages[$message_id])) {
$this->logger->logger("WARNING: Couldn't find message id " . $message_id . ' in the array of incoming messages. Maybe try to increase its size?', \danog\MadelineProto\Logger::WARNING); $this->logger->logger("WARNING: Couldn't find message id ".$message_id.' in the array of incoming messages. Maybe try to increase its size?', \danog\MadelineProto\Logger::WARNING);
} }
/*if ($this->temp_auth_key['id'] === null || $this->temp_auth_key['id'] === "\0\0\0\0\0\0\0\0") { /*if ($this->temp_auth_key['id'] === null || $this->temp_auth_key['id'] === "\0\0\0\0\0\0\0\0") {
// || (isset($this->incoming_messages[$message_id]['ack']) && $this->incoming_messages[$message_id]['ack'])) { // || (isset($this->incoming_messages[$message_id]['ack']) && $this->incoming_messages[$message_id]['ack'])) {

View File

@ -30,7 +30,7 @@ trait ResponseHandler
{ {
public function sendMsgsStateInfo($req_msg_id, $msg_ids): \Generator public function sendMsgsStateInfo($req_msg_id, $msg_ids): \Generator
{ {
$this->logger->logger('Sending state info for ' . \count($msg_ids) . ' message IDs'); $this->logger->logger('Sending state info for '.\count($msg_ids).' message IDs');
$info = ''; $info = '';
foreach ($msg_ids as $msg_id) { foreach ($msg_ids as $msg_id) {
$cur_info = 0; $cur_info = 0;
@ -65,7 +65,7 @@ trait ResponseHandler
unset($this->new_incoming[$current_msg_id]); unset($this->new_incoming[$current_msg_id]);
continue; continue;
} }
$this->logger->logger((isset($this->incoming_messages[$current_msg_id]['from_container']) ? 'Inside of container, received ' : 'Received ') . $this->incoming_messages[$current_msg_id]['content']['_'] . ' from DC ' . $this->datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE); $this->logger->logger((isset($this->incoming_messages[$current_msg_id]['from_container']) ? 'Inside of container, received ' : 'Received ').$this->incoming_messages[$current_msg_id]['content']['_'].' from DC '.$this->datacenter, \danog\MadelineProto\Logger::ULTRA_VERBOSE);
switch ($this->incoming_messages[$current_msg_id]['content']['_']) { switch ($this->incoming_messages[$current_msg_id]['content']['_']) {
case 'msgs_ack': case 'msgs_ack':
unset($this->new_incoming[$current_msg_id]); unset($this->new_incoming[$current_msg_id]);
@ -166,7 +166,7 @@ trait ResponseHandler
foreach ($this->incoming_messages[$current_msg_id]['content']['msg_ids'] as $key => $msg_id) { foreach ($this->incoming_messages[$current_msg_id]['content']['msg_ids'] as $key => $msg_id) {
$info = \ord($this->incoming_messages[$current_msg_id]['content']['info'][$key]); $info = \ord($this->incoming_messages[$current_msg_id]['content']['info'][$key]);
$msg_id = new \tgseclib\Math\BigInteger(\strrev($msg_id), 256); $msg_id = new \tgseclib\Math\BigInteger(\strrev($msg_id), 256);
$status = 'Status for message id ' . $msg_id . ': '; $status = 'Status for message id '.$msg_id.': ';
/*if ($info & 4) { /*if ($info & 4) {
*$this->gotResponseForOutgoingMessageId($msg_id); *$this->gotResponseForOutgoingMessageId($msg_id);
*} *}
@ -246,13 +246,13 @@ trait ResponseHandler
break; break;
default: default:
$only_updates = false; $only_updates = false;
$this->logger->logger('Trying to assign a response of type ' . $response_type . ' to its request...', \danog\MadelineProto\Logger::VERBOSE); $this->logger->logger('Trying to assign a response of type '.$response_type.' to its request...', \danog\MadelineProto\Logger::VERBOSE);
foreach ($this->new_outgoing as $key => $expecting_msg_id) { foreach ($this->new_outgoing as $key => $expecting_msg_id) {
$expecting = $this->outgoing_messages[$expecting_msg_id]; $expecting = $this->outgoing_messages[$expecting_msg_id];
if (!isset($expecting['type'])) { if (!isset($expecting['type'])) {
continue; continue;
} }
$this->logger->logger('Does the request of return type ' . $expecting['type'] . ' match?', \danog\MadelineProto\Logger::VERBOSE); $this->logger->logger('Does the request of return type '.$expecting['type'].' match?', \danog\MadelineProto\Logger::VERBOSE);
if ($response_type === $expecting['type']) { if ($response_type === $expecting['type']) {
$this->logger->logger('Yes', \danog\MadelineProto\Logger::VERBOSE); $this->logger->logger('Yes', \danog\MadelineProto\Logger::VERBOSE);
unset($this->new_incoming[$current_msg_id]); unset($this->new_incoming[$current_msg_id]);
@ -261,7 +261,7 @@ trait ResponseHandler
} }
$this->logger->logger('No', \danog\MadelineProto\Logger::VERBOSE); $this->logger->logger('No', \danog\MadelineProto\Logger::VERBOSE);
} }
$this->logger->logger('Dunno how to handle ' . PHP_EOL . \var_export($this->incoming_messages[$current_msg_id]['content'], true), \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger('Dunno how to handle '.PHP_EOL.\var_export($this->incoming_messages[$current_msg_id]['content'], true), \danog\MadelineProto\Logger::FATAL_ERROR);
unset($this->new_incoming[$current_msg_id]); unset($this->new_incoming[$current_msg_id]);
break; break;
} }
@ -287,7 +287,7 @@ trait ResponseHandler
if (isset($request['promise']) && \is_object($request['promise'])) { if (isset($request['promise']) && \is_object($request['promise'])) {
Loop::defer(function () use (&$request, $data) { Loop::defer(function () use (&$request, $data) {
if (isset($request['promise'])) { if (isset($request['promise'])) {
$this->logger->logger('Rejecting: ' . (isset($request['_']) ? $request['_'] : '-')); $this->logger->logger('Rejecting: '.(isset($request['_']) ? $request['_'] : '-'));
$this->logger->logger("Rejecting: {$data}"); $this->logger->logger("Rejecting: {$data}");
$promise = $request['promise']; $promise = $request['promise'];
unset($request['promise']); unset($request['promise']);
@ -300,7 +300,7 @@ trait ResponseHandler
$this->logger->logger("Got promise already resolved error", \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger("Got promise already resolved error", \danog\MadelineProto\Logger::FATAL_ERROR);
} }
} else { } else {
$this->logger->logger('Rejecting: already got response for ' . (isset($request['_']) ? $request['_'] : '-')); $this->logger->logger('Rejecting: already got response for '.(isset($request['_']) ? $request['_'] : '-'));
$this->logger->logger("Rejecting: {$data}"); $this->logger->logger("Rejecting: {$data}");
} }
}); });
@ -309,7 +309,7 @@ trait ResponseHandler
$this->handleReject($this->outgoing_messages[$message_id], $data); $this->handleReject($this->outgoing_messages[$message_id], $data);
} }
} else { } else {
$this->logger->logger('Rejecting: already got response for ' . (isset($request['_']) ? $request['_'] : '-')); $this->logger->logger('Rejecting: already got response for '.(isset($request['_']) ? $request['_'] : '-'));
$this->logger->logger("Rejecting: {$data}"); $this->logger->logger("Rejecting: {$data}");
} }
} }
@ -358,7 +358,7 @@ trait ResponseHandler
return; return;
case 303: case 303:
$this->API->datacenter->curdc = $datacenter = (int) \preg_replace('/[^0-9]+/', '', $response['error_message']); $this->API->datacenter->curdc = $datacenter = (int) \preg_replace('/[^0-9]+/', '', $response['error_message']);
if (isset($request['file']) && $request['file'] && $this->API->datacenter->has($datacenter . '_media')) { if (isset($request['file']) && $request['file'] && $this->API->datacenter->has($datacenter.'_media')) {
$datacenter .= '_media'; $datacenter .= '_media';
} }
if (isset($request['user_related']) && $request['user_related']) { if (isset($request['user_related']) && $request['user_related']) {
@ -383,8 +383,8 @@ trait ResponseHandler
$this->logger->logger('!!!!!!! WARNING !!!!!!!', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger('!!!!!!! WARNING !!!!!!!', \danog\MadelineProto\Logger::FATAL_ERROR);
$this->logger->logger("Telegram's flood prevention system suspended this account.", \danog\MadelineProto\Logger::ERROR); $this->logger->logger("Telegram's flood prevention system suspended this account.", \danog\MadelineProto\Logger::ERROR);
$this->logger->logger('To continue, manual verification is required.', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger('To continue, manual verification is required.', \danog\MadelineProto\Logger::FATAL_ERROR);
$phone = isset($this->authorization['user']['phone']) ? '+' . $this->authorization['user']['phone'] : 'you are currently using'; $phone = isset($this->authorization['user']['phone']) ? '+'.$this->authorization['user']['phone'] : 'you are currently using';
$this->logger->logger('Send an email to recover@telegram.org, asking to unban the phone number ' . $phone . ', and shortly describe what will you do with this phone number.', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger('Send an email to recover@telegram.org, asking to unban the phone number '.$phone.', and shortly describe what will you do with this phone number.', \danog\MadelineProto\Logger::FATAL_ERROR);
$this->logger->logger('Then login again.', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger('Then login again.', \danog\MadelineProto\Logger::FATAL_ERROR);
$this->logger->logger('If you intentionally deleted this account, ignore this message.', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger('If you intentionally deleted this account, ignore this message.', \danog\MadelineProto\Logger::FATAL_ERROR);
} }
@ -418,8 +418,8 @@ trait ResponseHandler
$this->logger->logger('!!!!!!! WARNING !!!!!!!', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger('!!!!!!! WARNING !!!!!!!', \danog\MadelineProto\Logger::FATAL_ERROR);
$this->logger->logger("Telegram's flood prevention system suspended this account.", \danog\MadelineProto\Logger::ERROR); $this->logger->logger("Telegram's flood prevention system suspended this account.", \danog\MadelineProto\Logger::ERROR);
$this->logger->logger('To continue, manual verification is required.', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger('To continue, manual verification is required.', \danog\MadelineProto\Logger::FATAL_ERROR);
$phone = isset($this->authorization['user']['phone']) ? '+' . $this->authorization['user']['phone'] : 'you are currently using'; $phone = isset($this->authorization['user']['phone']) ? '+'.$this->authorization['user']['phone'] : 'you are currently using';
$this->logger->logger('Send an email to recover@telegram.org, asking to unban the phone number ' . $phone . ', and quickly describe what will you do with this phone number.', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger('Send an email to recover@telegram.org, asking to unban the phone number '.$phone.', and quickly describe what will you do with this phone number.', \danog\MadelineProto\Logger::FATAL_ERROR);
$this->logger->logger('Then login again.', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger('Then login again.', \danog\MadelineProto\Logger::FATAL_ERROR);
$this->logger->logger('If you intentionally deleted this account, ignore this message.', \danog\MadelineProto\Logger::FATAL_ERROR); $this->logger->logger('If you intentionally deleted this account, ignore this message.', \danog\MadelineProto\Logger::FATAL_ERROR);
$this->API->resetSession(); $this->API->resetSession();
@ -451,7 +451,7 @@ trait ResponseHandler
$limit = $request['FloodWaitLimit'] ?? $this->API->settings['flood_timeout']['wait_if_lt']; $limit = $request['FloodWaitLimit'] ?? $this->API->settings['flood_timeout']['wait_if_lt'];
if (\is_numeric($seconds) && $seconds < $limit) { if (\is_numeric($seconds) && $seconds < $limit) {
//$this->gotResponseForOutgoingMessageId($request_id); //$this->gotResponseForOutgoingMessageId($request_id);
$this->logger->logger('Flood, waiting ' . $seconds . ' seconds before repeating async call of ' . ($request['_'] ?? '') . '...', \danog\MadelineProto\Logger::NOTICE); $this->logger->logger('Flood, waiting '.$seconds.' seconds before repeating async call of '.($request['_'] ?? '').'...', \danog\MadelineProto\Logger::NOTICE);
$request['sent'] = ($request['sent'] ?? \time()) + $seconds; $request['sent'] = ($request['sent'] ?? \time()) + $seconds;
Loop::delay($seconds * 1000, [$this, 'methodRecall'], ['message_id' => $request_id]); Loop::delay($seconds * 1000, [$this, 'methodRecall'], ['message_id' => $request_id]);
return; return;
@ -469,7 +469,7 @@ trait ResponseHandler
break; break;
case 'bad_server_salt': case 'bad_server_salt':
case 'bad_msg_notification': case 'bad_msg_notification':
$this->logger->logger('Received bad_msg_notification: ' . MTProto::BAD_MSG_ERROR_CODES[$response['error_code']], \danog\MadelineProto\Logger::WARNING); $this->logger->logger('Received bad_msg_notification: '.MTProto::BAD_MSG_ERROR_CODES[$response['error_code']], \danog\MadelineProto\Logger::WARNING);
switch ($response['error_code']) { switch ($response['error_code']) {
case 48: case 48:
$this->shared->getTempAuthKey()->setServerSalt($response['new_server_salt']); $this->shared->getTempAuthKey()->setServerSalt($response['new_server_salt']);
@ -478,7 +478,7 @@ trait ResponseHandler
case 16: case 16:
case 17: case 17:
$this->time_delta = (int) (new \tgseclib\Math\BigInteger(\strrev($response_id), 256))->bitwise_rightShift(32)->subtract(new \tgseclib\Math\BigInteger(\time()))->toString(); $this->time_delta = (int) (new \tgseclib\Math\BigInteger(\strrev($response_id), 256))->bitwise_rightShift(32)->subtract(new \tgseclib\Math\BigInteger(\time()))->toString();
$this->logger->logger('Set time delta to ' . $this->time_delta, \danog\MadelineProto\Logger::WARNING); $this->logger->logger('Set time delta to '.$this->time_delta, \danog\MadelineProto\Logger::WARNING);
$this->API->resetMTProtoSession(); $this->API->resetMTProtoSession();
$this->shared->setTempAuthKey(null); $this->shared->setTempAuthKey(null);
\danog\MadelineProto\Tools::callFork((function () use ($request_id): \Generator { \danog\MadelineProto\Tools::callFork((function () use ($request_id): \Generator {
@ -488,7 +488,7 @@ trait ResponseHandler
return; return;
} }
$this->gotResponseForOutgoingMessageId($request_id); $this->gotResponseForOutgoingMessageId($request_id);
$this->handleReject($request, new \danog\MadelineProto\RPCErrorException('Received bad_msg_notification: ' . MTProto::BAD_MSG_ERROR_CODES[$response['error_code']], $response['error_code'], $request['_'] ?? '')); $this->handleReject($request, new \danog\MadelineProto\RPCErrorException('Received bad_msg_notification: '.MTProto::BAD_MSG_ERROR_CODES[$response['error_code']], $response['error_code'], $request['_'] ?? ''));
return; return;
} }
} }
@ -497,7 +497,7 @@ trait ResponseHandler
} }
if (!isset($request['promise'])) { if (!isset($request['promise'])) {
$this->gotResponseForOutgoingMessageId($request_id); $this->gotResponseForOutgoingMessageId($request_id);
$this->logger->logger('Response: already got response for ' . (isset($request['_']) ? $request['_'] : '-') . ' with message ID ' . $request_id); $this->logger->logger('Response: already got response for '.(isset($request['_']) ? $request['_'] : '-').' with message ID '.$request_id);
return; return;
} }
$botAPI = isset($request['botAPI']) && $request['botAPI']; $botAPI = isset($request['botAPI']) && $request['botAPI'];

View File

@ -41,7 +41,7 @@ trait SeqNoHandler
{ {
$type = isset($this->incoming_messages[$current_msg_id]['content']['_']) ? $this->incoming_messages[$current_msg_id]['content']['_'] : '-'; $type = isset($this->incoming_messages[$current_msg_id]['content']['_']) ? $this->incoming_messages[$current_msg_id]['content']['_'] : '-';
if (isset($this->incoming_messages[$current_msg_id]['seq_no']) && ($seq_no = $this->generateInSeqNo($this->contentRelated($this->incoming_messages[$current_msg_id]['content']))) !== $this->incoming_messages[$current_msg_id]['seq_no']) { if (isset($this->incoming_messages[$current_msg_id]['seq_no']) && ($seq_no = $this->generateInSeqNo($this->contentRelated($this->incoming_messages[$current_msg_id]['content']))) !== $this->incoming_messages[$current_msg_id]['seq_no']) {
$this->API->logger->logger('SECURITY WARNING: Seqno mismatch (should be ' . $seq_no . ', is ' . $this->incoming_messages[$current_msg_id]['seq_no'] . ', ' . $type . ')', \danog\MadelineProto\Logger::ULTRA_VERBOSE); $this->API->logger->logger('SECURITY WARNING: Seqno mismatch (should be '.$seq_no.', is '.$this->incoming_messages[$current_msg_id]['seq_no'].', '.$type.')', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
} }
} }
public function generateInSeqNo($contentRelated) public function generateInSeqNo($contentRelated)

View File

@ -213,7 +213,7 @@ trait AuthKeyHandler
$encrypted_answer = $server_dh_params['encrypted_answer']; $encrypted_answer = $server_dh_params['encrypted_answer'];
$tmp_aes_key = \sha1($new_nonce.$server_nonce, true).\substr(\sha1($server_nonce.$new_nonce, true), 0, 12); $tmp_aes_key = \sha1($new_nonce.$server_nonce, true).\substr(\sha1($server_nonce.$new_nonce, true), 0, 12);
$tmp_aes_iv = \substr(\sha1($server_nonce.$new_nonce, true), 12, 8).\sha1($new_nonce.$new_nonce, true).\substr($new_nonce, 0, 4); $tmp_aes_iv = \substr(\sha1($server_nonce.$new_nonce, true), 12, 8).\sha1($new_nonce.$new_nonce, true).\substr($new_nonce, 0, 4);
$answer_with_hash = $this->igeDecrypt($encrypted_answer, $tmp_aes_key, $tmp_aes_iv); $answer_with_hash = Crypt::igeDecrypt($encrypted_answer, $tmp_aes_key, $tmp_aes_iv);
/* /*
* *********************************************************************** * ***********************************************************************
* Separate answer and hash * Separate answer and hash
@ -294,7 +294,7 @@ trait AuthKeyHandler
*/ */
$data_with_sha = \sha1($data, true).$data; $data_with_sha = \sha1($data, true).$data;
$data_with_sha_padded = $data_with_sha.\danog\MadelineProto\Tools::random(\danog\MadelineProto\Tools::posmod(-\strlen($data_with_sha), 16)); $data_with_sha_padded = $data_with_sha.\danog\MadelineProto\Tools::random(\danog\MadelineProto\Tools::posmod(-\strlen($data_with_sha), 16));
$encrypted_data = $this->igeEncrypt($data_with_sha_padded, $tmp_aes_key, $tmp_aes_iv); $encrypted_data = Crypt::igeEncrypt($data_with_sha_padded, $tmp_aes_key, $tmp_aes_iv);
$this->logger->logger('Executing set_client_DH_params...', \danog\MadelineProto\Logger::VERBOSE); $this->logger->logger('Executing set_client_DH_params...', \danog\MadelineProto\Logger::VERBOSE);
/* /*
* *********************************************************************** * ***********************************************************************
@ -519,8 +519,8 @@ trait AuthKeyHandler
$encrypted_data = \danog\MadelineProto\Tools::random(16).$message_id.\pack('VV', $seq_no, \strlen($message_data)).$message_data; $encrypted_data = \danog\MadelineProto\Tools::random(16).$message_id.\pack('VV', $seq_no, \strlen($message_data)).$message_data;
$message_key = \substr(\sha1($encrypted_data, true), -16); $message_key = \substr(\sha1($encrypted_data, true), -16);
$padding = \danog\MadelineProto\Tools::random(\danog\MadelineProto\Tools::posmod(-\strlen($encrypted_data), 16)); $padding = \danog\MadelineProto\Tools::random(\danog\MadelineProto\Tools::posmod(-\strlen($encrypted_data), 16));
list($aes_key, $aes_iv) = $this->oldAesCalculate($message_key, $datacenterConnection->getPermAuthKey()->getAuthKey()); list($aes_key, $aes_iv) = Crypt::oldAesCalculate($message_key, $datacenterConnection->getPermAuthKey()->getAuthKey());
$encrypted_message = $datacenterConnection->getPermAuthKey()->getID().$message_key.$this->igeEncrypt($encrypted_data.$padding, $aes_key, $aes_iv); $encrypted_message = $datacenterConnection->getPermAuthKey()->getID().$message_key.Crypt::igeEncrypt($encrypted_data.$padding, $aes_key, $aes_iv);
$res = yield from $connection->methodCallAsyncRead('auth.bindTempAuthKey', ['perm_auth_key_id' => $perm_auth_key_id, 'nonce' => $nonce, 'expires_at' => $expires_at, 'encrypted_message' => $encrypted_message], ['msg_id' => $message_id]); $res = yield from $connection->methodCallAsyncRead('auth.bindTempAuthKey', ['perm_auth_key_id' => $perm_auth_key_id, 'nonce' => $nonce, 'expires_at' => $expires_at, 'encrypted_message' => $encrypted_message], ['msg_id' => $message_id]);
if ($res === true) { if ($res === true) {
$this->logger->logger('Bound temporary and permanent authorization keys, DC '.$datacenter, \danog\MadelineProto\Logger::NOTICE); $this->logger->logger('Bound temporary and permanent authorization keys, DC '.$datacenter, \danog\MadelineProto\Logger::NOTICE);

View File

@ -87,7 +87,7 @@ trait Files
if (!$this->settings['upload']['allow_automatic_upload']) { if (!$this->settings['upload']['allow_automatic_upload']) {
return yield from $this->uploadFromUrl($file, 0, $fileName, $cb, $encrypted); return yield from $this->uploadFromUrl($file, 0, $fileName, $cb, $encrypted);
} }
$file = \danog\MadelineProto\Absolute::absolute($file); $file = Tools::absolute($file);
if (!yield exists($file)) { if (!yield exists($file)) {
throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['file_not_exist']); throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['file_not_exist']);
} }
@ -1095,7 +1095,7 @@ trait Files
$cb = $file; $cb = $file;
$file = $file->getFile(); $file = $file->getFile();
} }
$file = \danog\MadelineProto\Absolute::absolute(\preg_replace('|/+|', '/', $file)); $file = Tools::absolute(\preg_replace('|/+|', '/', $file));
if (!yield exists($file)) { if (!yield exists($file)) {
yield \touch($file); yield \touch($file);
} }
@ -1388,7 +1388,7 @@ trait Files
} }
if (isset($messageMedia['cdn_key'])) { if (isset($messageMedia['cdn_key'])) {
$ivec = \substr($messageMedia['cdn_iv'], 0, 12).\pack('N', $offset['offset'] >> 4); $ivec = \substr($messageMedia['cdn_iv'], 0, 12).\pack('N', $offset['offset'] >> 4);
$res['bytes'] = $this->ctrEncrypt($res['bytes'], $messageMedia['cdn_key'], $ivec); $res['bytes'] = Crypt::ctrEncrypt($res['bytes'], $messageMedia['cdn_key'], $ivec);
$this->checkCdnHash($messageMedia['file_token'], $offset['offset'], $res['bytes'], $old_dc); $this->checkCdnHash($messageMedia['file_token'], $offset['offset'], $res['bytes'], $old_dc);
} }
if (isset($messageMedia['key'])) { if (isset($messageMedia['key'])) {

View File

@ -96,7 +96,7 @@ class MinDatabase implements TLCallback
public function reset() public function reset()
{ {
if ($this->cache) { if ($this->cache) {
$this->API->logger->logger('Found ' . \count($this->cache) . ' pending contexts', \danog\MadelineProto\Logger::ERROR); $this->API->logger->logger('Found '.\count($this->cache).' pending contexts', \danog\MadelineProto\Logger::ERROR);
$this->cache = []; $this->cache = [];
} }
} }
@ -130,7 +130,7 @@ class MinDatabase implements TLCallback
$frames = \array_reverse($frames); $frames = \array_reverse($frames);
$tl_trace = \array_shift($frames); $tl_trace = \array_shift($frames);
foreach ($frames as $frame) { foreach ($frames as $frame) {
$tl_trace .= "['" . $frame . "']"; $tl_trace .= "['".$frame."']";
} }
$this->API->logger->logger($tl_trace, \danog\MadelineProto\Logger::ERROR); $this->API->logger->logger($tl_trace, \danog\MadelineProto\Logger::ERROR);
return false; return false;
@ -194,7 +194,7 @@ class MinDatabase implements TLCallback
} }
$this->db[$id] = $origin; $this->db[$id] = $origin;
} }
$this->API->logger->logger("Added origin ({$data['_']}) to " . \count($cache) . ' peer locations', \danog\MadelineProto\Logger::ULTRA_VERBOSE); $this->API->logger->logger("Added origin ({$data['_']}) to ".\count($cache).' peer locations', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
} }
public function populateFrom(array $object): \Generator public function populateFrom(array $object): \Generator
{ {
@ -228,6 +228,6 @@ class MinDatabase implements TLCallback
} }
public function __debugInfo() public function __debugInfo()
{ {
return ['MinDatabase instance ' . \spl_object_hash($this)]; return ['MinDatabase instance '.\spl_object_hash($this)];
} }
} }

View File

@ -155,7 +155,7 @@ class PasswordCalculator
*/ */
public function createSalt(string $prefix = ''): string public function createSalt(string $prefix = ''): string
{ {
return $prefix . \danog\MadelineProto\Tools::random(32); return $prefix.\danog\MadelineProto\Tools::random(32);
} }
/** /**
* Hash specified data using the salt with SHA256. * Hash specified data using the salt with SHA256.
@ -168,7 +168,7 @@ class PasswordCalculator
*/ */
public function hashSha256(string $data, string $salt): string public function hashSha256(string $data, string $salt): string
{ {
return \hash('sha256', $salt . $data . $salt, true); return \hash('sha256', $salt.$data.$salt, true);
} }
/** /**
* Hashes the specified password. * Hashes the specified password.
@ -207,14 +207,14 @@ class PasswordCalculator
$id = $this->srp_id; $id = $this->srp_id;
$x = new BigInteger($this->hashPassword($password, $client_salt, $server_salt), 256); $x = new BigInteger($this->hashPassword($password, $client_salt, $server_salt), 256);
$g_x = $g->powMod($x, $p); $g_x = $g->powMod($x, $p);
$k = new BigInteger(\hash('sha256', $pForHash . $gForHash, true), 256); $k = new BigInteger(\hash('sha256', $pForHash.$gForHash, true), 256);
$kg_x = $k->multiply($g_x)->powMod(Magic::$one, $p); $kg_x = $k->multiply($g_x)->powMod(Magic::$one, $p);
$a = new BigInteger(\danog\MadelineProto\Tools::random(2048 / 8), 256); $a = new BigInteger(\danog\MadelineProto\Tools::random(2048 / 8), 256);
$A = $g->powMod($a, $p); $A = $g->powMod($a, $p);
$this->checkG($A, $p); $this->checkG($A, $p);
$AForHash = \str_pad($A->toBytes(), 256, \chr(0), \STR_PAD_LEFT); $AForHash = \str_pad($A->toBytes(), 256, \chr(0), \STR_PAD_LEFT);
$b_kg_x = $B->powMod(Magic::$one, $p)->subtract($kg_x); $b_kg_x = $B->powMod(Magic::$one, $p)->subtract($kg_x);
$u = new BigInteger(\hash('sha256', $AForHash . $BForHash, true), 256); $u = new BigInteger(\hash('sha256', $AForHash.$BForHash, true), 256);
$ux = $u->multiply($x); $ux = $u->multiply($x);
$a_ux = $a->add($ux); $a_ux = $a->add($ux);
$S = $b_kg_x->powMod($a_ux, $p); $S = $b_kg_x->powMod($a_ux, $p);
@ -223,7 +223,7 @@ class PasswordCalculator
$h1 = \hash('sha256', $pForHash, true); $h1 = \hash('sha256', $pForHash, true);
$h2 = \hash('sha256', $gForHash, true); $h2 = \hash('sha256', $gForHash, true);
$h1 ^= $h2; $h1 ^= $h2;
$M1 = \hash('sha256', $h1 . \hash('sha256', $client_salt, true) . \hash('sha256', $server_salt, true) . $AForHash . $BForHash . $K, true); $M1 = \hash('sha256', $h1.\hash('sha256', $client_salt, true).\hash('sha256', $server_salt, true).$AForHash.$BForHash.$K, true);
return ['_' => 'inputCheckPasswordSRP', 'srp_id' => $id, 'A' => $AForHash, 'M1' => $M1]; return ['_' => 'inputCheckPasswordSRP', 'srp_id' => $id, 'A' => $AForHash, 'M1' => $M1];
} }
/** /**

View File

@ -125,7 +125,7 @@ class ReferenceDatabase implements TLCallback
public function reset() public function reset()
{ {
if ($this->cacheContexts) { if ($this->cacheContexts) {
$this->API->logger->logger('Found ' . \count($this->cacheContexts) . ' pending contexts', \danog\MadelineProto\Logger::ERROR); $this->API->logger->logger('Found '.\count($this->cacheContexts).' pending contexts', \danog\MadelineProto\Logger::ERROR);
$this->cacheContexts = []; $this->cacheContexts = [];
} }
if ($this->cache) { if ($this->cache) {
@ -162,7 +162,7 @@ class ReferenceDatabase implements TLCallback
$frames = \array_reverse($frames); $frames = \array_reverse($frames);
$tl_trace = \array_shift($frames); $tl_trace = \array_shift($frames);
foreach ($frames as $frame) { foreach ($frames as $frame) {
$tl_trace .= "['" . $frame . "']"; $tl_trace .= "['".$frame."']";
} }
$this->API->logger->logger($tl_trace, \danog\MadelineProto\Logger::ERROR); $this->API->logger->logger($tl_trace, \danog\MadelineProto\Logger::ERROR);
return false; return false;
@ -183,7 +183,7 @@ class ReferenceDatabase implements TLCallback
$locationType = self::PHOTO_LOCATION_LOCATION; $locationType = self::PHOTO_LOCATION_LOCATION;
break; break;
default: default:
throw new Exception('Unknown location type provided: ' . $location['_']); throw new Exception('Unknown location type provided: '.$location['_']);
} }
$this->API->logger->logger("Caching reference from location of type {$locationType} from {$location['_']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE); $this->API->logger->logger("Caching reference from location of type {$locationType} from {$location['_']}", \danog\MadelineProto\Logger::ULTRA_VERBOSE);
if (!isset($this->cache[$key])) { if (!isset($this->cache[$key])) {
@ -266,7 +266,7 @@ class ReferenceDatabase implements TLCallback
foreach ($cache as $location => $reference) { foreach ($cache as $location => $reference) {
$this->cache[$key][$location] = $reference; $this->cache[$key][$location] = $reference;
} }
$this->API->logger->logger("Skipped origin {$originType} ({$data['_']}) for " . \count($cache) . ' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE); $this->API->logger->logger("Skipped origin {$originType} ({$data['_']}) for ".\count($cache).' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
return; return;
} }
break; break;
@ -279,7 +279,7 @@ class ReferenceDatabase implements TLCallback
foreach ($cache as $location => $reference) { foreach ($cache as $location => $reference) {
$this->storeReference($location, $reference, $originType, $origin); $this->storeReference($location, $reference, $originType, $origin);
} }
$this->API->logger->logger("Added origin {$originType} ({$data['_']}) to " . \count($cache) . ' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE); $this->API->logger->logger("Added origin {$originType} ({$data['_']}) to ".\count($cache).' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
} }
public function addOriginMethodContext(string $type) public function addOriginMethodContext(string $type)
{ {
@ -359,7 +359,7 @@ class ReferenceDatabase implements TLCallback
foreach ($cache as $location => $reference) { foreach ($cache as $location => $reference) {
$this->storeReference($location, $reference, $originType, $origin); $this->storeReference($location, $reference, $originType, $origin);
} }
$this->API->logger->logger("Added origin {$originType} ({$data['_']}) to " . \count($cache) . ' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE); $this->API->logger->logger("Added origin {$originType} ({$data['_']}) to ".\count($cache).' references', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
} }
public function storeReference(string $location, string $reference, int $originType, array $origin) public function storeReference(string $location, string $reference, int $originType, array $origin)
{ {
@ -376,7 +376,7 @@ class ReferenceDatabase implements TLCallback
$this->cache[$key][$location] = $reference; $this->cache[$key][$location] = $reference;
} }
} }
public function refreshNext($refresh = false) public function refreshNext(bool $refresh = false)
{ {
if ($this->refreshCount === 1 && !$refresh) { if ($this->refreshCount === 1 && !$refresh) {
$this->refreshed = []; $this->refreshed = [];
@ -488,16 +488,16 @@ class ReferenceDatabase implements TLCallback
switch ($locationType) { switch ($locationType) {
case self::DOCUMENT_LOCATION: case self::DOCUMENT_LOCATION:
case self::PHOTO_LOCATION: case self::PHOTO_LOCATION:
return $locationType . (\is_int($location['id']) ? \danog\MadelineProto\Tools::packSignedLong($location['id']) : $location['id']); return $locationType.(\is_int($location['id']) ? \danog\MadelineProto\Tools::packSignedLong($location['id']) : $location['id']);
case self::PHOTO_LOCATION_LOCATION: case self::PHOTO_LOCATION_LOCATION:
$dc_id = \danog\MadelineProto\Tools::packSignedInt($location['dc_id']); $dc_id = \danog\MadelineProto\Tools::packSignedInt($location['dc_id']);
$volume_id = \is_int($location['volume_id']) ? \danog\MadelineProto\Tools::packSignedLong($location['volume_id']) : $location['volume_id']; $volume_id = \is_int($location['volume_id']) ? \danog\MadelineProto\Tools::packSignedLong($location['volume_id']) : $location['volume_id'];
$local_id = \danog\MadelineProto\Tools::packSignedInt($location['local_id']); $local_id = \danog\MadelineProto\Tools::packSignedInt($location['local_id']);
return $locationType . $dc_id . $volume_id . $local_id; return $locationType.$dc_id.$volume_id.$local_id;
} }
} }
public function __debugInfo() public function __debugInfo()
{ {
return ['ReferenceDatabase instance ' . \spl_object_hash($this)]; return ['ReferenceDatabase instance '.\spl_object_hash($this)];
} }
} }

View File

@ -249,7 +249,7 @@ trait UpdateHandler
if ($actual_updates) { if ($actual_updates) {
$updates = $actual_updates; $updates = $actual_updates;
} }
$this->logger->logger('Parsing updates (' . $updates['_'] . ') received via the socket...', \danog\MadelineProto\Logger::VERBOSE); $this->logger->logger('Parsing updates ('.$updates['_'].') received via the socket...', \danog\MadelineProto\Logger::VERBOSE);
switch ($updates['_']) { switch ($updates['_']) {
case 'updates': case 'updates':
case 'updatesCombined': case 'updatesCombined':
@ -311,7 +311,7 @@ trait UpdateHandler
$this->updaters[false]->resume(); $this->updaters[false]->resume();
break; break;
default: default:
throw new \danog\MadelineProto\ResponseException('Unrecognized update received: ' . \var_export($updates, true)); throw new \danog\MadelineProto\ResponseException('Unrecognized update received: '.\var_export($updates, true));
break; break;
} }
} }
@ -382,15 +382,15 @@ trait UpdateHandler
$cur_state->qts($update['qts']); $cur_state->qts($update['qts']);
} }
if ($update['qts'] < $cur_state->qts()) { if ($update['qts'] < $cur_state->qts()) {
$this->logger->logger('Duplicate update. update qts: ' . $update['qts'] . ' <= current qts ' . $cur_state->qts() . ', chat id: ' . $update['message']['chat_id'], \danog\MadelineProto\Logger::ERROR); $this->logger->logger('Duplicate update. update qts: '.$update['qts'].' <= current qts '.$cur_state->qts().', chat id: '.$update['message']['chat_id'], \danog\MadelineProto\Logger::ERROR);
return false; return false;
} }
if ($update['qts'] > $cur_state->qts() + 1) { if ($update['qts'] > $cur_state->qts() + 1) {
$this->logger->logger('Qts hole. Fetching updates manually: update qts: ' . $update['qts'] . ' > current qts ' . $cur_state->qts() . '+1, chat id: ' . $update['message']['chat_id'], \danog\MadelineProto\Logger::ERROR); $this->logger->logger('Qts hole. Fetching updates manually: update qts: '.$update['qts'].' > current qts '.$cur_state->qts().'+1, chat id: '.$update['message']['chat_id'], \danog\MadelineProto\Logger::ERROR);
$this->updaters[false]->resumeDefer(); $this->updaters[false]->resumeDefer();
return false; return false;
} }
$this->logger->logger('Applying qts: ' . $update['qts'] . ' over current qts ' . $cur_state->qts() . ', chat id: ' . $update['message']['chat_id'], \danog\MadelineProto\Logger::VERBOSE); $this->logger->logger('Applying qts: '.$update['qts'].' over current qts '.$cur_state->qts().', chat id: '.$update['message']['chat_id'], \danog\MadelineProto\Logger::VERBOSE);
yield from $this->methodCallAsyncRead('messages.receivedQueue', ['max_qts' => $cur_state->qts($update['qts'])], ['datacenter' => $this->settings['connection_settings']['default_dc']]); yield from $this->methodCallAsyncRead('messages.receivedQueue', ['max_qts' => $cur_state->qts($update['qts'])], ['datacenter' => $this->settings['connection_settings']['default_dc']]);
} }
yield from $this->handleEncryptedUpdate($update); yield from $this->handleEncryptedUpdate($update);
@ -407,7 +407,7 @@ trait UpdateHandler
if ($this->settings['secret_chats']['accept_chats'] === false || \is_array($this->settings['secret_chats']['accept_chats']) && !\in_array($update['chat']['admin_id'], $this->settings['secret_chats']['accept_chats'])) { if ($this->settings['secret_chats']['accept_chats'] === false || \is_array($this->settings['secret_chats']['accept_chats']) && !\in_array($update['chat']['admin_id'], $this->settings['secret_chats']['accept_chats'])) {
return; return;
} }
$this->logger->logger('Accepting secret chat ' . $update['chat']['id'], \danog\MadelineProto\Logger::NOTICE); $this->logger->logger('Accepting secret chat '.$update['chat']['id'], \danog\MadelineProto\Logger::NOTICE);
try { try {
yield from $this->acceptSecretChat($update['chat']); yield from $this->acceptSecretChat($update['chat']);
} catch (RPCErrorException $e) { } catch (RPCErrorException $e) {
@ -415,7 +415,7 @@ trait UpdateHandler
} }
break; break;
case 'encryptedChatDiscarded': case 'encryptedChatDiscarded':
$this->logger->logger('Deleting secret chat ' . $update['chat']['id'] . ' because it was revoked by the other user', \danog\MadelineProto\Logger::NOTICE); $this->logger->logger('Deleting secret chat '.$update['chat']['id'].' because it was revoked by the other user', \danog\MadelineProto\Logger::NOTICE);
if (isset($this->secret_chats[$update['chat']['id']])) { if (isset($this->secret_chats[$update['chat']['id']])) {
unset($this->secret_chats[$update['chat']['id']]); unset($this->secret_chats[$update['chat']['id']]);
} }
@ -427,7 +427,7 @@ trait UpdateHandler
} }
break; break;
case 'encryptedChat': case 'encryptedChat':
$this->logger->logger('Completing creation of secret chat ' . $update['chat']['id'], \danog\MadelineProto\Logger::NOTICE); $this->logger->logger('Completing creation of secret chat '.$update['chat']['id'], \danog\MadelineProto\Logger::NOTICE);
yield from $this->completeSecretChat($update['chat']); yield from $this->completeSecretChat($update['chat']);
break; break;
} }
@ -471,7 +471,7 @@ trait UpdateHandler
$request->setHeader('content-type', 'application/json'); $request->setHeader('content-type', 'application/json');
$request->setBody($payload); $request->setBody($payload);
$result = yield (yield $this->datacenter->getHTTPClient()->request($request))->getBody()->buffer(); $result = yield (yield $this->datacenter->getHTTPClient()->request($request))->getBody()->buffer();
$this->logger->logger('Result of webhook query is ' . $result, \danog\MadelineProto\Logger::NOTICE); $this->logger->logger('Result of webhook query is '.$result, \danog\MadelineProto\Logger::NOTICE);
$result = \json_decode($result, true); $result = \json_decode($result, true);
if (\is_array($result) && isset($result['method']) && $result['method'] != '' && \is_string($result['method'])) { if (\is_array($result) && isset($result['method']) && $result['method'] != '' && \is_string($result['method'])) {
try { try {

View File

@ -27,24 +27,71 @@ use Amp\Http\Client\Request;
*/ */
class MyTelegramOrgWrapper class MyTelegramOrgWrapper
{ {
private $logged = false; /**
private $hash = ''; * Whether we're logged in.
private $number; */
private $creation_hash; private bool $logged = false;
private $settings = []; /**
private $async = true; * Login hash.
*/
private string $hash = '';
/**
* Phone number.
*
* @var string
*/
private string $number = '';
/**
* Creation hash.
*/
private string $creation_hash = '';
/**
* Settings.
*/
private array $settings = [];
/**
* Async setting.
*/
private bool $async = true;
/**
* Datacenter instance.
*/
private DataCenter $datacenter;
/**
* Cooke jar.
*
* @var InMemoryCookieJar
*/
private $jar; private $jar;
/**
* Endpoint.
*/
const MY_TELEGRAM_URL = 'https://my.telegram.org'; const MY_TELEGRAM_URL = 'https://my.telegram.org';
public function __sleep() /**
* Sleep function.
*
* @return array
*/
public function __sleep(): array
{ {
return ['logged', 'hash', 'number', 'creation_hash', 'settings', 'async', 'jar']; return ['logged', 'hash', 'number', 'creation_hash', 'settings', 'async', 'jar'];
} }
public function __construct($settings = []) /**
* Constructor.
*
* @param array $settings
*/
public function __construct(array $settings = [])
{ {
$this->settings = MTProto::parseSettings($settings, $this->settings); $this->settings = MTProto::parseSettings($settings, $this->settings);
$this->__wakeup(); $this->__wakeup();
} }
public function __wakeup() /**
* Wakeup function.
*
* @return void
*/
public function __wakeup(): void
{ {
if ($this->settings === null) { if ($this->settings === null) {
$this->settings = []; $this->settings = [];
@ -64,10 +111,17 @@ class MyTelegramOrgWrapper
} }
}, [], $this->settings['connection_settings'], true, $this->jar); }, [], $this->settings['connection_settings'], true, $this->jar);
} }
public function login($number): \Generator /**
* Login.
*
* @param string $number Phone number
*
* @return \Generator
*/
public function login(string $number): \Generator
{ {
$this->number = $number; $this->number = $number;
$request = new Request(self::MY_TELEGRAM_URL . '/auth/send_password', 'POST'); $request = new Request(self::MY_TELEGRAM_URL.'/auth/send_password', 'POST');
$request->setBody(\http_build_query(['phone' => $number])); $request->setBody(\http_build_query(['phone' => $number]));
$request->setHeaders($this->getHeaders('origin')); $request->setHeaders($this->getHeaders('origin'));
$response = yield $this->datacenter->getHTTPClient()->request($request); $response = yield $this->datacenter->getHTTPClient()->request($request);
@ -78,12 +132,19 @@ class MyTelegramOrgWrapper
} }
$this->hash = $resulta['random_hash']; $this->hash = $resulta['random_hash'];
} }
public function completeLogin($password): \Generator /**
* Complete login.
*
* @param string $password Password
*
* @return \Generator
*/
public function completeLogin(string $password): \Generator
{ {
if ($this->logged) { if ($this->logged) {
throw new Exception('Already logged in!'); throw new Exception('Already logged in!');
} }
$request = new Request(self::MY_TELEGRAM_URL . '/auth/login', 'POST'); $request = new Request(self::MY_TELEGRAM_URL.'/auth/login', 'POST');
$request->setBody(\http_build_query(['phone' => $this->number, 'random_hash' => $this->hash, 'password' => $password])); $request->setBody(\http_build_query(['phone' => $this->number, 'random_hash' => $this->hash, 'password' => $password]));
$request->setHeaders($this->getHeaders('origin')); $request->setHeaders($this->getHeaders('origin'));
$request->setHeader('user-agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13'); $request->setHeader('user-agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13');
@ -98,16 +159,26 @@ class MyTelegramOrgWrapper
} }
return $this->logged = true; return $this->logged = true;
} }
public function loggedIn() /**
* Whether we are logged in.
*
* @return boolean
*/
public function loggedIn(): bool
{ {
return $this->logged; return $this->logged;
} }
/**
* Check if an app was already created.
*
* @return \Generator
*/
public function hasApp(): \Generator public function hasApp(): \Generator
{ {
if (!$this->logged) { if (!$this->logged) {
throw new Exception('Not logged in!'); throw new Exception('Not logged in!');
} }
$request = new Request(self::MY_TELEGRAM_URL . '/apps'); $request = new Request(self::MY_TELEGRAM_URL.'/apps');
$request->setHeaders($this->getHeaders('refer')); $request->setHeaders($this->getHeaders('refer'));
$response = yield $this->datacenter->getHTTPClient()->request($request); $response = yield $this->datacenter->getHTTPClient()->request($request);
$result = yield $response->getBody()->buffer(); $result = yield $response->getBody()->buffer();
@ -122,12 +193,17 @@ class MyTelegramOrgWrapper
$this->logged = false; $this->logged = false;
throw new Exception($title); throw new Exception($title);
} }
/**
* Get the currently created app.
*
* @return \Generator
*/
public function getApp(): \Generator public function getApp(): \Generator
{ {
if (!$this->logged) { if (!$this->logged) {
throw new Exception('Not logged in!'); throw new Exception('Not logged in!');
} }
$request = new Request(self::MY_TELEGRAM_URL . '/apps'); $request = new Request(self::MY_TELEGRAM_URL.'/apps');
$request->setHeaders($this->getHeaders('refer')); $request->setHeaders($this->getHeaders('refer'));
$response = yield $this->datacenter->getHTTPClient()->request($request); $response = yield $this->datacenter->getHTTPClient()->request($request);
$result = yield $response->getBody()->buffer(); $result = yield $response->getBody()->buffer();
@ -143,7 +219,14 @@ class MyTelegramOrgWrapper
$api_hash = $asd[0]; $api_hash = $asd[0];
return ['api_id' => (int) $api_id, 'api_hash' => $api_hash]; return ['api_id' => (int) $api_id, 'api_hash' => $api_hash];
} }
public function createApp($settings): \Generator /**
* Create an app.
*
* @param array $settings App parameters
*
* @return \Generator
*/
public function createApp(array $settings): \Generator
{ {
if (!$this->logged) { if (!$this->logged) {
throw new Exception('Not logged in!'); throw new Exception('Not logged in!');
@ -151,7 +234,7 @@ class MyTelegramOrgWrapper
if (yield from $this->hasApp()) { if (yield from $this->hasApp()) {
throw new Exception('The app was already created!'); throw new Exception('The app was already created!');
} }
$request = new Request(self::MY_TELEGRAM_URL . '/apps/create', 'POST'); $request = new Request(self::MY_TELEGRAM_URL.'/apps/create', 'POST');
$request->setHeaders($this->getHeaders('app')); $request->setHeaders($this->getHeaders('app'));
$request->setBody(\http_build_query(['hash' => $this->creation_hash, 'app_title' => $settings['app_title'], 'app_shortname' => $settings['app_shortname'], 'app_url' => $settings['app_url'], 'app_platform' => $settings['app_platform'], 'app_desc' => $settings['app_desc']])); $request->setBody(\http_build_query(['hash' => $this->creation_hash, 'app_title' => $settings['app_title'], 'app_shortname' => $settings['app_shortname'], 'app_url' => $settings['app_url'], 'app_platform' => $settings['app_platform'], 'app_desc' => $settings['app_desc']]));
$response = yield $this->datacenter->getHTTPClient()->request($request); $response = yield $this->datacenter->getHTTPClient()->request($request);
@ -159,7 +242,7 @@ class MyTelegramOrgWrapper
if ($result) { if ($result) {
throw new Exception(\html_entity_decode($result)); throw new Exception(\html_entity_decode($result));
} }
$request = new Request(self::MY_TELEGRAM_URL . '/apps'); $request = new Request(self::MY_TELEGRAM_URL.'/apps');
$request->setHeaders($this->getHeaders('refer')); $request->setHeaders($this->getHeaders('refer'));
$response = yield $this->datacenter->getHTTPClient()->request($request); $response = yield $this->datacenter->getHTTPClient()->request($request);
$result = yield $response->getBody()->buffer(); $result = yield $response->getBody()->buffer();
@ -182,8 +265,12 @@ class MyTelegramOrgWrapper
} }
/** /**
* Function for generating curl request headers. * Function for generating curl request headers.
*
* @param string $httpType Origin
*
* @return array
*/ */
private function getHeaders($httpType) private function getHeaders(string $httpType): array
{ {
// Common header flags. // Common header flags.
$headers = []; $headers = [];
@ -194,26 +281,26 @@ class MyTelegramOrgWrapper
// Add additional headers based on the type of request. // Add additional headers based on the type of request.
switch ($httpType) { switch ($httpType) {
case 'origin': case 'origin':
$headers[] = 'Origin: ' . self::MY_TELEGRAM_URL; $headers[] = 'Origin: '.self::MY_TELEGRAM_URL;
//$headers[] = 'Accept-Encoding: gzip, deflate, br'; //$headers[] = 'Accept-Encoding: gzip, deflate, br';
$headers[] = 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8'; $headers[] = 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8';
$headers[] = 'Accept: application/json, text/javascript, */*; q=0.01'; $headers[] = 'Accept: application/json, text/javascript, */*; q=0.01';
$headers[] = 'Referer: ' . self::MY_TELEGRAM_URL . '/auth'; $headers[] = 'Referer: '.self::MY_TELEGRAM_URL.'/auth';
$headers[] = 'X-Requested-With: XMLHttpRequest'; $headers[] = 'X-Requested-With: XMLHttpRequest';
break; break;
case 'refer': case 'refer':
//$headers[] = 'Accept-Encoding: gzip, deflate, sdch, br'; //$headers[] = 'Accept-Encoding: gzip, deflate, sdch, br';
$headers[] = 'Upgrade-Insecure-Requests: 1'; $headers[] = 'Upgrade-Insecure-Requests: 1';
$headers[] = 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'; $headers[] = 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8';
$headers[] = 'Referer: ' . self::MY_TELEGRAM_URL; $headers[] = 'Referer: '.self::MY_TELEGRAM_URL;
$headers[] = 'Cache-Control: max-age=0'; $headers[] = 'Cache-Control: max-age=0';
break; break;
case 'app': case 'app':
$headers[] = 'Origin: ' . self::MY_TELEGRAM_URL; $headers[] = 'Origin: '.self::MY_TELEGRAM_URL;
//$headers[] = 'Accept-Encoding: gzip, deflate, br'; //$headers[] = 'Accept-Encoding: gzip, deflate, br';
$headers[] = 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8'; $headers[] = 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8';
$headers[] = 'Accept: */*'; $headers[] = 'Accept: */*';
$headers[] = 'Referer: ' . self::MY_TELEGRAM_URL . '/apps'; $headers[] = 'Referer: '.self::MY_TELEGRAM_URL.'/apps';
$headers[] = 'X-Requested-With: XMLHttpRequest'; $headers[] = 'X-Requested-With: XMLHttpRequest';
break; break;
} }
@ -224,15 +311,37 @@ class MyTelegramOrgWrapper
} }
return $final_headers; return $final_headers;
} }
public function async($async) /**
* Enable or disable async.
*
* @param boolean $async Async
*
* @return void
*/
public function async(bool $async): void
{ {
$this->async = $async; $this->async = $async;
} }
public function loop($callable) /**
* Run specified callable synchronously.
*
* @param callable $callable Callable
*
* @return mixed
*/
public function loop(callable $callable)
{ {
return Tools::wait($callable()); return Tools::wait($callable());
} }
public function __call($name, $arguments) /**
* Call function.
*
* @param string $name Function name
* @param array $arguments Arguments
*
* @return void
*/
public function __call(string $name, array $arguments)
{ {
$name .= '_async'; $name .= '_async';
$async = \is_array(\end($arguments)) && isset(\end($arguments)['async']) ? \end($arguments)['async'] : $this->async; $async = \is_array(\end($arguments)) && isset(\end($arguments)['async']) ? \end($arguments)['async'] : $this->async;

View File

@ -24,7 +24,7 @@ class PTSException extends \Exception
use TL\PrettyException; use TL\PrettyException;
public function __toString() public function __toString()
{ {
return \get_class($this) . ($this->message !== '' ? ': ' : '') . $this->message . PHP_EOL . 'TL Trace:' . PHP_EOL . PHP_EOL . $this->getTLTrace() . PHP_EOL; return \get_class($this).($this->message !== '' ? ': ' : '').$this->message.PHP_EOL.'TL Trace:'.PHP_EOL.PHP_EOL.$this->getTLTrace().PHP_EOL;
} }
public function __construct($message, $file = '') public function __construct($message, $file = '')
{ {

View File

@ -22,11 +22,15 @@ namespace danog\MadelineProto;
class RPCErrorException extends \Exception class RPCErrorException extends \Exception
{ {
use TL\PrettyException; use TL\PrettyException;
/**
* RPC error code
*/
public string $rpc = '';
private $fetched = false; private $fetched = false;
public static $descriptions = ['RPC_MCGET_FAIL' => 'Telegram is having internal issues, please try again later.', 'RPC_CALL_FAIL' => 'Telegram is having internal issues, please try again later.', 'USER_PRIVACY_RESTRICTED' => "The user's privacy settings do not allow you to do this", 'CHANNEL_PRIVATE' => "You haven't joined this channel/supergroup", 'USER_IS_BOT' => "Bots can't send messages to other bots", 'BOT_METHOD_INVALID' => 'This method cannot be run by a bot', 'PHONE_CODE_EXPIRED' => 'The phone code you provided has expired, this may happen if it was sent to any chat on telegram (if the code is sent through a telegram chat (not the official account) to avoid it append or prepend to the code some chars)', 'USERNAME_INVALID' => 'The provided username is not valid', 'ACCESS_TOKEN_INVALID' => 'The provided token is not valid', 'ACTIVE_USER_REQUIRED' => 'The method is only available to already activated users', 'FIRSTNAME_INVALID' => 'The first name is invalid', 'LASTNAME_INVALID' => 'The last name is invalid', 'PHONE_NUMBER_INVALID' => 'The phone number is invalid', 'PHONE_CODE_HASH_EMPTY' => 'phone_code_hash is missing', 'PHONE_CODE_EMPTY' => 'phone_code is missing', 'API_ID_INVALID' => 'The api_id/api_hash combination is invalid', 'PHONE_NUMBER_OCCUPIED' => 'The phone number is already in use', 'PHONE_NUMBER_UNOCCUPIED' => 'The phone number is not yet being used', 'USERS_TOO_FEW' => 'Not enough users (to create a chat, for example)', 'USERS_TOO_MUCH' => 'The maximum number of users has been exceeded (to create a chat, for example)', 'TYPE_CONSTRUCTOR_INVALID' => 'The type constructor is invalid', 'FILE_PART_INVALID' => 'The file part number is invalid', 'FILE_PARTS_INVALID' => 'The number of file parts is invalid', 'MD5_CHECKSUM_INVALID' => 'The MD5 checksums do not match', 'PHOTO_INVALID_DIMENSIONS' => 'The photo dimensions are invalid', 'FIELD_NAME_INVALID' => 'The field with the name FIELD_NAME is invalid', 'FIELD_NAME_EMPTY' => 'The field with the name FIELD_NAME is missing', 'MSG_WAIT_FAILED' => 'A waiting call returned an error', 'USERNAME_NOT_OCCUPIED' => 'The provided username is not occupied', 'PHONE_NUMBER_BANNED' => 'The provided phone number is banned from telegram', 'AUTH_KEY_UNREGISTERED' => 'The authorization key has expired', 'INVITE_HASH_EXPIRED' => 'The invite link has expired', 'USER_DEACTIVATED' => 'The user was deactivated', 'USER_ALREADY_PARTICIPANT' => 'The user is already in the group', 'MESSAGE_ID_INVALID' => 'The provided message id is invalid', 'PEER_ID_INVALID' => 'The provided peer id is invalid', 'CHAT_ID_INVALID' => 'The provided chat id is invalid', 'MESSAGE_DELETE_FORBIDDEN' => "You can't delete one of the messages you tried to delete, most likely because it is a service message.", 'CHAT_ADMIN_REQUIRED' => 'You must be an admin in this chat to do this', -429 => 'Too many requests', 'PEER_FLOOD' => "You are spamreported, you can't do this"]; public static $descriptions = ['RPC_MCGET_FAIL' => 'Telegram is having internal issues, please try again later.', 'RPC_CALL_FAIL' => 'Telegram is having internal issues, please try again later.', 'USER_PRIVACY_RESTRICTED' => "The user's privacy settings do not allow you to do this", 'CHANNEL_PRIVATE' => "You haven't joined this channel/supergroup", 'USER_IS_BOT' => "Bots can't send messages to other bots", 'BOT_METHOD_INVALID' => 'This method cannot be run by a bot', 'PHONE_CODE_EXPIRED' => 'The phone code you provided has expired, this may happen if it was sent to any chat on telegram (if the code is sent through a telegram chat (not the official account) to avoid it append or prepend to the code some chars)', 'USERNAME_INVALID' => 'The provided username is not valid', 'ACCESS_TOKEN_INVALID' => 'The provided token is not valid', 'ACTIVE_USER_REQUIRED' => 'The method is only available to already activated users', 'FIRSTNAME_INVALID' => 'The first name is invalid', 'LASTNAME_INVALID' => 'The last name is invalid', 'PHONE_NUMBER_INVALID' => 'The phone number is invalid', 'PHONE_CODE_HASH_EMPTY' => 'phone_code_hash is missing', 'PHONE_CODE_EMPTY' => 'phone_code is missing', 'API_ID_INVALID' => 'The api_id/api_hash combination is invalid', 'PHONE_NUMBER_OCCUPIED' => 'The phone number is already in use', 'PHONE_NUMBER_UNOCCUPIED' => 'The phone number is not yet being used', 'USERS_TOO_FEW' => 'Not enough users (to create a chat, for example)', 'USERS_TOO_MUCH' => 'The maximum number of users has been exceeded (to create a chat, for example)', 'TYPE_CONSTRUCTOR_INVALID' => 'The type constructor is invalid', 'FILE_PART_INVALID' => 'The file part number is invalid', 'FILE_PARTS_INVALID' => 'The number of file parts is invalid', 'MD5_CHECKSUM_INVALID' => 'The MD5 checksums do not match', 'PHOTO_INVALID_DIMENSIONS' => 'The photo dimensions are invalid', 'FIELD_NAME_INVALID' => 'The field with the name FIELD_NAME is invalid', 'FIELD_NAME_EMPTY' => 'The field with the name FIELD_NAME is missing', 'MSG_WAIT_FAILED' => 'A waiting call returned an error', 'USERNAME_NOT_OCCUPIED' => 'The provided username is not occupied', 'PHONE_NUMBER_BANNED' => 'The provided phone number is banned from telegram', 'AUTH_KEY_UNREGISTERED' => 'The authorization key has expired', 'INVITE_HASH_EXPIRED' => 'The invite link has expired', 'USER_DEACTIVATED' => 'The user was deactivated', 'USER_ALREADY_PARTICIPANT' => 'The user is already in the group', 'MESSAGE_ID_INVALID' => 'The provided message id is invalid', 'PEER_ID_INVALID' => 'The provided peer id is invalid', 'CHAT_ID_INVALID' => 'The provided chat id is invalid', 'MESSAGE_DELETE_FORBIDDEN' => "You can't delete one of the messages you tried to delete, most likely because it is a service message.", 'CHAT_ADMIN_REQUIRED' => 'You must be an admin in this chat to do this', -429 => 'Too many requests', 'PEER_FLOOD' => "You are spamreported, you can't do this"];
public static $errorMethodMap = []; public static $errorMethodMap = [];
private $caller = ''; private $caller = '';
public static function localizeMessage($method, $code, $error) public static function localizeMessage($method, int $code, string $error)
{ {
if (!$method || !$code || !$error) { if (!$method || !$code || !$error) {
return $error; return $error;
@ -34,7 +38,7 @@ class RPCErrorException extends \Exception
$error = \preg_replace('/\\d+$/', "X", $error); $error = \preg_replace('/\\d+$/', "X", $error);
$description = self::$descriptions[$error] ?? ''; $description = self::$descriptions[$error] ?? '';
if (!isset(self::$errorMethodMap[$code][$method][$error]) || !isset(self::$descriptions[$error]) || $code === 500) { if (!isset(self::$errorMethodMap[$code][$method][$error]) || !isset(self::$descriptions[$error]) || $code === 500) {
$res = \json_decode(@\file_get_contents('https://rpc.pwrtelegram.xyz/?method=' . $method . '&code=' . $code . '&error=' . $error, false, \stream_context_create(['http' => ['timeout' => 3]])), true); $res = \json_decode(@\file_get_contents('https://rpc.pwrtelegram.xyz/?method='.$method.'&code='.$code.'&error='.$error, false, \stream_context_create(['http' => ['timeout' => 3]])), true);
if (isset($res['ok']) && $res['ok'] && isset($res['result'])) { if (isset($res['ok']) && $res['ok'] && isset($res['result'])) {
$description = $res['result']; $description = $res['result'];
self::$descriptions[$error] = $description; self::$descriptions[$error] = $description;
@ -48,9 +52,9 @@ class RPCErrorException extends \Exception
} }
public function __toString() public function __toString()
{ {
$result = \sprintf(\danog\MadelineProto\Lang::$current_lang['rpc_tg_error'], self::localizeMessage($this->caller, $this->code, $this->message) . " ({$this->code})", $this->rpc, $this->file, $this->line . PHP_EOL, \danog\MadelineProto\Magic::$revision . PHP_EOL . PHP_EOL) . PHP_EOL . $this->getTLTrace() . PHP_EOL; $result = \sprintf(\danog\MadelineProto\Lang::$current_lang['rpc_tg_error'], self::localizeMessage($this->caller, $this->code, $this->message)." ({$this->code})", $this->rpc, $this->file, $this->line.PHP_EOL, \danog\MadelineProto\Magic::$revision.PHP_EOL.PHP_EOL).PHP_EOL.$this->getTLTrace().PHP_EOL;
if (PHP_SAPI !== 'cli') { if (PHP_SAPI !== 'cli') {
$result = \str_replace(PHP_EOL, '<br>' . PHP_EOL, $result); $result = \str_replace(PHP_EOL, '<br>'.PHP_EOL, $result);
} }
return $result; return $result;
} }

View File

@ -61,7 +61,7 @@ class RSA
$this->n = Tools::getVar($key, 'modulus'); $this->n = Tools::getVar($key, 'modulus');
$this->e = Tools::getVar($key, 'exponent'); $this->e = Tools::getVar($key, 'exponent');
\danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['computing_fingerprint'], Logger::ULTRA_VERBOSE); \danog\MadelineProto\Logger::log(\danog\MadelineProto\Lang::$current_lang['computing_fingerprint'], Logger::ULTRA_VERBOSE);
$this->fp = \substr(\sha1((yield from $TL->serializeObject(['type' => 'bytes'], $this->n->toBytes(), 'key')) . (yield from $TL->serializeObject(['type' => 'bytes'], $this->e->toBytes(), 'key')), true), -8); $this->fp = \substr(\sha1((yield from $TL->serializeObject(['type' => 'bytes'], $this->n->toBytes(), 'key')).(yield from $TL->serializeObject(['type' => 'bytes'], $this->e->toBytes(), 'key')), true), -8);
return $this; return $this;
} }
/** /**

View File

@ -52,7 +52,7 @@ trait AuthKeyHandler
//$this->logger->logger($params['id'],$this->secretChatStatus($params['id'])); //$this->logger->logger($params['id'],$this->secretChatStatus($params['id']));
if ($this->secretChatStatus($params['id']) !== 0) { if ($this->secretChatStatus($params['id']) !== 0) {
//$this->logger->logger($this->secretChatStatus($params['id'])); //$this->logger->logger($this->secretChatStatus($params['id']));
$this->logger->logger("I've already accepted secret chat " . $params['id']); $this->logger->logger("I've already accepted secret chat ".$params['id']);
return false; return false;
} }
$dh_config = (yield from $this->getDhConfig()); $dh_config = (yield from $this->getDhConfig());
@ -70,7 +70,7 @@ trait AuthKeyHandler
$this->checkG($g_b, $dh_config['p']); $this->checkG($g_b, $dh_config['p']);
yield from $this->methodCallAsyncRead('messages.acceptEncryption', ['peer' => $params['id'], 'g_b' => $g_b->toBytes(), 'key_fingerprint' => $key['fingerprint']], ['datacenter' => $this->datacenter->curdc]); yield from $this->methodCallAsyncRead('messages.acceptEncryption', ['peer' => $params['id'], 'g_b' => $g_b->toBytes(), 'key_fingerprint' => $key['fingerprint']], ['datacenter' => $this->datacenter->curdc]);
yield from $this->notifyLayer($params['id']); yield from $this->notifyLayer($params['id']);
$this->logger->logger('Secret chat ' . $params['id'] . ' accepted successfully!', \danog\MadelineProto\Logger::NOTICE); $this->logger->logger('Secret chat '.$params['id'].' accepted successfully!', \danog\MadelineProto\Logger::NOTICE);
} }
/** /**
* Request secret chat. * Request secret chat.
@ -86,7 +86,7 @@ trait AuthKeyHandler
throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database'); throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database');
} }
$user = $user['InputUser']; $user = $user['InputUser'];
$this->logger->logger('Creating secret chat with ' . $user['user_id'] . '...', \danog\MadelineProto\Logger::VERBOSE); $this->logger->logger('Creating secret chat with '.$user['user_id'].'...', \danog\MadelineProto\Logger::VERBOSE);
$dh_config = (yield from $this->getDhConfig()); $dh_config = (yield from $this->getDhConfig());
$this->logger->logger('Generating a...', \danog\MadelineProto\Logger::VERBOSE); $this->logger->logger('Generating a...', \danog\MadelineProto\Logger::VERBOSE);
$a = new \tgseclib\Math\BigInteger(\danog\MadelineProto\Tools::random(256), 256); $a = new \tgseclib\Math\BigInteger(\danog\MadelineProto\Tools::random(256), 256);
@ -96,7 +96,7 @@ trait AuthKeyHandler
$res = yield from $this->methodCallAsyncRead('messages.requestEncryption', ['user_id' => $user, 'g_a' => $g_a->toBytes()], ['datacenter' => $this->datacenter->curdc]); $res = yield from $this->methodCallAsyncRead('messages.requestEncryption', ['user_id' => $user, 'g_a' => $g_a->toBytes()], ['datacenter' => $this->datacenter->curdc]);
$this->temp_requested_secret_chats[$res['id']] = $a; $this->temp_requested_secret_chats[$res['id']] = $a;
$this->updaters[false]->resume(); $this->updaters[false]->resume();
$this->logger->logger('Secret chat ' . $res['id'] . ' requested successfully!', \danog\MadelineProto\Logger::NOTICE); $this->logger->logger('Secret chat '.$res['id'].' requested successfully!', \danog\MadelineProto\Logger::NOTICE);
return $res['id']; return $res['id'];
} }
/** /**
@ -110,7 +110,7 @@ trait AuthKeyHandler
{ {
if ($this->secretChatStatus($params['id']) !== 1) { if ($this->secretChatStatus($params['id']) !== 1) {
//$this->logger->logger($this->secretChatStatus($params['id'])); //$this->logger->logger($this->secretChatStatus($params['id']));
$this->logger->logger('Could not find and complete secret chat ' . $params['id']); $this->logger->logger('Could not find and complete secret chat '.$params['id']);
return false; return false;
} }
$dh_config = (yield from $this->getDhConfig()); $dh_config = (yield from $this->getDhConfig());
@ -128,7 +128,7 @@ trait AuthKeyHandler
$key['visualization_46'] = \substr(\hash('sha256', $key['auth_key'], true), 20); $key['visualization_46'] = \substr(\hash('sha256', $key['auth_key'], true), 20);
$this->secret_chats[$params['id']] = ['key' => $key, 'admin' => true, 'user_id' => $params['participant_id'], 'InputEncryptedChat' => ['chat_id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputEncryptedChat'], 'in_seq_no_x' => 0, 'out_seq_no_x' => 1, 'in_seq_no' => 0, 'out_seq_no' => 0, 'layer' => 8, 'ttl' => 0, 'ttr' => 100, 'updated' => \time(), 'incoming' => [], 'outgoing' => [], 'created' => \time(), 'rekeying' => [0], 'key_x' => 'to server', 'mtproto' => 1]; $this->secret_chats[$params['id']] = ['key' => $key, 'admin' => true, 'user_id' => $params['participant_id'], 'InputEncryptedChat' => ['chat_id' => $params['id'], 'access_hash' => $params['access_hash'], '_' => 'inputEncryptedChat'], 'in_seq_no_x' => 0, 'out_seq_no_x' => 1, 'in_seq_no' => 0, 'out_seq_no' => 0, 'layer' => 8, 'ttl' => 0, 'ttr' => 100, 'updated' => \time(), 'incoming' => [], 'outgoing' => [], 'created' => \time(), 'rekeying' => [0], 'key_x' => 'to server', 'mtproto' => 1];
yield from $this->notifyLayer($params['id']); yield from $this->notifyLayer($params['id']);
$this->logger->logger('Secret chat ' . $params['id'] . ' completed successfully!', \danog\MadelineProto\Logger::NOTICE); $this->logger->logger('Secret chat '.$params['id'].' completed successfully!', \danog\MadelineProto\Logger::NOTICE);
} }
private function notifyLayer($chat): \Generator private function notifyLayer($chat): \Generator
{ {
@ -152,7 +152,7 @@ trait AuthKeyHandler
if ($this->secret_chats[$chat]['rekeying'][0] !== 0) { if ($this->secret_chats[$chat]['rekeying'][0] !== 0) {
return; return;
} }
$this->logger->logger('Rekeying secret chat ' . $chat . '...', \danog\MadelineProto\Logger::VERBOSE); $this->logger->logger('Rekeying secret chat '.$chat.'...', \danog\MadelineProto\Logger::VERBOSE);
$dh_config = (yield from $this->getDhConfig()); $dh_config = (yield from $this->getDhConfig());
$this->logger->logger('Generating a...', \danog\MadelineProto\Logger::VERBOSE); $this->logger->logger('Generating a...', \danog\MadelineProto\Logger::VERBOSE);
$a = new \tgseclib\Math\BigInteger(\danog\MadelineProto\Tools::random(256), 256); $a = new \tgseclib\Math\BigInteger(\danog\MadelineProto\Tools::random(256), 256);
@ -188,7 +188,7 @@ trait AuthKeyHandler
return; return;
} }
} }
$this->logger->logger('Accepting rekeying of secret chat ' . $chat . '...', \danog\MadelineProto\Logger::VERBOSE); $this->logger->logger('Accepting rekeying of secret chat '.$chat.'...', \danog\MadelineProto\Logger::VERBOSE);
$dh_config = (yield from $this->getDhConfig()); $dh_config = (yield from $this->getDhConfig());
$this->logger->logger('Generating b...', \danog\MadelineProto\Logger::VERBOSE); $this->logger->logger('Generating b...', \danog\MadelineProto\Logger::VERBOSE);
$b = new \tgseclib\Math\BigInteger(\danog\MadelineProto\Tools::random(256), 256); $b = new \tgseclib\Math\BigInteger(\danog\MadelineProto\Tools::random(256), 256);
@ -219,7 +219,7 @@ trait AuthKeyHandler
$this->secret_chats[$chat]['rekeying'] = [0]; $this->secret_chats[$chat]['rekeying'] = [0];
return; return;
} }
$this->logger->logger('Committing rekeying of secret chat ' . $chat . '...', \danog\MadelineProto\Logger::VERBOSE); $this->logger->logger('Committing rekeying of secret chat '.$chat.'...', \danog\MadelineProto\Logger::VERBOSE);
$dh_config = (yield from $this->getDhConfig()); $dh_config = (yield from $this->getDhConfig());
$params['g_b'] = new \tgseclib\Math\BigInteger((string) $params['g_b'], 256); $params['g_b'] = new \tgseclib\Math\BigInteger((string) $params['g_b'], 256);
$this->checkG($params['g_b'], $dh_config['p']); $this->checkG($params['g_b'], $dh_config['p']);
@ -257,7 +257,7 @@ trait AuthKeyHandler
yield from $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionAbortKey', 'exchange_id' => $params['exchange_id']]]], ['datacenter' => $this->datacenter->curdc]); yield from $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionAbortKey', 'exchange_id' => $params['exchange_id']]]], ['datacenter' => $this->datacenter->curdc]);
throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!'); throw new \danog\MadelineProto\SecurityException('Invalid key fingerprint!');
} }
$this->logger->logger('Completing rekeying of secret chat ' . $chat . '...', \danog\MadelineProto\Logger::VERBOSE); $this->logger->logger('Completing rekeying of secret chat '.$chat.'...', \danog\MadelineProto\Logger::VERBOSE);
$this->secret_chats[$chat]['rekeying'] = [0]; $this->secret_chats[$chat]['rekeying'] = [0];
$this->secret_chats[$chat]['old_key'] = $this->secret_chats[$chat]['key']; $this->secret_chats[$chat]['old_key'] = $this->secret_chats[$chat]['key'];
$this->secret_chats[$chat]['key'] = $this->temp_rekeyed_secret_chats[$params['exchange_id']]; $this->secret_chats[$chat]['key'] = $this->temp_rekeyed_secret_chats[$params['exchange_id']];
@ -265,7 +265,7 @@ trait AuthKeyHandler
$this->secret_chats[$chat]['updated'] = \time(); $this->secret_chats[$chat]['updated'] = \time();
unset($this->temp_rekeyed_secret_chats[$params['exchange_id']]); unset($this->temp_rekeyed_secret_chats[$params['exchange_id']]);
yield from $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionNoop']]], ['datacenter' => $this->datacenter->curdc]); yield from $this->methodCallAsyncRead('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionNoop']]], ['datacenter' => $this->datacenter->curdc]);
$this->logger->logger('Secret chat ' . $chat . ' rekeyed successfully!', \danog\MadelineProto\Logger::VERBOSE); $this->logger->logger('Secret chat '.$chat.' rekeyed successfully!', \danog\MadelineProto\Logger::VERBOSE);
return true; return true;
} }
/** /**
@ -316,7 +316,7 @@ trait AuthKeyHandler
*/ */
public function discardSecretChat(int $chat): \Generator public function discardSecretChat(int $chat): \Generator
{ {
$this->logger->logger('Discarding secret chat ' . $chat . '...', \danog\MadelineProto\Logger::VERBOSE); $this->logger->logger('Discarding secret chat '.$chat.'...', \danog\MadelineProto\Logger::VERBOSE);
if (isset($this->secret_chats[$chat])) { if (isset($this->secret_chats[$chat])) {
unset($this->secret_chats[$chat]); unset($this->secret_chats[$chat]);
} }

View File

@ -19,6 +19,8 @@
namespace danog\MadelineProto\SecretChats; namespace danog\MadelineProto\SecretChats;
use danog\MadelineProto\MTProtoTools\Crypt;
/** /**
* Manages packing and unpacking of messages, and the list of sent and received messages. * Manages packing and unpacking of messages, and the list of sent and received messages.
*/ */
@ -51,21 +53,21 @@ trait MessageHandler
} }
$this->secret_chats[$chat_id]['outgoing'][$this->secret_chats[$chat_id]['out_seq_no']] = $message; $this->secret_chats[$chat_id]['outgoing'][$this->secret_chats[$chat_id]['out_seq_no']] = $message;
$message = (yield from $this->TL->serializeObject(['type' => $constructor = $this->secret_chats[$chat_id]['layer'] === 8 ? 'DecryptedMessage' : 'DecryptedMessageLayer'], $message, $constructor, $this->secret_chats[$chat_id]['layer'])); $message = (yield from $this->TL->serializeObject(['type' => $constructor = $this->secret_chats[$chat_id]['layer'] === 8 ? 'DecryptedMessage' : 'DecryptedMessageLayer'], $message, $constructor, $this->secret_chats[$chat_id]['layer']));
$message = \danog\MadelineProto\Tools::packUnsignedInt(\strlen($message)) . $message; $message = \danog\MadelineProto\Tools::packUnsignedInt(\strlen($message)).$message;
if ($this->secret_chats[$chat_id]['mtproto'] === 2) { if ($this->secret_chats[$chat_id]['mtproto'] === 2) {
$padding = \danog\MadelineProto\Tools::posmod(-\strlen($message), 16); $padding = \danog\MadelineProto\Tools::posmod(-\strlen($message), 16);
if ($padding < 12) { if ($padding < 12) {
$padding += 16; $padding += 16;
} }
$message .= \danog\MadelineProto\Tools::random($padding); $message .= \danog\MadelineProto\Tools::random($padding);
$message_key = \substr(\hash('sha256', \substr($this->secret_chats[$chat_id]['key']['auth_key'], 88 + ($this->secret_chats[$chat_id]['admin'] ? 0 : 8), 32) . $message, true), 8, 16); $message_key = \substr(\hash('sha256', \substr($this->secret_chats[$chat_id]['key']['auth_key'], 88 + ($this->secret_chats[$chat_id]['admin'] ? 0 : 8), 32).$message, true), 8, 16);
list($aes_key, $aes_iv) = $this->aesCalculate($message_key, $this->secret_chats[$chat_id]['key']['auth_key'], $this->secret_chats[$chat_id]['admin']); list($aes_key, $aes_iv) = Crypt::aesCalculate($message_key, $this->secret_chats[$chat_id]['key']['auth_key'], $this->secret_chats[$chat_id]['admin']);
} else { } else {
$message_key = \substr(\sha1($message, true), -16); $message_key = \substr(\sha1($message, true), -16);
list($aes_key, $aes_iv) = $this->oldAesCalculate($message_key, $this->secret_chats[$chat_id]['key']['auth_key'], true); list($aes_key, $aes_iv) = Crypt::oldAesCalculate($message_key, $this->secret_chats[$chat_id]['key']['auth_key'], true);
$message .= \danog\MadelineProto\Tools::random(\danog\MadelineProto\Tools::posmod(-\strlen($message), 16)); $message .= \danog\MadelineProto\Tools::random(\danog\MadelineProto\Tools::posmod(-\strlen($message), 16));
} }
$message = $this->secret_chats[$chat_id]['key']['fingerprint'] . $message_key . $this->igeEncrypt($message, $aes_key, $aes_iv); $message = $this->secret_chats[$chat_id]['key']['fingerprint'].$message_key.Crypt::igeEncrypt($message, $aes_key, $aes_iv);
return $message; return $message;
} }
private function handleEncryptedUpdate(array $message): \Generator private function handleEncryptedUpdate(array $message): \Generator
@ -91,25 +93,25 @@ trait MessageHandler
$message_key = \substr($message['message']['bytes'], 8, 16); $message_key = \substr($message['message']['bytes'], 8, 16);
$encrypted_data = \substr($message['message']['bytes'], 24); $encrypted_data = \substr($message['message']['bytes'], 24);
if ($this->secret_chats[$message['message']['chat_id']]['mtproto'] === 2) { if ($this->secret_chats[$message['message']['chat_id']]['mtproto'] === 2) {
$this->logger->logger('Trying MTProto v2 decryption for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE); $this->logger->logger('Trying MTProto v2 decryption for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE);
try { try {
$message_data = $this->tryMTProtoV2Decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data); $message_data = $this->tryMTProtoV2Decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data);
$this->logger->logger('MTProto v2 decryption OK for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE); $this->logger->logger('MTProto v2 decryption OK for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE);
} catch (\danog\MadelineProto\SecurityException $e) { } catch (\danog\MadelineProto\SecurityException $e) {
$this->logger->logger('MTProto v2 decryption failed with message ' . $e->getMessage() . ', trying MTProto v1 decryption for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE); $this->logger->logger('MTProto v2 decryption failed with message '.$e->getMessage().', trying MTProto v1 decryption for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE);
$message_data = $this->tryMTProtoV1Decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data); $message_data = $this->tryMTProtoV1Decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data);
$this->logger->logger('MTProto v1 decryption OK for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE); $this->logger->logger('MTProto v1 decryption OK for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE);
$this->secret_chats[$message['message']['chat_id']]['mtproto'] = 1; $this->secret_chats[$message['message']['chat_id']]['mtproto'] = 1;
} }
} else { } else {
$this->logger->logger('Trying MTProto v1 decryption for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE); $this->logger->logger('Trying MTProto v1 decryption for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE);
try { try {
$message_data = $this->tryMTProtoV1Decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data); $message_data = $this->tryMTProtoV1Decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data);
$this->logger->logger('MTProto v1 decryption OK for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE); $this->logger->logger('MTProto v1 decryption OK for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE);
} catch (\danog\MadelineProto\SecurityException $e) { } catch (\danog\MadelineProto\SecurityException $e) {
$this->logger->logger('MTProto v1 decryption failed with message ' . $e->getMessage() . ', trying MTProto v2 decryption for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE); $this->logger->logger('MTProto v1 decryption failed with message '.$e->getMessage().', trying MTProto v2 decryption for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE);
$message_data = $this->tryMTProtoV2Decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data); $message_data = $this->tryMTProtoV2Decrypt($message_key, $message['message']['chat_id'], $old, $encrypted_data);
$this->logger->logger('MTProto v2 decryption OK for chat ' . $message['message']['chat_id'] . '...', \danog\MadelineProto\Logger::NOTICE); $this->logger->logger('MTProto v2 decryption OK for chat '.$message['message']['chat_id'].'...', \danog\MadelineProto\Logger::NOTICE);
$this->secret_chats[$message['message']['chat_id']]['mtproto'] = 2; $this->secret_chats[$message['message']['chat_id']]['mtproto'] = 2;
} }
} }
@ -125,8 +127,8 @@ trait MessageHandler
} }
private function tryMTProtoV1Decrypt($message_key, $chat_id, $old, $encrypted_data) private function tryMTProtoV1Decrypt($message_key, $chat_id, $old, $encrypted_data)
{ {
list($aes_key, $aes_iv) = $this->oldAesCalculate($message_key, $this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], true); list($aes_key, $aes_iv) = Crypt::oldAesCalculate($message_key, $this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], true);
$decrypted_data = $this->igeDecrypt($encrypted_data, $aes_key, $aes_iv); $decrypted_data = Crypt::igeDecrypt($encrypted_data, $aes_key, $aes_iv);
$message_data_length = \unpack('V', \substr($decrypted_data, 0, 4))[1]; $message_data_length = \unpack('V', \substr($decrypted_data, 0, 4))[1];
$message_data = \substr($decrypted_data, 4, $message_data_length); $message_data = \substr($decrypted_data, 4, $message_data_length);
if ($message_data_length > \strlen($decrypted_data)) { if ($message_data_length > \strlen($decrypted_data)) {
@ -145,14 +147,14 @@ trait MessageHandler
} }
private function tryMTProtoV2Decrypt($message_key, $chat_id, $old, $encrypted_data) private function tryMTProtoV2Decrypt($message_key, $chat_id, $old, $encrypted_data)
{ {
list($aes_key, $aes_iv) = $this->aesCalculate($message_key, $this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], !$this->secret_chats[$chat_id]['admin']); list($aes_key, $aes_iv) = Crypt::aesCalculate($message_key, $this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], !$this->secret_chats[$chat_id]['admin']);
$decrypted_data = $this->igeDecrypt($encrypted_data, $aes_key, $aes_iv); $decrypted_data = Crypt::igeDecrypt($encrypted_data, $aes_key, $aes_iv);
$message_data_length = \unpack('V', \substr($decrypted_data, 0, 4))[1]; $message_data_length = \unpack('V', \substr($decrypted_data, 0, 4))[1];
$message_data = \substr($decrypted_data, 4, $message_data_length); $message_data = \substr($decrypted_data, 4, $message_data_length);
if ($message_data_length > \strlen($decrypted_data)) { if ($message_data_length > \strlen($decrypted_data)) {
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_data_length_too_big']); throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_data_length_too_big']);
} }
if ($message_key != \substr(\hash('sha256', \substr($this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], 88 + ($this->secret_chats[$chat_id]['admin'] ? 8 : 0), 32) . $decrypted_data, true), 8, 16)) { if ($message_key != \substr(\hash('sha256', \substr($this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], 88 + ($this->secret_chats[$chat_id]['admin'] ? 8 : 0), 32).$decrypted_data, true), 8, 16)) {
throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_key_mismatch']); throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['msg_key_mismatch']);
} }
if (\strlen($decrypted_data) - 4 - $message_data_length < 12) { if (\strlen($decrypted_data) - 4 - $message_data_length < 12) {

View File

@ -62,7 +62,7 @@ trait ResponseHandler
$update['message']['decrypted_message']['action']['end_seq_no'] -= $this->secret_chats[$update['message']['chat_id']]['out_seq_no_x']; $update['message']['decrypted_message']['action']['end_seq_no'] -= $this->secret_chats[$update['message']['chat_id']]['out_seq_no_x'];
$update['message']['decrypted_message']['action']['start_seq_no'] /= 2; $update['message']['decrypted_message']['action']['start_seq_no'] /= 2;
$update['message']['decrypted_message']['action']['end_seq_no'] /= 2; $update['message']['decrypted_message']['action']['end_seq_no'] /= 2;
$this->logger->logger('Resending messages for secret chat ' . $update['message']['chat_id'], \danog\MadelineProto\Logger::WARNING); $this->logger->logger('Resending messages for secret chat '.$update['message']['chat_id'], \danog\MadelineProto\Logger::WARNING);
foreach ($this->secret_chats[$update['message']['chat_id']]['outgoing'] as $seq => $message) { foreach ($this->secret_chats[$update['message']['chat_id']]['outgoing'] as $seq => $message) {
if ($seq >= $update['message']['decrypted_message']['action']['start_seq_no'] && $seq <= $update['message']['decrypted_message']['action']['end_seq_no']) { if ($seq >= $update['message']['decrypted_message']['action']['start_seq_no'] && $seq <= $update['message']['decrypted_message']['action']['end_seq_no']) {
//throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['resending_unsupported']); //throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['resending_unsupported']);
@ -92,7 +92,7 @@ trait ResponseHandler
} }
break; break;
default: default:
throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['unrecognized_dec_msg'] . \var_export($update, true)); throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['unrecognized_dec_msg'].\var_export($update, true));
break; break;
} }
} }

View File

@ -51,7 +51,7 @@ trait SeqNoHandler
if (isset($message['decrypted_message']['out_seq_no']) && $C < $this->secret_chats[$chat_id]['in_seq_no']) { if (isset($message['decrypted_message']['out_seq_no']) && $C < $this->secret_chats[$chat_id]['in_seq_no']) {
if (($message['decrypted_message']['out_seq_no'] - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2 !== $C) { if (($message['decrypted_message']['out_seq_no'] - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2 !== $C) {
yield from $this->discardSecretChat($chat_id); yield from $this->discardSecretChat($chat_id);
throw new \danog\MadelineProto\SecurityException('out_seq_no hole: should be ' . $C . ', is ' . ($message['decrypted_message']['out_seq_no'] - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2); throw new \danog\MadelineProto\SecurityException('out_seq_no hole: should be '.$C.', is '.($message['decrypted_message']['out_seq_no'] - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2);
} }
$C++; $C++;
} }
@ -59,13 +59,13 @@ trait SeqNoHandler
//$this->logger->logger($C, $seqno); //$this->logger->logger($C, $seqno);
if ($seqno < $C) { if ($seqno < $C) {
// <= C // <= C
$this->logger->logger('WARNING: dropping repeated message with seqno ' . $seqno); $this->logger->logger('WARNING: dropping repeated message with seqno '.$seqno);
return false; return false;
} }
if ($seqno > $C) { if ($seqno > $C) {
// > C+1 // > C+1
yield from $this->discardSecretChat($chat_id); yield from $this->discardSecretChat($chat_id);
throw new \danog\MadelineProto\SecurityException('WARNING: out_seq_no gap detected (' . $seqno . ' > ' . $C . ')!'); throw new \danog\MadelineProto\SecurityException('WARNING: out_seq_no gap detected ('.$seqno.' > '.$C.')!');
} }
return true; return true;
} }

View File

@ -42,7 +42,7 @@ class Serialization
*/ */
public static function realpaths(string $file): array public static function realpaths(string $file): array
{ {
$file = Absolute::absolute($file); $file = Tools::absolute($file);
return ['file' => $file, 'lockfile' => $file.'.lock', 'tempfile' => $file.'.temp.session']; return ['file' => $file, 'lockfile' => $file.'.lock', 'tempfile' => $file.'.temp.session'];
} }
/** /**
@ -80,7 +80,7 @@ class Serialization
if ($e->getFile() === 'MadelineProto' && $e->getLine() === 1) { if ($e->getFile() === 'MadelineProto' && $e->getLine() === 1) {
throw $e; throw $e;
} }
if (\constant("MADELINEPROTO_TEST") === 'pony') { if (@\constant("MADELINEPROTO_TEST") === 'pony') {
throw $e; throw $e;
} }
\class_exists('\\Volatile'); \class_exists('\\Volatile');

View File

@ -266,7 +266,7 @@ class HashedBufferedStream implements BufferedProxyStreamInterface, BufferInterf
throw new \danog\MadelineProto\Exception('Too much out of frame data was sent, cannot check hash'); throw new \danog\MadelineProto\Exception('Too much out of frame data was sent, cannot check hash');
} }
\hash_update($this->write_hash, $data); \hash_update($this->write_hash, $data);
return $this->write_buffer->bufferWrite($data . $this->getWriteHash()); return $this->write_buffer->bufferWrite($data.$this->getWriteHash());
} }
if ($this->write_check_after) { if ($this->write_check_after) {
$this->write_check_pos += $length; $this->write_check_pos += $length;

View File

@ -45,7 +45,7 @@ class AbridgedStream implements BufferedStreamInterface, MTProtoBufferInterface
*/ */
public function connect(ConnectionContext $ctx, string $header = ''): \Generator public function connect(ConnectionContext $ctx, string $header = ''): \Generator
{ {
$this->stream = (yield from $ctx->getStream(\chr(239) . $header)); $this->stream = (yield from $ctx->getStream(\chr(239).$header));
} }
/** /**
* Async close. * Async close.
@ -69,7 +69,7 @@ class AbridgedStream implements BufferedStreamInterface, MTProtoBufferInterface
if ($length < 127) { if ($length < 127) {
$message = \chr($length); $message = \chr($length);
} else { } else {
$message = \chr(127) . \substr(\pack('V', $length), 0, 3); $message = \chr(127).\substr(\pack('V', $length), 0, 3);
} }
$buffer = yield $this->stream->getWriteBuffer(\strlen($message) + $length, $append); $buffer = yield $this->stream->getWriteBuffer(\strlen($message) + $length, $append);
yield $buffer->bufferWrite($message); yield $buffer->bufferWrite($message);
@ -87,7 +87,7 @@ class AbridgedStream implements BufferedStreamInterface, MTProtoBufferInterface
$buffer = yield $this->stream->getReadBuffer($l); $buffer = yield $this->stream->getReadBuffer($l);
$length = \ord(yield $buffer->bufferRead(1)); $length = \ord(yield $buffer->bufferRead(1));
if ($length >= 127) { if ($length >= 127) {
$length = \unpack('V', (yield $buffer->bufferRead(3)) . "\0")[1]; $length = \unpack('V', (yield $buffer->bufferRead(3))."\0")[1];
} }
$length <<= 2; $length <<= 2;
return $buffer; return $buffer;

View File

@ -68,7 +68,7 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface
public function setExtra($extra) public function setExtra($extra)
{ {
if (isset($extra['user']) && isset($extra['password'])) { if (isset($extra['user']) && isset($extra['password'])) {
$this->header = \base64_encode($extra['user'] . ':' . $extra['password']) . "\r\n"; $this->header = \base64_encode($extra['user'].':'.$extra['password'])."\r\n";
} }
} }
/** /**
@ -89,7 +89,7 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface
*/ */
public function getWriteBufferGenerator(int $length, string $append = ''): \Generator public function getWriteBufferGenerator(int $length, string $append = ''): \Generator
{ {
$headers = 'POST ' . $this->uri->getPath() . " HTTP/1.1\r\nHost: " . $this->uri->getHost() . ':' . $this->uri->getPort() . "\r\n" . "Content-Type: application/x-www-form-urlencoded\r\nConnection: keep-alive\r\nKeep-Alive: timeout=100000, max=10000000\r\nContent-Length: " . $length . $this->header . "\r\n\r\n"; $headers = 'POST '.$this->uri->getPath()." HTTP/1.1\r\nHost: ".$this->uri->getHost().':'.$this->uri->getPort()."\r\n"."Content-Type: application/x-www-form-urlencoded\r\nConnection: keep-alive\r\nKeep-Alive: timeout=100000, max=10000000\r\nContent-Length: ".$length.$this->header."\r\n\r\n";
$buffer = yield $this->stream->getWriteBuffer(\strlen($headers) + $length, $append); $buffer = yield $this->stream->getWriteBuffer(\strlen($headers) + $length, $append);
yield $buffer->bufferWrite($headers); yield $buffer->bufferWrite($headers);
return $buffer; return $buffer;
@ -127,7 +127,7 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface
} }
$code = (int) $code; $code = (int) $code;
unset($headers[0]); unset($headers[0]);
if (\array_pop($headers) . \array_pop($headers) !== '') { if (\array_pop($headers).\array_pop($headers) !== '') {
throw new \danog\MadelineProto\Exception('Wrong last header'); throw new \danog\MadelineProto\Exception('Wrong last header');
} }
foreach ($headers as $key => $current_header) { foreach ($headers as $key => $current_header) {

View File

@ -47,7 +47,7 @@ class IntermediatePaddedStream implements BufferedStreamInterface, MTProtoBuffer
*/ */
public function connect(ConnectionContext $ctx, string $header = ''): \Generator public function connect(ConnectionContext $ctx, string $header = ''): \Generator
{ {
$this->stream = (yield from $ctx->getStream(\str_repeat(\chr(221), 4) . $header)); $this->stream = (yield from $ctx->getStream(\str_repeat(\chr(221), 4).$header));
} }
/** /**
* Async close. * Async close.
@ -68,7 +68,7 @@ class IntermediatePaddedStream implements BufferedStreamInterface, MTProtoBuffer
public function getWriteBufferGenerator(int $length, string $append = ''): \Generator public function getWriteBufferGenerator(int $length, string $append = ''): \Generator
{ {
$padding_length = \danog\MadelineProto\Tools::randomInt($modulus = 16); $padding_length = \danog\MadelineProto\Tools::randomInt($modulus = 16);
$buffer = yield $this->stream->getWriteBuffer(4 + $length + $padding_length, $append . \danog\MadelineProto\Tools::random($padding_length)); $buffer = yield $this->stream->getWriteBuffer(4 + $length + $padding_length, $append.\danog\MadelineProto\Tools::random($padding_length));
yield $buffer->bufferWrite(\pack('V', $padding_length + $length)); yield $buffer->bufferWrite(\pack('V', $padding_length + $length));
return $buffer; return $buffer;
} }

View File

@ -47,7 +47,7 @@ class IntermediateStream implements BufferedStreamInterface, MTProtoBufferInterf
*/ */
public function connect(ConnectionContext $ctx, string $header = ''): \Generator public function connect(ConnectionContext $ctx, string $header = ''): \Generator
{ {
$this->stream = (yield from $ctx->getStream(\str_repeat(\chr(238), 4) . $header)); $this->stream = (yield from $ctx->getStream(\str_repeat(\chr(238), 4).$header));
} }
/** /**
* Async close. * Async close.

View File

@ -52,17 +52,17 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
if ($secure) { if ($secure) {
$ctx->setSocketContext($ctx->getSocketContext()->withTlsContext(new ClientTlsContext($uri->getHost()))); $ctx->setSocketContext($ctx->getSocketContext()->withTlsContext(new ClientTlsContext($uri->getHost())));
} }
$ctx->setUri('tcp://' . $this->extra['address'] . ':' . $this->extra['port'])->secure(false); $ctx->setUri('tcp://'.$this->extra['address'].':'.$this->extra['port'])->secure(false);
$this->stream = (yield from $ctx->getStream()); $this->stream = (yield from $ctx->getStream());
$address = $uri->getHost(); $address = $uri->getHost();
$port = $uri->getPort(); $port = $uri->getPort();
try { try {
if (\strlen(\inet_pton($address) === 16)) { if (\strlen(\inet_pton($address) === 16)) {
$address = '[' . $address . ']'; $address = '['.$address.']';
} }
} catch (\danog\MadelineProto\Exception $e) { } catch (\danog\MadelineProto\Exception $e) {
} }
yield $this->stream->write("CONNECT {$address}:{$port} HTTP/1.1\r\nHost: {$address}:{$port}\r\nAccept: */*\r\n" . $this->getProxyAuthHeader() . "Connection: keep-Alive\r\n\r\n"); yield $this->stream->write("CONNECT {$address}:{$port} HTTP/1.1\r\nHost: {$address}:{$port}\r\nAccept: */*\r\n".$this->getProxyAuthHeader()."Connection: keep-Alive\r\n\r\n");
$buffer = yield $this->stream->getReadBuffer($l); $buffer = yield $this->stream->getReadBuffer($l);
$headers = ''; $headers = '';
$was_crlf = false; $was_crlf = false;
@ -87,7 +87,7 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
} }
$code = (int) $code; $code = (int) $code;
unset($headers[0]); unset($headers[0]);
if (\array_pop($headers) . \array_pop($headers) !== '') { if (\array_pop($headers).\array_pop($headers) !== '') {
throw new \danog\MadelineProto\Exception('Wrong last header'); throw new \danog\MadelineProto\Exception('Wrong last header');
} }
foreach ($headers as $key => $current_header) { foreach ($headers as $key => $current_header) {
@ -122,7 +122,7 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
if ($secure) { if ($secure) {
yield $this->getSocket()->setupTls(); yield $this->getSocket()->setupTls();
} }
\danog\MadelineProto\Logger::log('Connected to ' . $address . ':' . $port . ' via http'); \danog\MadelineProto\Logger::log('Connected to '.$address.':'.$port.' via http');
if (\strlen($header)) { if (\strlen($header)) {
yield (yield $this->stream->getWriteBuffer(\strlen($header)))->bufferWrite($header); yield (yield $this->stream->getWriteBuffer(\strlen($header)))->bufferWrite($header);
} }
@ -171,7 +171,7 @@ class HttpProxy implements RawProxyStreamInterface, BufferedProxyStreamInterface
if (!isset($this->extra['username']) || !isset($this->extra['password'])) { if (!isset($this->extra['username']) || !isset($this->extra['password'])) {
return ''; return '';
} }
return 'Proxy-Authorization: Basic ' . \base64_encode($this->extra['username'] . ':' . $this->extra['password']) . "\r\n"; return 'Proxy-Authorization: Basic '.\base64_encode($this->extra['username'].':'.$this->extra['password'])."\r\n";
} }
/** /**
* Sets proxy data. * Sets proxy data.

View File

@ -53,12 +53,12 @@ class SocksProxy implements RawProxyStreamInterface, BufferedProxyStreamInterfac
if ($secure) { if ($secure) {
$ctx->setSocketContext($ctx->getSocketContext()->withTlsContext(new ClientTlsContext($uri->getHost()))); $ctx->setSocketContext($ctx->getSocketContext()->withTlsContext(new ClientTlsContext($uri->getHost())));
} }
$ctx->setUri('tcp://' . $this->extra['address'] . ':' . $this->extra['port'])->secure(false); $ctx->setUri('tcp://'.$this->extra['address'].':'.$this->extra['port'])->secure(false);
$methods = \chr(0); $methods = \chr(0);
if (isset($this->extra['username']) && isset($this->extra['password'])) { if (isset($this->extra['username']) && isset($this->extra['password'])) {
$methods .= \chr(2); $methods .= \chr(2);
} }
$this->stream = (yield from $ctx->getStream(\chr(5) . \chr(\strlen($methods)) . $methods)); $this->stream = (yield from $ctx->getStream(\chr(5).\chr(\strlen($methods)).$methods));
$l = 2; $l = 2;
$buffer = yield $this->stream->getReadBuffer($l); $buffer = yield $this->stream->getReadBuffer($l);
$version = \ord(yield $buffer->bufferRead(1)); $version = \ord(yield $buffer->bufferRead(1));
@ -67,7 +67,7 @@ class SocksProxy implements RawProxyStreamInterface, BufferedProxyStreamInterfac
throw new \danog\MadelineProto\Exception("Wrong SOCKS5 version: {$version}"); throw new \danog\MadelineProto\Exception("Wrong SOCKS5 version: {$version}");
} }
if ($method === 2) { if ($method === 2) {
$auth = \chr(1) . \chr(\strlen($this->extra['username'])) . $this->extra['username'] . \chr(\strlen($this->extra['password'])) . $this->extra['password']; $auth = \chr(1).\chr(\strlen($this->extra['username'])).$this->extra['username'].\chr(\strlen($this->extra['password'])).$this->extra['password'];
yield $this->stream->write($auth); yield $this->stream->write($auth);
$buffer = yield $this->stream->getReadBuffer($l); $buffer = yield $this->stream->getReadBuffer($l);
$version = \ord(yield $buffer->bufferRead(1)); $version = \ord(yield $buffer->bufferRead(1));
@ -84,9 +84,9 @@ class SocksProxy implements RawProxyStreamInterface, BufferedProxyStreamInterfac
$payload = \pack('C3', 0x5, 0x1, 0x0); $payload = \pack('C3', 0x5, 0x1, 0x0);
try { try {
$ip = \inet_pton($uri->getHost()); $ip = \inet_pton($uri->getHost());
$payload .= $ip ? \pack('C1', \strlen($ip) === 4 ? 0x1 : 0x4) . $ip : \pack('C2', 0x3, \strlen($uri->getHost())) . $uri->getHost(); $payload .= $ip ? \pack('C1', \strlen($ip) === 4 ? 0x1 : 0x4).$ip : \pack('C2', 0x3, \strlen($uri->getHost())).$uri->getHost();
} catch (\danog\MadelineProto\Exception $e) { } catch (\danog\MadelineProto\Exception $e) {
$payload .= \pack('C2', 0x3, \strlen($uri->getHost())) . $uri->getHost(); $payload .= \pack('C2', 0x3, \strlen($uri->getHost())).$uri->getHost();
} }
$payload .= \pack('n', $uri->getPort()); $payload .= \pack('n', $uri->getPort());
yield $this->stream->write($payload); yield $this->stream->write($payload);
@ -126,7 +126,7 @@ class SocksProxy implements RawProxyStreamInterface, BufferedProxyStreamInterfac
$l = 2; $l = 2;
$buffer = yield $this->stream->getReadBuffer($l); $buffer = yield $this->stream->getReadBuffer($l);
$port = \unpack('n', yield $buffer->bufferRead(2))[1]; $port = \unpack('n', yield $buffer->bufferRead(2))[1];
\danog\MadelineProto\Logger::log(['Connected to ' . $ip . ':' . $port . ' via socks5']); \danog\MadelineProto\Logger::log(['Connected to '.$ip.':'.$port.' via socks5']);
if ($secure) { if ($secure) {
yield $this->getSocket()->setupTls(); yield $this->getSocket()->setupTls();
} }

View File

@ -111,7 +111,7 @@ class DefaultStream implements RawStreamInterface, ProxyStreamInterface
$this->stream = null; $this->stream = null;
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
\danog\MadelineProto\Logger::log('Got exception while closing stream: ' . $e->getMessage()); \danog\MadelineProto\Logger::log('Got exception while closing stream: '.$e->getMessage());
} }
} }
/** /**

View File

@ -94,7 +94,7 @@ class PremadeStream implements RawStreamInterface, ProxyStreamInterface
$this->stream = null; $this->stream = null;
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
\danog\MadelineProto\Logger::log('Got exception while closing stream: ' . $e->getMessage()); \danog\MadelineProto\Logger::log('Got exception while closing stream: '.$e->getMessage());
} }
} }
public function close() public function close()

View File

@ -24,9 +24,9 @@ class Exception extends \Exception
use \danog\MadelineProto\TL\PrettyException; use \danog\MadelineProto\TL\PrettyException;
public function __toString() public function __toString()
{ {
$result = \get_class($this) . ($this->message !== '' ? ': ' : '') . $this->message . PHP_EOL . \danog\MadelineProto\Magic::$revision . PHP_EOL . 'TL Trace (YOU ABSOLUTELY MUST READ THE TEXT BELOW):' . PHP_EOL . PHP_EOL . $this->getTLTrace() . PHP_EOL; $result = \get_class($this).($this->message !== '' ? ': ' : '').$this->message.PHP_EOL.\danog\MadelineProto\Magic::$revision.PHP_EOL.'TL Trace (YOU ABSOLUTELY MUST READ THE TEXT BELOW):'.PHP_EOL.PHP_EOL.$this->getTLTrace().PHP_EOL;
if (PHP_SAPI !== 'cli') { if (PHP_SAPI !== 'cli') {
$result = \str_replace(PHP_EOL, '<br>' . PHP_EOL, $result); $result = \str_replace(PHP_EOL, '<br>'.PHP_EOL, $result);
} }
return $result; return $result;
} }

View File

@ -48,7 +48,7 @@ trait Extension
{ {
foreach (self::ALL_MIMES as $key => $value) { foreach (self::ALL_MIMES as $key => $value) {
if (\array_search($mime, $value) !== false) { if (\array_search($mime, $value) !== false) {
return '.' . $key; return '.'.$key;
} }
} }
return ''; return '';

View File

@ -137,7 +137,7 @@ trait TD
if (isset($params['fwd_from'])) { if (isset($params['fwd_from'])) {
$newparams[$td] = ['_' => 'messageForwardedFromUser']; $newparams[$td] = ['_' => 'messageForwardedFromUser'];
if (isset($params['fwd_from']['channel_id'])) { if (isset($params['fwd_from']['channel_id'])) {
$newparams[$td] = ['_' => 'messageForwardedPost', 'chat_id' => '-100' . $params['fwd_from']['channel_id']]; $newparams[$td] = ['_' => 'messageForwardedPost', 'chat_id' => '-100'.$params['fwd_from']['channel_id']];
} }
$newparams[$td]['date'] = $params['fwd_from']['date']; $newparams[$td]['date'] = $params['fwd_from']['date'];
if (isset($params['fwd_from']['channel_post'])) { if (isset($params['fwd_from']['channel_post'])) {
@ -201,7 +201,7 @@ trait TD
$newparams['ID'] = \ucfirst($value); $newparams['ID'] = \ucfirst($value);
} else { } else {
if (!\is_numeric($key) && !\preg_match('/_^/', $key)) { if (!\is_numeric($key) && !\preg_match('/_^/', $key)) {
$key = $key . '_'; $key = $key.'_';
} }
$newparams[$key] = $this->tdToTdcli($value); $newparams[$key] = $this->tdToTdcli($value);
} }

View File

@ -24,9 +24,9 @@ class Exception extends \Exception
use PrettyException; use PrettyException;
public function __toString() public function __toString()
{ {
$result = \get_class($this) . ($this->message !== '' ? ': ' : '') . $this->message . PHP_EOL . \danog\MadelineProto\Magic::$revision . PHP_EOL . 'TL Trace (YOU ABSOLUTELY MUST READ THE TEXT BELOW):' . PHP_EOL . PHP_EOL . $this->getTLTrace() . PHP_EOL; $result = \get_class($this).($this->message !== '' ? ': ' : '').$this->message.PHP_EOL.\danog\MadelineProto\Magic::$revision.PHP_EOL.'TL Trace (YOU ABSOLUTELY MUST READ THE TEXT BELOW):'.PHP_EOL.PHP_EOL.$this->getTLTrace().PHP_EOL;
if (PHP_SAPI !== 'cli') { if (PHP_SAPI !== 'cli') {
$result = \str_replace(PHP_EOL, '<br>' . PHP_EOL, $result); $result = \str_replace(PHP_EOL, '<br>'.PHP_EOL, $result);
} }
return $result; return $result;
} }

View File

@ -80,13 +80,13 @@ trait PrettyException
$this->tl_trace = ''; $this->tl_trace = '';
$eol = PHP_EOL; $eol = PHP_EOL;
if (PHP_SAPI !== 'cli') { if (PHP_SAPI !== 'cli') {
$eol = '<br>' . PHP_EOL; $eol = '<br>'.PHP_EOL;
} }
$tl = false; $tl = false;
foreach (\array_reverse($trace ?? $this->getTrace()) as $k => $frame) { foreach (\array_reverse($trace ?? $this->getTrace()) as $k => $frame) {
if (isset($frame['function']) && \in_array($frame['function'], ['serializeParams', 'serializeObject'])) { if (isset($frame['function']) && \in_array($frame['function'], ['serializeParams', 'serializeObject'])) {
if (($frame['args'][2] ?? '') !== '') { if (($frame['args'][2] ?? '') !== '') {
$this->tl_trace .= $tl ? "['" . $frame['args'][2] . "']" : "While serializing: \t" . $frame['args'][2]; $this->tl_trace .= $tl ? "['".$frame['args'][2]."']" : "While serializing: \t".$frame['args'][2];
$tl = true; $tl = true;
} }
} else { } else {
@ -96,18 +96,18 @@ trait PrettyException
if (isset($frame['function']) && ($frame['function'] === 'handle_rpc_error' && $k === \count($this->getTrace()) - 1) || $frame['function'] === 'unserialize') { if (isset($frame['function']) && ($frame['function'] === 'handle_rpc_error' && $k === \count($this->getTrace()) - 1) || $frame['function'] === 'unserialize') {
continue; continue;
} }
$this->tl_trace .= isset($frame['file']) ? \str_pad(\basename($frame['file']) . '(' . $frame['line'] . '):', 20) . "\t" : ''; $this->tl_trace .= isset($frame['file']) ? \str_pad(\basename($frame['file']).'('.$frame['line'].'):', 20)."\t" : '';
$this->tl_trace .= isset($frame['function']) ? $frame['function'] . '(' : ''; $this->tl_trace .= isset($frame['function']) ? $frame['function'].'(' : '';
$this->tl_trace .= isset($frame['args']) ? \substr(\json_encode($frame['args']), 1, -1) : ''; $this->tl_trace .= isset($frame['args']) ? \substr(\json_encode($frame['args']), 1, -1) : '';
$this->tl_trace .= ')'; $this->tl_trace .= ')';
$this->tl_trace .= $eol; $this->tl_trace .= $eol;
$tl = false; $tl = false;
} }
} }
$this->tl_trace .= $init !== '' ? "['" . $init . "']" : ''; $this->tl_trace .= $init !== '' ? "['".$init."']" : '';
$this->tl_trace = \implode($eol, \array_reverse(\explode($eol, $this->tl_trace))); $this->tl_trace = \implode($eol, \array_reverse(\explode($eol, $this->tl_trace)));
if ($previous_trace) { if ($previous_trace) {
$this->tl_trace .= $eol . $eol; $this->tl_trace .= $eol.$eol;
$this->tl_trace .= "Previous TL trace:{$eol}"; $this->tl_trace .= "Previous TL trace:{$eol}";
$this->tl_trace .= $previous_trace; $this->tl_trace .= $previous_trace;
} }

View File

@ -20,6 +20,7 @@
namespace danog\MadelineProto\TL; namespace danog\MadelineProto\TL;
use danog\MadelineProto\MTProto; use danog\MadelineProto\MTProto;
use danog\MadelineProto\Tools;
/** /**
* TL serialization. * TL serialization.
@ -142,7 +143,7 @@ class TL
$this->tdDescriptions = ['types' => [], 'constructors' => [], 'methods' => []]; $this->tdDescriptions = ['types' => [], 'constructors' => [], 'methods' => []];
foreach ($files as $scheme_type => $file) { foreach ($files as $scheme_type => $file) {
$this->API->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['file_parsing'], \basename($file)), \danog\MadelineProto\Logger::VERBOSE); $this->API->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['file_parsing'], \basename($file)), \danog\MadelineProto\Logger::VERBOSE);
$filec = \file_get_contents(\danog\MadelineProto\Absolute::absolute($file)); $filec = \file_get_contents(Tools::absolute($file));
$TL_dict = \json_decode($filec, true); $TL_dict = \json_decode($filec, true);
if ($TL_dict === null) { if ($TL_dict === null) {
$TL_dict = ['methods' => [], 'constructors' => []]; $TL_dict = ['methods' => [], 'constructors' => []];
@ -793,8 +794,8 @@ class TL
/** /**
* Deserialize TL object. * Deserialize TL object.
* *
* @param resource $stream Stream * @param string|resource $stream Stream
* @param array $type Type identifier * @param array $type Type identifier
* *
* @return mixed * @return mixed
*/ */

View File

@ -30,10 +30,10 @@ class TLConstructors
{ {
return ['by_predicate_and_layer', 'by_id', 'layers']; return ['by_predicate_and_layer', 'by_id', 'layers'];
} }
public function add($json_dict, $scheme_type) public function add(array $json_dict, string $scheme_type): void
{ {
if (isset($this->by_id[$json_dict['id']]) && (!isset($this->by_id[$json_dict['id']]['layer']) || $this->by_id[$json_dict['id']]['layer'] > $json_dict['layer'])) { if (isset($this->by_id[$json_dict['id']]) && (!isset($this->by_id[$json_dict['id']]['layer']) || $this->by_id[$json_dict['id']]['layer'] > $json_dict['layer'])) {
return false; return;
} }
$predicate = (string) (($scheme_type === 'mtproto' && $json_dict['predicate'] === 'message' ? 'MT' : '').$json_dict['predicate']); $predicate = (string) (($scheme_type === 'mtproto' && $json_dict['predicate'] === 'message' ? 'MT' : '').$json_dict['predicate']);
$this->by_id[$json_dict['id']] = ['predicate' => $predicate, 'params' => $json_dict['params'], 'type' => ($scheme_type === 'mtproto' && $json_dict['type'] === 'Message' ? 'MT' : '').$json_dict['type']]; $this->by_id[$json_dict['id']] = ['predicate' => $predicate, 'params' => $json_dict['params'], 'type' => ($scheme_type === 'mtproto' && $json_dict['type'] === 'Message' ? 'MT' : '').$json_dict['type']];
@ -47,7 +47,7 @@ class TLConstructors
$this->by_predicate_and_layer[$predicate.$json_dict['layer']] = $json_dict['id']; $this->by_predicate_and_layer[$predicate.$json_dict['layer']] = $json_dict['id'];
$this->parseParams($json_dict['id'], $scheme_type === 'mtproto'); $this->parseParams($json_dict['id'], $scheme_type === 'mtproto');
} }
public function findByType($type) public function findByType(string $type)
{ {
foreach ($this->by_id as $id => $constructor) { foreach ($this->by_id as $id => $constructor) {
if ($constructor['type'] === $type) { if ($constructor['type'] === $type) {
@ -57,7 +57,7 @@ class TLConstructors
} }
return false; return false;
} }
public function findByPredicate($predicate, $layer = -1) public function findByPredicate(string $predicate, int $layer = -1)
{ {
if ($layer !== -1) { if ($layer !== -1) {
$chosenid = null; $chosenid = null;

View File

@ -26,11 +26,11 @@ class TLMethods
public $by_id = []; public $by_id = [];
public $by_method = []; public $by_method = [];
public $method_namespace = []; public $method_namespace = [];
public function __sleep() public function __sleep(): array
{ {
return ['by_id', 'by_method', 'method_namespace']; return ['by_id', 'by_method', 'method_namespace'];
} }
public function add($json_dict) public function add(array $json_dict): void
{ {
$this->by_id[$json_dict['id']] = ['method' => $json_dict['method'], 'type' => $json_dict['type'], 'params' => $json_dict['params']]; $this->by_id[$json_dict['id']] = ['method' => $json_dict['method'], 'type' => $json_dict['type'], 'params' => $json_dict['params']];
$this->by_method[$json_dict['method']] = $json_dict['id']; $this->by_method[$json_dict['method']] = $json_dict['id'];
@ -40,7 +40,7 @@ class TLMethods
} }
$this->parseParams($json_dict['id']); $this->parseParams($json_dict['id']);
} }
public function findById($id) public function findById(string $id)
{ {
if (isset($this->by_id[$id])) { if (isset($this->by_id[$id])) {
$method = $this->by_id[$id]; $method = $this->by_id[$id];
@ -49,7 +49,7 @@ class TLMethods
} }
return false; return false;
} }
public function findByMethod($method_name) public function findByMethod(string $method_name)
{ {
if (isset($this->by_method[$method_name])) { if (isset($this->by_method[$method_name])) {
$method = $this->by_id[$this->by_method[$method_name]]; $method = $this->by_id[$this->by_method[$method_name]];

View File

@ -31,10 +31,10 @@ trait TLParams
if (\preg_match('/^(v|V)ector\\<(.*)\\>$/', $param['type'], $matches)) { if (\preg_match('/^(v|V)ector\\<(.*)\\>$/', $param['type'], $matches)) {
$param['type'] = $matches[1] === 'v' ? 'vector' : 'Vector t'; $param['type'] = $matches[1] === 'v' ? 'vector' : 'Vector t';
$param['subtype'] = $matches[2]; $param['subtype'] = $matches[2];
$param['subtype'] = ($mtproto && $param['subtype'] === 'Message' ? 'MT' : '') . $param['subtype']; $param['subtype'] = ($mtproto && $param['subtype'] === 'Message' ? 'MT' : '').$param['subtype'];
$param['subtype'] = $mtproto && $param['subtype'] === '%Message' ? '%MTMessage' : $param['subtype']; $param['subtype'] = $mtproto && $param['subtype'] === '%Message' ? '%MTMessage' : $param['subtype'];
} }
$param['type'] = ($mtproto && $param['type'] === 'Message' ? 'MT' : '') . $param['type']; $param['type'] = ($mtproto && $param['type'] === 'Message' ? 'MT' : '').$param['type'];
$param['type'] = $mtproto && $param['type'] === '%Message' ? '%MTMessage' : $param['type']; $param['type'] = $mtproto && $param['type'] === '%Message' ? '%MTMessage' : $param['type'];
$this->by_id[$key]['params'][$kkey] = $param; $this->by_id[$key]['params'][$kkey] = $param;
} }

View File

@ -1,23 +0,0 @@
MadelineProto.main flags:# encrypted_layer:int settings:MadelineProto.settings config:Config authorization:flags.0?auth.Authorization authorized:int rsa_keys:Vector<MadelineProto.RSA> last_recv:int dh_config:messages.DhConfig chats:Vector<Chat> last_stored:int qres:Vector<PWR.Chat> pending_updates:Vector<Update> updates_state:MadelineProto.Updates_state got_state:flags.1?true channels_state:MadelineProto.Channel_states updates:Vector<Update> updates_key:int getting_state:flags.2?true full_chats:MadelineProto.FullChat msg_ids:Vector<long> dialog_params:MadelineProto.DialogParams datacenter:MadelineProto.DataCenter v:int constructors:MadelineProto.Constructors td_constructors:flags.3?MadelineProto.Constructors methods:MadelineProto.Methods td_methods:flags.4?MadelineProto.Methods td_descriptions:flags.5?MadelineProto.Descriptions twoe1984:Serialized twoe2047:Serialized twoe2048:Serialized zero:Serialized one:Serialized two:Serialized three:Serialized four:Serialized = MadelineProto.Main;
MadelineProto.settings = MadelineProto.Settings;
MadelineProto.connection_settings = MadelineProto.Settings;
MadelineProto.channel_states = pts:int pending_pts_updates:Vector<Update> sync_loading:Bool MadelineProto.Channel_states;
MadelineProto.update_state = pts:int qts:int seq:int date:int pending_seq_updates:Vector<Update> pending_pts_updates:Vector<Update> sync_loading:Bool MadelineProto.Update_state;
MadelineProto.rsa e:Serialized n:Serialized fp:string = MadelineProto.RSA;
MadelineProto.dialogParams flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int = MadelineProto.DialogParams;
MadelineProto.dataCenter sockets:Vector<MadelineProto.Connection> curdc:int dclist:Vector<dcOption> settings:MadelineProto.Settings = MadelineProto.DataCenter;
MadelineProto.connection flags:# protocol:string ip:string port:int timeout:int parsed:flags.0?MadelineProto.ParsedUrl temp_auth_key:MadelineProto.AuthKey auth_key:MadelineProto.AuthKey ipv6:flags.1?true incoming_messages:Vector<MadelineProto.Messages> outgoing_messages:Vector<MadelineProto.Messages> new_incoming:Vector<long> new_outgoing:Vector<long>
MadelineProto.descriptions = MadelineProto.Descriptions;
MadelineProto.methods = MadelineProto.Methods;
MadelineProto.constructors = MadelineProto.Constructors;
MadelineProto.parsedUrl = MadelineProto.ParsedUrl;
MadelineProto.authKey server_salt:long id:long auth_key:string = MadelineProto.AuthKey;
MadelineProto.messages flags:# seq_no:flags.0?int content:Object response:int = MadelineProto.Messages;
pwr.chat flags:# type:string id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string lang_code:flags.3?string username:flags.4?string verified:flags.5?true restricted:flags.6?true restriction_reason:flags.7?string status:flags.8?UserStatus bot_inline_placeholder:flags.9?string about:flags.10?string bot_info:flags.11?BotInfo phone_calls_available:flags.12?true phone_calls_private:flags.13?true common_chats_count:flags.14?int photo:flags.15?string title:flags.16?string participants_count:flags.17?int kicked_count:flags.18?int admin_count:flags.19?int admin:flags.20?true all_members_are_administrators:flags.21?true invite:flags.22?string participants:flags.23?Vector<PWRParticipant> democracy:flags.24?true signatures:flags.25?true can_view_participants:flags.26?true can_set_username:flags.27?true migrated_from_chat_id:flags.28?int migrated_from_max_id:flags.29?int pinned_msg_id:flags.30?int = PWR.Chat;
pwr.participant flags:# user:PWR.Chat inviter:flags.0?PWR.Chat date:int role:string = PWR.Participant;
//auth.sentCodeMP flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int phone_number:flags.3?string phone_code:flags.4?string = auth.Authorization;
//auth.noPasswordMP new_salt:bytes email_unconfirmed_pattern:string = auth.Authorization;
//auth.passwordMP current_salt:bytes new_salt:bytes hint:string has_recovery:Bool email_unconfirmed_pattern:string = auth.Authorization;

View File

@ -1,19 +0,0 @@
bot_thumbnail#0 dc_id:int id:long access_hash:long volume_id:long = File;
bot_profile_photo#1 dc_id:int id:long access_hash:long volume_id:long = File;
bot_photo#2 dc_id:int id:long access_hash:long volume_id:long = File;
bot_voice#3 dc_id:int id:long access_hash:long = File;
bot_video#4 dc_id:int id:long access_hash:long = File;
bot_document#5 dc_id:int id:long access_hash:long = File;
bot_encrypted#6 dc_id:int id:long access_hash:long = File;
bot_temp#7 dc_id:int id:long access_hash:long = File;
bot_sticker#8 dc_id:int id:long access_hash:long = File;
bot_audio#9 dc_id:int id:long access_hash:long = File;
bot_gif#A dc_id:int id:long access_hash:long = File;
bot_encrypted_thumbnail#B dc_id:int id:long access_hash:long = File;
bot_wallpaper#C dc_id:int id:long access_hash:long = File;
bot_video_note#D dc_id:int id:long access_hash:long = File;
bot_secure_raw#F dc_id:int id:long access_hash:long = File;
bot_secure#10 dc_id:int id:long access_hash:long = File;
bot_background#11 dc_id:int id:long access_hash:long = File;
bot_size#12 dc_id:int id:long access_hash:long = File;

View File

@ -1,3 +0,0 @@
decryptedDataBlock#dbf948c1 random_id:long random_bytes:string flags:# voice_call_id:flags.2?int128 in_seq_no:flags.4?int out_seq_no:flags.4?int recent_received_mask:flags.5?int proto:flags.3?int extra:flags.1?string raw_data:flags.0?string = DecryptedDataBlock;
simpleDataBlock#cc0d0e76 random_id:long random_bytes:string raw_data:string = DecryptedDataBlock;

File diff suppressed because one or more lines are too long

View File

@ -1,86 +0,0 @@
resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector<long> = ResPQ;
vector {t:Type} # [ t ] = Vector t;
p_q_inner_data_dc#a9f55f95 pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 dc:int = P_Q_inner_data;
p_q_inner_data_temp_dc#56fddf88 pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 dc:int expires_in:int = P_Q_inner_data;
p_q_inner_data pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data;
p_q_inner_data_temp pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 expires_in:int = P_Q_inner_data;
server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params;
server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params;
server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:string g_a:string server_time:int = Server_DH_inner_data;
client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:string = Client_DH_Inner_Data;
dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer;
dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer;
dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = Set_client_DH_params_answer;
bind_auth_key_inner#75a3f765 nonce:long temp_auth_key_id:long perm_auth_key_id:long temp_session_id:long expires_at:int = BindAuthKeyInner;
rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult;
rpc_error#2144ca19 error_code:int error_message:string = RpcError;
rpc_answer_unknown#5e2ad36e = RpcDropAnswer;
rpc_answer_dropped_running#cd78e586 = RpcDropAnswer;
rpc_answer_dropped#a43ad8b7 msg_id:long seq_no:int bytes:int = RpcDropAnswer;
future_salt#0949d9dc valid_since:int valid_until:int salt:long = FutureSalt;
future_salts#ae500895 req_msg_id:long now:int salts:vector<future_salt> = FutureSalts;
pong#347773c5 msg_id:long ping_id:long = Pong;
destroy_session_ok#e22045fc session_id:long = DestroySessionRes;
destroy_session_none#62d350c9 session_id:long = DestroySessionRes;
new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long = NewSession;
msg_container#73f1f8dc messages:vector<%Message> = MessageContainer;
message msg_id:long seqno:int bytes:int body:Object = Message;
msg_copy#e06046b2 orig_message:Message = MessageCopy;
gzip_packed#3072cfa1 packed_data:bytes = Object;
msgs_ack#62d6b459 msg_ids:Vector<long> = MsgsAck;
bad_msg_notification#a7eff811 bad_msg_id:long bad_msg_seqno:int error_code:int = BadMsgNotification;
bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int error_code:int new_server_salt:long = BadMsgNotification;
msg_resend_ans_req#8610baeb msg_ids:Vector<long> = MsgResendReq;
msg_resend_req#7d861a08 msg_ids:Vector<long> = MsgResendReq;
msgs_state_req#da69fb52 msg_ids:Vector<long> = MsgsStateReq;
msgs_state_info#04deb57d req_msg_id:long info:string = MsgsStateInfo;
msgs_all_info#8cc0d131 msg_ids:Vector<long> info:string = MsgsAllInfo;
msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long bytes:int status:int = MsgDetailedInfo;
msg_new_detailed_info#809db6df answer_msg_id:long bytes:int status:int = MsgDetailedInfo;
rsa_public_key n:string e:string = RSAPublicKey;
http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait;
---functions---
req_pq_multi#be7e8ef1 nonce:int128 = ResPQ;
req_pq nonce:int128 = ResPQ;
req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params;
set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:string = Set_client_DH_params_answer;
rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer;
get_future_salts#b921bd04 num:int = FutureSalts;
ping#7abe77ec ping_id:long = Pong;
ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong;
destroy_session#e7512126 session_id:long = DestroySessionRes;
//test.useGzipPacked = GzipPacked;
//test.useServerDhInnerData = Server_DH_inner_data;
//test.useNewSessionCreated = NewSession;
//test.useMsgsAck = MsgsAck;
//test.useBadMsgNotification = BadMsgNotification;
//test.useOther key:rsa_public_key p_q_data:P_Q_inner_data dh_data:client_DH_inner_data = RpcError;

View File

@ -1,76 +0,0 @@
===8===
decryptedMessage#1f814f1f random_id:long random_bytes:bytes message:string media:DecryptedMessageMedia = DecryptedMessage;
decryptedMessageService#aa48327d random_id:long random_bytes:bytes action:DecryptedMessageAction = DecryptedMessage;
decryptedMessageMediaEmpty#89f5c4a = DecryptedMessageMedia;
decryptedMessageMediaPhoto#32798a8c thumb:bytes thumb_w:int thumb_h:int w:int h:int size:int key:bytes iv:bytes = DecryptedMessageMedia;
decryptedMessageMediaVideo#4cee6ef3 thumb:bytes thumb_w:int thumb_h:int duration:int w:int h:int size:int key:bytes iv:bytes = DecryptedMessageMedia;
decryptedMessageMediaGeoPoint#35480a59 lat:double long:double = DecryptedMessageMedia;
decryptedMessageMediaContact#588a0a97 phone_number:string first_name:string last_name:string user_id:int = DecryptedMessageMedia;
decryptedMessageActionSetMessageTTL#a1733aec ttl_seconds:int = DecryptedMessageAction;
decryptedMessageMediaDocument#b095434b thumb:bytes thumb_w:int thumb_h:int file_name:string mime_type:string size:int key:bytes iv:bytes = DecryptedMessageMedia;
decryptedMessageMediaAudio#6080758f duration:int size:int key:bytes iv:bytes = DecryptedMessageMedia;
decryptedMessageActionReadMessages#c4f40be random_ids:Vector<long> = DecryptedMessageAction;
decryptedMessageActionDeleteMessages#65614304 random_ids:Vector<long> = DecryptedMessageAction;
decryptedMessageActionScreenshotMessages#8ac1f475 random_ids:Vector<long> = DecryptedMessageAction;
decryptedMessageActionFlushHistory#6719e45c = DecryptedMessageAction;
===17===
decryptedMessage#204d3878 random_id:long ttl:int message:string media:DecryptedMessageMedia = DecryptedMessage;
decryptedMessageService#73164160 random_id:long action:DecryptedMessageAction = DecryptedMessage;
decryptedMessageMediaVideo#524a415d thumb:bytes thumb_w:int thumb_h:int duration:int mime_type:string w:int h:int size:int key:bytes iv:bytes = DecryptedMessageMedia;
decryptedMessageMediaAudio#57e0a9cb duration:int mime_type:string size:int key:bytes iv:bytes = DecryptedMessageMedia;
decryptedMessageLayer#1be31789 random_bytes:bytes layer:int in_seq_no:int out_seq_no:int message:DecryptedMessage = DecryptedMessageLayer;
sendMessageTypingAction#16bf744e = SendMessageAction;
sendMessageCancelAction#fd5ec8f5 = SendMessageAction;
sendMessageRecordVideoAction#a187d66f = SendMessageAction;
sendMessageUploadVideoAction#92042ff7 = SendMessageAction;
sendMessageRecordAudioAction#d52f73f7 = SendMessageAction;
sendMessageUploadAudioAction#e6ac8a6f = SendMessageAction;
sendMessageUploadPhotoAction#990a3c1a = SendMessageAction;
sendMessageUploadDocumentAction#8faee98e = SendMessageAction;
sendMessageGeoLocationAction#176f8ba1 = SendMessageAction;
sendMessageChooseContactAction#628cbc6f = SendMessageAction;
decryptedMessageActionResend#511110b0 start_seq_no:int end_seq_no:int = DecryptedMessageAction;
decryptedMessageActionNotifyLayer#f3048883 layer:int = DecryptedMessageAction;
decryptedMessageActionTyping#ccb27641 action:SendMessageAction = DecryptedMessageAction;
===20===
decryptedMessageActionRequestKey#f3c9611b exchange_id:long g_a:bytes = DecryptedMessageAction;
decryptedMessageActionAcceptKey#6fe1735b exchange_id:long g_b:bytes key_fingerprint:long = DecryptedMessageAction;
decryptedMessageActionAbortKey#dd05ec6b exchange_id:long = DecryptedMessageAction;
decryptedMessageActionCommitKey#ec2e0b9b exchange_id:long key_fingerprint:long = DecryptedMessageAction;
decryptedMessageActionNoop#a82fdd63 = DecryptedMessageAction;
===23===
documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute;
documentAttributeAnimated#11b58939 = DocumentAttribute;
documentAttributeSticker#fb0a5727 = DocumentAttribute;
documentAttributeVideo#5910cccb duration:int w:int h:int = DocumentAttribute;
documentAttributeAudio#51448e5 duration:int = DocumentAttribute;
documentAttributeFilename#15590068 file_name:string = DocumentAttribute;
photoSizeEmpty#e17e23c type:string = PhotoSize;
photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize;
photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize;
fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation;
fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation;
decryptedMessageMediaExternalDocument#fa95b0dd id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int attributes:Vector<DocumentAttribute> = DecryptedMessageMedia;
===45===
decryptedMessage#36b091de flags:# random_id:long ttl:int message:string media:flags.9?DecryptedMessageMedia entities:flags.7?Vector<MessageEntity> via_bot_name:flags.11?string reply_to_random_id:flags.3?long = DecryptedMessage;
decryptedMessageMediaPhoto#f1fa8d78 thumb:bytes thumb_w:int thumb_h:int w:int h:int size:int key:bytes iv:bytes caption:string = DecryptedMessageMedia;
decryptedMessageMediaVideo#970c8c0e thumb:bytes thumb_w:int thumb_h:int duration:int mime_type:string w:int h:int size:int key:bytes iv:bytes caption:string = DecryptedMessageMedia;
decryptedMessageMediaDocument#7afe8ae2 thumb:bytes thumb_w:int thumb_h:int mime_type:string size:int key:bytes iv:bytes attributes:Vector<DocumentAttribute> caption:string = DecryptedMessageMedia;
===46===
decryptedMessageMediaVenue#8a0df56f lat:double long:double title:string address:string provider:string venue_id:string = DecryptedMessageMedia;
documentAttributeAudio#ded218e0 duration:int title:string performer:string = DocumentAttribute;
decryptedMessageMediaWebPage#e50511d8 url:string = DecryptedMessageMedia;
===55===
documentAttributeSticker#3a556302 alt:string stickerset:InputStickerSet = DocumentAttribute;
===66===
documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true duration:int w:int h:int = DocumentAttribute;
===73===
decryptedMessage#91cc4674 flags:# random_id:long ttl:int message:string media:flags.9?DecryptedMessageMedia entities:flags.7?Vector<MessageEntity> via_bot_name:flags.11?string reply_to_random_id:flags.3?long grouped_id:flags.17?long = DecryptedMessage;

View File

@ -1,17 +0,0 @@
dataJSON#7d748d04 data:string = DataJSON;
socketMessageRequest request_id:int method:vector<string> args:vector<%DataJSON> = SocketMessage;
socketMessageResponse request_id:int data:%DataJSON = SocketMessage;
socketMessageException request_id:int exception:SocketException = SocketMessage;
socketMessageUpdate data:%DataJSON = SocketMessage;
socketMessageLog flags:# thread:flags.0?true process:flags.1?true file:string level:int data:%DataJSON = SocketMessage;
socketMessageRawData stream_id:string data:bytes = SocketMessage;
socketException message:string code:int trace:%SocketTLTrace = SocketException;
socketRPCErrorException flags:# rpc_message:flags.0?string message:flags.1?string code:int trace:%SocketTLTrace = SocketException;
socketTLException message:string code:int trace:%SocketTLTrace = SocketException;
socketDOMException message:string code:int trace:%SocketTLTrace = SocketException;
socketTLTrace frames:vector<%SocketTLFrame> = SocketTLTrace;
socketTLFrame flags:# file:flags.0?string line:flags.1?int function:flags.2?string args:flags.3?string tl_param:flags.4?string = SocketTLFrame;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,723 +0,0 @@
int ?= Int;
long ?= Long;
double ?= Double;
string ?= String;
bytes string = Bytes;
int128 long long = Int128;
int256 long long long long = Int256;
boolFalse#bc799737 = Bool;
boolTrue#997275b5 = Bool;
true#3fedd339 = True;
vector#1cb5c415 {t:Type} # [ t ] = Vector t;
error#c4b9f9bb code:int text:string = Error;
null#56730bcc = Null;
inputPeerEmpty#7f3b18ea = InputPeer;
inputPeerSelf#7da07ec9 = InputPeer;
inputPeerChat#179be863 chat_id:int = InputPeer;
inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer;
inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer;
inputUserEmpty#b98886cf = InputUser;
inputUserSelf#f7c1b13f = InputUser;
inputUser#d8292816 user_id:int access_hash:long = InputUser;
inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact;
inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile;
inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile;
inputMediaEmpty#9664f57f = InputMedia;
inputMediaUploadedPhoto#f7aff1c0 file:InputFile caption:string = InputMedia;
inputMediaPhoto#e9bfb4f3 id:InputPhoto caption:string = InputMedia;
inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia;
inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia;
inputMediaUploadedVideo#82713fdf file:InputFile duration:int w:int h:int mime_type:string caption:string = InputMedia;
inputMediaUploadedThumbVideo#7780ddf9 file:InputFile thumb:InputFile duration:int w:int h:int mime_type:string caption:string = InputMedia;
inputMediaVideo#936a4ebd video:InputVideo caption:string = InputMedia;
inputMediaUploadedAudio#4e498cab file:InputFile duration:int mime_type:string = InputMedia;
inputMediaAudio#89938781 audio:InputAudio = InputMedia;
inputMediaUploadedDocument#1d89306d file:InputFile mime_type:string attributes:Vector<DocumentAttribute> caption:string = InputMedia;
inputMediaUploadedThumbDocument#ad613491 file:InputFile thumb:InputFile mime_type:string attributes:Vector<DocumentAttribute> caption:string = InputMedia;
inputMediaDocument#1a77f29c document_id:InputDocument caption:string = InputMedia;
inputMediaVenue#2827a81a geo_point:InputGeoPoint title:string address:string provider:string venue_id:string = InputMedia;
inputMediaGifExternal#4843b0fd url:string q:string = InputMedia;
inputChatPhotoEmpty#1ca48f57 = InputChatPhoto;
inputChatUploadedPhoto#94254732 file:InputFile crop:InputPhotoCrop = InputChatPhoto;
inputChatPhoto#b2e1bf08 id:InputPhoto crop:InputPhotoCrop = InputChatPhoto;
inputGeoPointEmpty#e4c123d6 = InputGeoPoint;
inputGeoPoint#f3b7acc9 latitude:double longitude:double = InputGeoPoint;
inputPhotoEmpty#1cd7bf0d = InputPhoto;
inputPhoto#fb95c6c4 id:long access_hash:long = InputPhoto;
inputVideoEmpty#5508ec75 = InputVideo;
inputVideo#ee579652 id:long access_hash:long = InputVideo;
inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLocation;
inputVideoFileLocation#3d0364ec id:long access_hash:long = InputFileLocation;
inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation;
inputAudioFileLocation#74dc404d id:long access_hash:long = InputFileLocation;
inputDocumentFileLocation#4e45abe9 id:long access_hash:long = InputFileLocation;
inputPhotoCropAuto#ade6b004 = InputPhotoCrop;
inputPhotoCrop#d9915325 crop_left:double crop_top:double crop_width:double = InputPhotoCrop;
inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent;
peerUser#9db1bc6d user_id:int = Peer;
peerChat#bad0e5bb chat_id:int = Peer;
peerChannel#bddde532 channel_id:int = Peer;
storage.fileUnknown#aa963b05 = storage.FileType;
storage.fileJpeg#7efe0e = storage.FileType;
storage.fileGif#cae1aadf = storage.FileType;
storage.filePng#a4f63c0 = storage.FileType;
storage.filePdf#ae1e508d = storage.FileType;
storage.fileMp3#528a0677 = storage.FileType;
storage.fileMov#4b09ebbc = storage.FileType;
storage.filePartial#40bc6f52 = storage.FileType;
storage.fileMp4#b3cea0e4 = storage.FileType;
storage.fileWebp#1081464c = storage.FileType;
fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation;
fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation;
userEmpty#200250ba id:int = User;
user#d10d979a flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string = User;
userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto;
userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto;
userStatusEmpty#9d05049 = UserStatus;
userStatusOnline#edb93949 expires:int = UserStatus;
userStatusOffline#8c703f was_online:int = UserStatus;
userStatusRecently#e26f42f1 = UserStatus;
userStatusLastWeek#7bf09fc = UserStatus;
userStatusLastMonth#77ebc742 = UserStatus;
chatEmpty#9ba2d800 id:int = Chat;
chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat;
chatForbidden#7328bdb id:int title:string = Chat;
channel#4b1b7506 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true editor:flags.3?true moderator:flags.4?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true id:int access_hash:long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string = Chat;
channelForbidden#2d85832c id:int access_hash:long title:string = Chat;
chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> = ChatFull;
channelFull#9e341ddf flags:# can_view_participants:flags.3?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int read_inbox_max_id:int unread_count:int unread_important_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int = ChatFull;
chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant;
chatParticipantCreator#da13538a user_id:int = ChatParticipant;
chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant;
chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants;
chatParticipants#3f460fed chat_id:int participants:Vector<ChatParticipant> version:int = ChatParticipants;
chatPhotoEmpty#37c1011c = ChatPhoto;
chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto;
messageEmpty#83e5de54 id:int = Message;
message#c992e15c flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true id:int from_id:flags.8?int to_id:Peer fwd_from_id:flags.2?Peer fwd_date:flags.2?int via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int = Message;
messageService#c06b9607 flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true id:int from_id:flags.8?int to_id:Peer date:int action:MessageAction = Message;
messageMediaEmpty#3ded6320 = MessageMedia;
messageMediaPhoto#3d8ce53d photo:Photo caption:string = MessageMedia;
messageMediaVideo#5bcf1675 video:Video caption:string = MessageMedia;
messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia;
messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:string user_id:int = MessageMedia;
messageMediaUnsupported#9f84f49e = MessageMedia;
messageMediaDocument#f3e02ea8 document:Document caption:string = MessageMedia;
messageMediaAudio#c6b68300 audio:Audio = MessageMedia;
messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia;
messageMediaVenue#7912b71f geo:GeoPoint title:string address:string provider:string venue_id:string = MessageMedia;
messageActionEmpty#b6aef7b0 = MessageAction;
messageActionChatCreate#a6638b9a title:string users:Vector<int> = MessageAction;
messageActionChatEditTitle#b5a1ce5a title:string = MessageAction;
messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction;
messageActionChatDeletePhoto#95e3fbef = MessageAction;
messageActionChatAddUser#488a7337 users:Vector<int> = MessageAction;
messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction;
messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction;
messageActionChannelCreate#95d2ac92 title:string = MessageAction;
messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction;
messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction;
dialog#c1dd804a peer:Peer top_message:int read_inbox_max_id:int unread_count:int notify_settings:PeerNotifySettings = Dialog;
dialogChannel#5b8496b2 peer:Peer top_message:int top_important_message:int read_inbox_max_id:int unread_count:int unread_important_count:int notify_settings:PeerNotifySettings pts:int = Dialog;
photoEmpty#2331b22d id:long = Photo;
photo#cded42fe id:long access_hash:long date:int sizes:Vector<PhotoSize> = Photo;
photoSizeEmpty#e17e23c type:string = PhotoSize;
photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize;
photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize;
videoEmpty#c10658a8 id:long = Video;
video#f72887d3 id:long access_hash:long date:int duration:int mime_type:string size:int thumb:PhotoSize dc_id:int w:int h:int = Video;
geoPointEmpty#1117dd5f = GeoPoint;
geoPoint#2049d70c longitude:double latitude:double = GeoPoint;
auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone;
auth.sentCode#efed51d9 phone_registered:Bool phone_code_hash:string send_call_timeout:int is_password:Bool = auth.SentCode;
auth.sentAppCode#e325edcf phone_registered:Bool phone_code_hash:string send_call_timeout:int is_password:Bool = auth.SentCode;
auth.authorization#ff036af1 user:User = auth.Authorization;
auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization;
inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer;
inputNotifyUsers#193b4417 = InputNotifyPeer;
inputNotifyChats#4a95e84e = InputNotifyPeer;
inputNotifyAll#a429b886 = InputNotifyPeer;
inputPeerNotifyEventsEmpty#f03064d8 = InputPeerNotifyEvents;
inputPeerNotifyEventsAll#e86a2c74 = InputPeerNotifyEvents;
inputPeerNotifySettings#46a2ce98 mute_until:int sound:string show_previews:Bool events_mask:int = InputPeerNotifySettings;
peerNotifyEventsEmpty#add53cb3 = PeerNotifyEvents;
peerNotifyEventsAll#6d1ded88 = PeerNotifyEvents;
peerNotifySettingsEmpty#70a68512 = PeerNotifySettings;
peerNotifySettings#8d5e11ee mute_until:int sound:string show_previews:Bool events_mask:int = PeerNotifySettings;
wallPaper#ccb03657 id:int title:string sizes:Vector<PhotoSize> color:int = WallPaper;
wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper;
inputReportReasonSpam#58dbcab8 = ReportReason;
inputReportReasonViolence#1e22c78d = ReportReason;
inputReportReasonPornography#2e59d922 = ReportReason;
inputReportReasonOther#e1746d0a text:string = ReportReason;
userFull#5a89ac5b user:User link:contacts.Link profile_photo:Photo notify_settings:PeerNotifySettings blocked:Bool bot_info:BotInfo = UserFull;
contact#f911c994 user_id:int mutual:Bool = Contact;
importedContact#d0028438 user_id:int client_id:long = ImportedContact;
contactBlocked#561bc879 user_id:int date:int = ContactBlocked;
contactSuggested#3de191a1 user_id:int mutual_contacts:int = ContactSuggested;
contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus;
contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link;
contacts.contactsNotModified#b74ba9d2 = contacts.Contacts;
contacts.contacts#6f8b8cb2 contacts:Vector<Contact> users:Vector<User> = contacts.Contacts;
contacts.importedContacts#ad524315 imported:Vector<ImportedContact> retry_contacts:Vector<long> users:Vector<User> = contacts.ImportedContacts;
contacts.blocked#1c138d15 blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked;
contacts.blockedSlice#900802a1 count:int blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked;
contacts.suggested#5649dcc5 results:Vector<ContactSuggested> users:Vector<User> = contacts.Suggested;
messages.dialogs#15ba6c40 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
messages.dialogsSlice#71e094f3 count:int dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
messages.messages#8c718e87 messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.messagesSlice#b446ae3 count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.channelMessages#bc0f17bc flags:# pts:int count:int messages:Vector<Message> collapsed:flags.0?Vector<MessageGroup> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.chats#64ff9fd5 chats:Vector<Chat> = messages.Chats;
messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector<Chat> users:Vector<User> = messages.ChatFull;
messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory;
inputMessagesFilterEmpty#57e2f66c = MessagesFilter;
inputMessagesFilterPhotos#9609a51c = MessagesFilter;
inputMessagesFilterVideo#9fc00e65 = MessagesFilter;
inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter;
inputMessagesFilterPhotoVideoDocuments#d95e73bb = MessagesFilter;
inputMessagesFilterDocument#9eddf188 = MessagesFilter;
inputMessagesFilterAudio#cfc87522 = MessagesFilter;
inputMessagesFilterAudioDocuments#5afbf764 = MessagesFilter;
inputMessagesFilterUrl#7ef0dd87 = MessagesFilter;
inputMessagesFilterGif#ffc86587 = MessagesFilter;
updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update;
updateMessageID#4e90bfd6 id:int random_id:long = Update;
updateDeleteMessages#a20db0e5 messages:Vector<int> pts:int pts_count:int = Update;
updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update;
updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update;
updateChatParticipants#7761198 participants:ChatParticipants = Update;
updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update;
updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update;
updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update;
updateContactRegistered#2575bbb9 user_id:int date:int = Update;
updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update;
updateNewAuthorization#8f06529a auth_key_id:long date:int device:string location:string = Update;
updateNewEncryptedMessage#12bcbd9a encr_message:EncryptedMessage qts:int = Update;
updateEncryptedChatTyping#1710f156 chat_id:int = Update;
updateEncryption#b4a2e88d encr_chat:EncryptedChat date:int = Update;
updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update;
updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update;
updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update;
updateDcOptions#8e5e9873 dc_options:Vector<DcOption> = Update;
updateUserBlocked#80ece81a user_id:int blocked:Bool = Update;
updateNotifySettings#bec268ef notify_peer:NotifyPeer notify_settings:PeerNotifySettings = Update;
updateServiceNotification#382dd3e4 type:string message_text:string media:MessageMedia popup:Bool = Update;
updatePrivacy#ee3b272a key:PrivacyKey rules:Vector<PrivacyRule> = Update;
updateUserPhone#12b9417b user_id:int phone:string = Update;
updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update;
updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update;
updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update;
updateReadMessagesContents#68c13933 messages:Vector<int> pts:int pts_count:int = Update;
updateChannelTooLong#60946422 channel_id:int = Update;
updateChannel#b6d45656 channel_id:int = Update;
updateChannelGroup#c36c1e3c channel_id:int group:MessageGroup = Update;
updateNewChannelMessage#62ba04d9 message:Message channel_pts:int channel_pts_count:int = Update;
updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update;
updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector<int> channel_pts:int channel_pts_count:int = Update;
updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update;
updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update;
updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update;
updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update;
updateStickerSetsOrder#f0dfb451 order:Vector<long> = Update;
updateStickerSets#43ae3dec = Update;
updateSavedGifs#9375341e = Update;
updateBotInlineQuery#c01eea08 query_id:long user_id:int query:string offset:string = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference;
updates.difference#f49ca0 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> state:updates.State = updates.Difference;
updates.differenceSlice#a8fb1981 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> intermediate_state:updates.State = updates.Difference;
updatesTooLong#e317af7e = Updates;
updateShortMessage#13e4deaa flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from_id:flags.2?Peer fwd_date:flags.2?int via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates;
updateShortChatMessage#248afa62 flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from_id:flags.2?Peer fwd_date:flags.2?int via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates;
updateShort#78d4dec1 update:Update date:int = Updates;
updatesCombined#725b04c3 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq_start:int seq:int = Updates;
updates#74ae4240 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq:int = Updates;
updateShortSentMessage#11f1331c flags:# unread:flags.0?true out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector<MessageEntity> = Updates;
photos.photos#8dca6aa5 photos:Vector<Photo> users:Vector<User> = photos.Photos;
photos.photosSlice#15051f54 count:int photos:Vector<Photo> users:Vector<User> = photos.Photos;
photos.photo#20212ca8 photo:Photo users:Vector<User> = photos.Photo;
upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File;
dcOption#5d8c6cc flags:# ipv6:flags.0?true media_only:flags.1?true id:int ip_address:string port:int = DcOption;
config#6bbc5f8 date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int disabled_features:Vector<DisabledFeature> = Config;
nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
help.appUpdate#8987f311 id:int critical:Bool url:string text:string = help.AppUpdate;
help.noAppUpdate#c45a6536 = help.AppUpdate;
help.inviteText#18cb9f78 message:string = help.InviteText;
encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat;
encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat;
encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat;
encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat;
encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat;
inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat;
encryptedFileEmpty#c21f497e = EncryptedFile;
encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile;
inputEncryptedFileEmpty#1837c364 = InputEncryptedFile;
inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile;
inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile;
inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile;
encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage;
encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage;
messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig;
messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig;
messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage;
messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage;
inputAudioEmpty#d95adc84 = InputAudio;
inputAudio#77d440ff id:long access_hash:long = InputAudio;
inputDocumentEmpty#72f0eaae = InputDocument;
inputDocument#18798952 id:long access_hash:long = InputDocument;
audioEmpty#586988d8 id:long = Audio;
audio#f9e35055 id:long access_hash:long date:int duration:int mime_type:string size:int dc_id:int = Audio;
documentEmpty#36f8c871 id:long = Document;
document#f9a39f4f id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int attributes:Vector<DocumentAttribute> = Document;
help.support#17c6b5f6 phone_number:string user:User = help.Support;
notifyPeer#9fd40bd8 peer:Peer = NotifyPeer;
notifyUsers#b4c83b4c = NotifyPeer;
notifyChats#c007cec3 = NotifyPeer;
notifyAll#74d07c60 = NotifyPeer;
sendMessageTypingAction#16bf744e = SendMessageAction;
sendMessageCancelAction#fd5ec8f5 = SendMessageAction;
sendMessageRecordVideoAction#a187d66f = SendMessageAction;
sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction;
sendMessageRecordAudioAction#d52f73f7 = SendMessageAction;
sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction;
sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction;
sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction;
sendMessageGeoLocationAction#176f8ba1 = SendMessageAction;
sendMessageChooseContactAction#628cbc6f = SendMessageAction;
contacts.found#1aa1f784 results:Vector<Peer> chats:Vector<Chat> users:Vector<User> = contacts.Found;
inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey;
privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey;
inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule;
inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule;
inputPrivacyValueAllowUsers#131cc67f users:Vector<InputUser> = InputPrivacyRule;
inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule;
inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule;
inputPrivacyValueDisallowUsers#90110467 users:Vector<InputUser> = InputPrivacyRule;
privacyValueAllowContacts#fffe1bac = PrivacyRule;
privacyValueAllowAll#65427b82 = PrivacyRule;
privacyValueAllowUsers#4d5bbe0c users:Vector<int> = PrivacyRule;
privacyValueDisallowContacts#f888fa1a = PrivacyRule;
privacyValueDisallowAll#8b73e763 = PrivacyRule;
privacyValueDisallowUsers#c7f49b7 users:Vector<int> = PrivacyRule;
account.privacyRules#554abb6f rules:Vector<PrivacyRule> users:Vector<User> = account.PrivacyRules;
accountDaysTTL#b8d0afdf days:int = AccountDaysTTL;
account.sentChangePhoneCode#a4f58c4c phone_code_hash:string send_call_timeout:int = account.SentChangePhoneCode;
documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute;
documentAttributeAnimated#11b58939 = DocumentAttribute;
documentAttributeSticker#3a556302 alt:string stickerset:InputStickerSet = DocumentAttribute;
documentAttributeVideo#5910cccb duration:int w:int h:int = DocumentAttribute;
documentAttributeAudio#ded218e0 duration:int title:string performer:string = DocumentAttribute;
documentAttributeFilename#15590068 file_name:string = DocumentAttribute;
messages.stickersNotModified#f1749a22 = messages.Stickers;
messages.stickers#8a8ecd32 hash:string stickers:Vector<Document> = messages.Stickers;
stickerPack#12b299d4 emoticon:string documents:Vector<long> = StickerPack;
messages.allStickersNotModified#e86602c3 = messages.AllStickers;
messages.allStickers#edfd405f hash:int sets:Vector<StickerSet> = messages.AllStickers;
disabledFeature#ae636f24 feature:string description:string = DisabledFeature;
messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages;
contactLinkUnknown#5f4f9247 = ContactLink;
contactLinkNone#feedd3ad = ContactLink;
contactLinkHasPhone#268f3f59 = ContactLink;
contactLinkContact#d502c2d0 = ContactLink;
webPageEmpty#eb1477e8 id:long = WebPage;
webPagePending#c586da1c id:long date:int = WebPage;
webPage#ca820ed7 flags:# id:long url:string display_url:string type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document = WebPage;
authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization;
account.authorizations#1250abde authorizations:Vector<Authorization> = account.Authorizations;
account.noPassword#96dabc18 new_salt:bytes email_unconfirmed_pattern:string = account.Password;
account.password#7c18141c current_salt:bytes new_salt:bytes hint:string has_recovery:Bool email_unconfirmed_pattern:string = account.Password;
account.passwordSettings#b7b72ab3 email:string = account.PasswordSettings;
account.passwordInputSettings#bcfc532c flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string = account.PasswordInputSettings;
auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery;
receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage;
chatInviteEmpty#69df3769 = ExportedChatInvite;
chatInviteExported#fc2e05bc link:string = ExportedChatInvite;
chatInviteAlready#5a686d7c chat:Chat = ChatInvite;
chatInvite#93e99b60 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string = ChatInvite;
inputStickerSetEmpty#ffb62b95 = InputStickerSet;
inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
stickerSet#cd303b41 flags:# installed:flags.0?true disabled:flags.1?true official:flags.2?true id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet;
messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
botCommand#c27ac8c7 command:string description:string = BotCommand;
botInfoEmpty#bb2e37ce = BotInfo;
botInfo#9cf585d user_id:int version:int share_text:string description:string commands:Vector<BotCommand> = BotInfo;
keyboardButton#a2fa4880 text:string = KeyboardButton;
keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow;
replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup;
replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup;
replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector<KeyboardButtonRow> = ReplyMarkup;
help.appChangelogEmpty#af7e0394 = help.AppChangelog;
help.appChangelog#4668e6bd text:string = help.AppChangelog;
messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity;
messageEntityMention#fa04579d offset:int length:int = MessageEntity;
messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity;
messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity;
messageEntityUrl#6ed02538 offset:int length:int = MessageEntity;
messageEntityEmail#64e475c2 offset:int length:int = MessageEntity;
messageEntityBold#bd610bc9 offset:int length:int = MessageEntity;
messageEntityItalic#826f8b60 offset:int length:int = MessageEntity;
messageEntityCode#28a20571 offset:int length:int = MessageEntity;
messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity;
messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity;
inputChannelEmpty#ee8c1e86 = InputChannel;
inputChannel#afeb712e channel_id:int access_hash:long = InputChannel;
contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector<Chat> users:Vector<User> = contacts.ResolvedPeer;
messageRange#ae30253 min_id:int max_id:int = MessageRange;
messageGroup#e8346f53 min_id:int max_id:int count:int date:int = MessageGroup;
updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true channel_pts:int timeout:flags.1?int = updates.ChannelDifference;
updates.channelDifferenceTooLong#5e167646 flags:# final:flags.0?true channel_pts:int timeout:flags.1?int top_message:int top_important_message:int read_inbox_max_id:int unread_count:int unread_important_count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference;
updates.channelDifference#2064674e flags:# final:flags.0?true channel_pts:int timeout:flags.1?int new_messages:Vector<Message> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference;
channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter;
channelMessagesFilter#cd77d957 flags:# important_only:flags.0?true exclude_new_messages:flags.1?true ranges:Vector<MessageRange> = ChannelMessagesFilter;
channelMessagesFilterCollapsed#fa01232e = ChannelMessagesFilter;
channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant;
channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant;
channelParticipantModerator#91057fef user_id:int inviter_id:int date:int = ChannelParticipant;
channelParticipantEditor#98192d61 user_id:int inviter_id:int date:int = ChannelParticipant;
channelParticipantKicked#8cc5e69a user_id:int kicked_by:int date:int = ChannelParticipant;
channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant;
channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter;
channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter;
channelParticipantsKicked#3c37bb7a = ChannelParticipantsFilter;
channelParticipantsBots#b0d1865b = ChannelParticipantsFilter;
channelRoleEmpty#b285a0c6 = ChannelParticipantRole;
channelRoleModerator#9618d975 = ChannelParticipantRole;
channelRoleEditor#820bfe8c = ChannelParticipantRole;
channels.channelParticipants#f56ee2a8 count:int participants:Vector<ChannelParticipant> users:Vector<User> = channels.ChannelParticipants;
channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector<User> = channels.ChannelParticipant;
help.termsOfService#f1ee3e90 text:string = help.TermsOfService;
foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif;
foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif;
messages.foundGifs#450a1c0a next_offset:int results:Vector<FoundGif> = messages.FoundGifs;
messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs;
messages.savedGifs#2e0709a5 hash:int gifs:Vector<Document> = messages.SavedGifs;
inputBotInlineMessageMediaAuto#2e43e587 caption:string = InputBotInlineMessage;
inputBotInlineMessageText#adf0df71 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> = InputBotInlineMessage;
inputBotInlineResult#2cbbe15a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:InputBotInlineMessage = InputBotInlineResult;
botInlineMessageMediaAuto#fc56e87d caption:string = BotInlineMessage;
botInlineMessageText#a56197a9 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> = BotInlineMessage;
botInlineMediaResultDocument#f897d33e id:string type:string document:Document send_message:BotInlineMessage = BotInlineResult;
botInlineMediaResultPhoto#c5528587 id:string type:string photo:Photo send_message:BotInlineMessage = BotInlineResult;
botInlineResult#9bebaeb9 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:BotInlineMessage = BotInlineResult;
messages.botResults#1170b0a3 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string results:Vector<BotInlineResult> = messages.BotResults;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector<long> query:!X = X;
initConnection#69796de9 {X:Type} api_id:int device_model:string system_version:string app_version:string lang_code:string query:!X = X;
invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X;
invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X;
auth.checkPhone#6fe51dfb phone_number:string = auth.CheckedPhone;
auth.sendCode#768d5f4d phone_number:string sms_type:int api_id:int api_hash:string lang_code:string = auth.SentCode;
auth.sendCall#3c51564 phone_number:string phone_code_hash:string = Bool;
auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization;
auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization;
auth.logOut#5717da40 = Bool;
auth.resetAuthorizations#9fab0d1a = Bool;
auth.sendInvites#771c1d97 phone_numbers:Vector<string> message:string = Bool;
auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization;
auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization;
auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool;
auth.sendSms#da9f3e8 phone_number:string phone_code_hash:string = Bool;
auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization;
auth.checkPassword#a63011e password_hash:bytes = auth.Authorization;
auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery;
auth.recoverPassword#4ea56e92 code:string = auth.Authorization;
account.registerDevice#446c712c token_type:int token:string device_model:string system_version:string app_version:string app_sandbox:Bool lang_code:string = Bool;
account.unregisterDevice#65c55b40 token_type:int token:string = Bool;
account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool;
account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings;
account.resetNotifySettings#db7e1747 = Bool;
account.updateProfile#f0888d68 first_name:string last_name:string = User;
account.updateStatus#6628562c offline:Bool = Bool;
account.getWallPapers#c04cfac2 = Vector<WallPaper>;
account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool;
account.checkUsername#2714d86c username:string = Bool;
account.updateUsername#3e0bdd7c username:string = User;
account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules;
account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector<InputPrivacyRule> = account.PrivacyRules;
account.deleteAccount#418d4e0b reason:string = Bool;
account.getAccountTTL#8fc711d = AccountDaysTTL;
account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool;
account.sendChangePhoneCode#a407a8f4 phone_number:string = account.SentChangePhoneCode;
account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User;
account.updateDeviceLocked#38df3532 period:int = Bool;
account.getAuthorizations#e320c158 = account.Authorizations;
account.resetAuthorization#df77f3bc hash:long = Bool;
account.getPassword#548a30f5 = account.Password;
account.getPasswordSettings#bc8d11bb current_password_hash:bytes = account.PasswordSettings;
account.updatePasswordSettings#fa7c4b86 current_password_hash:bytes new_settings:account.PasswordInputSettings = Bool;
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
users.getFullUser#ca30a5b1 id:InputUser = UserFull;
contacts.getStatuses#c4a353ee = Vector<ContactStatus>;
contacts.getContacts#22c6aa08 hash:string = contacts.Contacts;
contacts.importContacts#da30b32d contacts:Vector<InputContact> replace:Bool = contacts.ImportedContacts;
contacts.getSuggested#cd773428 limit:int = contacts.Suggested;
contacts.deleteContact#8e953744 id:InputUser = contacts.Link;
contacts.deleteContacts#59ab389e id:Vector<InputUser> = Bool;
contacts.block#332b49fc id:InputUser = Bool;
contacts.unblock#e54100bd id:InputUser = Bool;
contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked;
contacts.exportCard#84e53737 = Vector<int>;
contacts.importCard#4fe196fe export_card:Vector<int> = User;
contacts.search#11f812d8 q:string limit:int = contacts.Found;
contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer;
messages.getMessages#4222fa74 id:Vector<int> = messages.Messages;
messages.getDialogs#6b47f94d offset_date:int offset_id:int offset_peer:InputPeer limit:int = messages.Dialogs;
messages.getHistory#8a8ec2da peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
messages.search#d4569248 flags:# important_only:flags.0?true peer:InputPeer q:string filter:MessagesFilter min_date:int max_date:int offset:int max_id:int limit:int = messages.Messages;
messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages;
messages.deleteHistory#b7c13bd9 peer:InputPeer max_id:int = messages.AffectedHistory;
messages.deleteMessages#a5f18925 id:Vector<int> = messages.AffectedMessages;
messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool;
messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true broadcast:flags.4?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates;
messages.sendMedia#c8f16791 flags:# broadcast:flags.4?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia random_id:long reply_markup:flags.2?ReplyMarkup = Updates;
messages.forwardMessages#708e0195 flags:# broadcast:flags.4?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer = Updates;
messages.reportSpam#cf1592db peer:InputPeer = Bool;
messages.getChats#3c6aa187 id:Vector<int> = messages.Chats;
messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull;
messages.editChatTitle#dc452855 chat_id:int title:string = Updates;
messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates;
messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates;
messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates;
messages.createChat#9cb126e users:Vector<InputUser> title:string = Updates;
messages.forwardMessage#33963bf9 peer:InputPeer id:int random_id:long = Updates;
messages.sendBroadcast#bf73f4da contacts:Vector<InputUser> random_id:Vector<long> message:string media:InputMedia = Updates;
messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig;
messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat;
messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat;
messages.discardEncryption#edd923c5 chat_id:int = Bool;
messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool;
messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool;
messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage;
messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage;
messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage;
messages.receivedQueue#55a5bb66 max_qts:int = Vector<long>;
messages.readMessageContents#36a73f77 id:Vector<int> = messages.AffectedMessages;
messages.getStickers#ae22e045 emoticon:string hash:string = messages.Stickers;
messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers;
messages.getWebPagePreview#25223e24 message:string = MessageMedia;
messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite;
messages.checkChatInvite#3eadb1bb hash:string = ChatInvite;
messages.importChatInvite#6c50051c hash:string = Updates;
messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet;
messages.installStickerSet#7b30c3a6 stickerset:InputStickerSet disabled:Bool = Bool;
messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool;
messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates;
messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector<int> increment:Bool = Vector<int>;
messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates;
messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool;
messages.migrateChat#15a3b8e3 chat_id:int = Updates;
messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
messages.reorderStickerSets#9fcfbc30 order:Vector<long> = Bool;
messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document;
messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs;
messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs;
messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool;
messages.getInlineBotResults#9324600d bot:InputUser query:string offset:string = messages.BotResults;
messages.setInlineBotResults#3f23ec12 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector<InputBotInlineResult> cache_time:int next_offset:flags.2?string = Bool;
messages.sendInlineBotResult#b16e06fe flags:# broadcast:flags.4?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates;
updates.getState#edd4882a = updates.State;
updates.getDifference#a041495 pts:int date:int qts:int = updates.Difference;
updates.getChannelDifference#bb32d7c0 channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference;
photos.updateProfilePhoto#eef579a0 id:InputPhoto crop:InputPhotoCrop = UserProfilePhoto;
photos.uploadProfilePhoto#d50f9c88 file:InputFile caption:string geo_point:InputGeoPoint crop:InputPhotoCrop = photos.Photo;
photos.deletePhotos#87cf7f2f id:Vector<InputPhoto> = Vector<long>;
photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos;
upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool;
upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File;
upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool;
help.getConfig#c4f9186b = Config;
help.getNearestDc#1fb33026 = NearestDc;
help.getAppUpdate#c812ac7e device_model:string system_version:string app_version:string lang_code:string = help.AppUpdate;
help.saveAppLog#6f02f748 events:Vector<InputAppEvent> = Bool;
help.getInviteText#a4a95186 lang_code:string = help.InviteText;
help.getSupport#9cdf08cd = help.Support;
help.getAppChangelog#5bab7fb2 device_model:string system_version:string app_version:string lang_code:string = help.AppChangelog;
help.getTermsOfService#37d78f83 lang_code:string = help.TermsOfService;
channels.getDialogs#a9d3d249 offset:int limit:int = messages.Dialogs;
channels.getImportantHistory#ddb929cb channel:InputChannel offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool;
channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages;
channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory;
channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector<int> = Bool;
channels.getMessages#93d7b347 channel:InputChannel id:Vector<int> = messages.Messages;
channels.getParticipants#24d98f92 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int = channels.ChannelParticipants;
channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant;
channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats;
channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull;
channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates;
channels.editAbout#13e27f1e channel:InputChannel about:string = Bool;
channels.editAdmin#eb7611d0 channel:InputChannel user_id:InputUser role:ChannelParticipantRole = Updates;
channels.editTitle#566decd0 channel:InputChannel title:string = Updates;
channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates;
channels.toggleComments#aaa29e88 channel:InputChannel enabled:Bool = Updates;
channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool;
channels.updateUsername#3514b3de channel:InputChannel username:string = Bool;
channels.joinChannel#24b524c5 channel:InputChannel = Updates;
channels.leaveChannel#f836aa95 channel:InputChannel = Updates;
channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector<InputUser> = Updates;
channels.kickFromChannel#a672de14 channel:InputChannel user_id:InputUser kicked:Bool = Updates;
channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite;
channels.deleteChannel#c0111fe3 channel:InputChannel = Updates;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,934 +0,0 @@
///////////////////////////////
/// Authorization key creation
///////////////////////////////
//resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector<long> = ResPQ;
//p_q_inner_data#83c95aec pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data;
//server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params;
//server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params;
//server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:string g_a:string server_time:int = Server_DH_inner_data;
//client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:string = Client_DH_Inner_Data;
//dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer;
//dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer;
//dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = Set_client_DH_params_answer;
destroy_auth_key_ok#f660e1d4 = DestroyAuthKeyRes;
destroy_auth_key_none#0a9f2259 = DestroyAuthKeyRes;
destroy_auth_key_fail#ea109b13 = DestroyAuthKeyRes;
---functions---
//req_pq#60469778 nonce:int128 = ResPQ;
//req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params;
//set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:string = Set_client_DH_params_answer;
destroy_auth_key#d1435160 = DestroyAuthKeyRes;
///////////////////////////////
///////// Main application API
///////////////////////////////
---types---
boolFalse#bc799737 = Bool;
boolTrue#997275b5 = Bool;
true#3fedd339 = True;
vector#1cb5c415 {t:Type} # [ t ] = Vector t;
error#c4b9f9bb code:int text:string = Error;
null#56730bcc = Null;
inputPeerEmpty#7f3b18ea = InputPeer;
inputPeerSelf#7da07ec9 = InputPeer;
inputPeerChat#179be863 chat_id:int = InputPeer;
inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer;
inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer;
inputUserEmpty#b98886cf = InputUser;
inputUserSelf#f7c1b13f = InputUser;
inputUser#d8292816 user_id:int access_hash:long = InputUser;
inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact;
inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile;
inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile;
inputMediaEmpty#9664f57f = InputMedia;
inputMediaUploadedPhoto#630c9af1 flags:# file:InputFile caption:string stickers:flags.0?Vector<InputDocument> = InputMedia;
inputMediaPhoto#e9bfb4f3 id:InputPhoto caption:string = InputMedia;
inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia;
inputMediaContact#a6e45987 phone_number:string first_name:string last_name:string = InputMedia;
inputMediaUploadedDocument#d070f1e9 flags:# file:InputFile mime_type:string attributes:Vector<DocumentAttribute> caption:string stickers:flags.0?Vector<InputDocument> = InputMedia;
inputMediaUploadedThumbDocument#50d88cae flags:# file:InputFile thumb:InputFile mime_type:string attributes:Vector<DocumentAttribute> caption:string stickers:flags.0?Vector<InputDocument> = InputMedia;
inputMediaDocument#1a77f29c id:InputDocument caption:string = InputMedia;
inputMediaVenue#2827a81a geo_point:InputGeoPoint title:string address:string provider:string venue_id:string = InputMedia;
inputMediaGifExternal#4843b0fd url:string q:string = InputMedia;
inputMediaPhotoExternal#b55f4f18 url:string caption:string = InputMedia;
inputMediaDocumentExternal#e5e9607c url:string caption:string = InputMedia;
inputMediaGame#d33f43f3 id:InputGame = InputMedia;
inputChatPhotoEmpty#1ca48f57 = InputChatPhoto;
inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto;
inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto;
inputGeoPointEmpty#e4c123d6 = InputGeoPoint;
inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint;
inputPhotoEmpty#1cd7bf0d = InputPhoto;
inputPhoto#fb95c6c4 id:long access_hash:long = InputPhoto;
inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLocation;
inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation;
inputDocumentFileLocation#430f0724 id:long access_hash:long version:int = InputFileLocation;
inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent;
peerUser#9db1bc6d user_id:int = Peer;
peerChat#bad0e5bb chat_id:int = Peer;
peerChannel#bddde532 channel_id:int = Peer;
storage.fileUnknown#aa963b05 = storage.FileType;
storage.fileJpeg#7efe0e = storage.FileType;
storage.fileGif#cae1aadf = storage.FileType;
storage.filePng#a4f63c0 = storage.FileType;
storage.filePdf#ae1e508d = storage.FileType;
storage.fileMp3#528a0677 = storage.FileType;
storage.fileMov#4b09ebbc = storage.FileType;
storage.filePartial#40bc6f52 = storage.FileType;
storage.fileMp4#b3cea0e4 = storage.FileType;
storage.fileWebp#1081464c = storage.FileType;
fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation;
fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation;
userEmpty#200250ba id:int = User;
user#d10d979a flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string = User;
userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto;
userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto;
userStatusEmpty#9d05049 = UserStatus;
userStatusOnline#edb93949 expires:int = UserStatus;
userStatusOffline#8c703f was_online:int = UserStatus;
userStatusRecently#e26f42f1 = UserStatus;
userStatusLastWeek#7bf09fc = UserStatus;
userStatusLastMonth#77ebc742 = UserStatus;
chatEmpty#9ba2d800 id:int = Chat;
chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat;
chatForbidden#7328bdb id:int title:string = Chat;
channel#a14dca52 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true editor:flags.3?true moderator:flags.4?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string = Chat;
channelForbidden#8537784f flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string = Chat;
chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> = ChatFull;
channelFull#c3d5512f flags:# can_view_participants:flags.3?true can_set_username:flags.6?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int = ChatFull;
chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant;
chatParticipantCreator#da13538a user_id:int = ChatParticipant;
chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant;
chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants;
chatParticipants#3f460fed chat_id:int participants:Vector<ChatParticipant> version:int = ChatParticipants;
chatPhotoEmpty#37c1011c = ChatPhoto;
chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto;
messageEmpty#83e5de54 id:int = Message;
message#c09be45f flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int = Message;
messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message;
messageMediaEmpty#3ded6320 = MessageMedia;
messageMediaPhoto#3d8ce53d photo:Photo caption:string = MessageMedia;
messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia;
messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:string user_id:int = MessageMedia;
messageMediaUnsupported#9f84f49e = MessageMedia;
messageMediaDocument#f3e02ea8 document:Document caption:string = MessageMedia;
messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia;
messageMediaVenue#7912b71f geo:GeoPoint title:string address:string provider:string venue_id:string = MessageMedia;
messageMediaGame#fdb19008 game:Game = MessageMedia;
messageActionEmpty#b6aef7b0 = MessageAction;
messageActionChatCreate#a6638b9a title:string users:Vector<int> = MessageAction;
messageActionChatEditTitle#b5a1ce5a title:string = MessageAction;
messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction;
messageActionChatDeletePhoto#95e3fbef = MessageAction;
messageActionChatAddUser#488a7337 users:Vector<int> = MessageAction;
messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction;
messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction;
messageActionChannelCreate#95d2ac92 title:string = MessageAction;
messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction;
messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction;
messageActionPinMessage#94bd38ed = MessageAction;
messageActionHistoryClear#9fbab604 = MessageAction;
messageActionGameScore#92a72876 game_id:long score:int = MessageAction;
messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction;
dialog#66ffba14 flags:# pinned:flags.2?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog;
photoEmpty#2331b22d id:long = Photo;
photo#9288dd29 flags:# has_stickers:flags.0?true id:long access_hash:long date:int sizes:Vector<PhotoSize> = Photo;
photoSizeEmpty#e17e23c type:string = PhotoSize;
photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize;
photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize;
geoPointEmpty#1117dd5f = GeoPoint;
geoPoint#2049d70c long:double lat:double = GeoPoint;
auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone;
auth.sentCode#5e002502 flags:# phone_registered:flags.0?true type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode;
auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization;
auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization;
inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer;
inputNotifyUsers#193b4417 = InputNotifyPeer;
inputNotifyChats#4a95e84e = InputNotifyPeer;
inputNotifyAll#a429b886 = InputNotifyPeer;
inputPeerNotifyEventsEmpty#f03064d8 = InputPeerNotifyEvents;
inputPeerNotifyEventsAll#e86a2c74 = InputPeerNotifyEvents;
inputPeerNotifySettings#38935eb2 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = InputPeerNotifySettings;
peerNotifyEventsEmpty#add53cb3 = PeerNotifyEvents;
peerNotifyEventsAll#6d1ded88 = PeerNotifyEvents;
peerNotifySettingsEmpty#70a68512 = PeerNotifySettings;
peerNotifySettings#9acda4c0 flags:# show_previews:flags.0?true silent:flags.1?true mute_until:int sound:string = PeerNotifySettings;
peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings;
wallPaper#ccb03657 id:int title:string sizes:Vector<PhotoSize> color:int = WallPaper;
wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper;
inputReportReasonSpam#58dbcab8 = ReportReason;
inputReportReasonViolence#1e22c78d = ReportReason;
inputReportReasonPornography#2e59d922 = ReportReason;
inputReportReasonOther#e1746d0a text:string = ReportReason;
userFull#f220f3f flags:# blocked:flags.0?true phone_calls_available:flags.4?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo common_chats_count:int = UserFull;
contact#f911c994 user_id:int mutual:Bool = Contact;
importedContact#d0028438 user_id:int client_id:long = ImportedContact;
contactBlocked#561bc879 user_id:int date:int = ContactBlocked;
contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus;
contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link;
contacts.contactsNotModified#b74ba9d2 = contacts.Contacts;
contacts.contacts#6f8b8cb2 contacts:Vector<Contact> users:Vector<User> = contacts.Contacts;
contacts.importedContacts#ad524315 imported:Vector<ImportedContact> retry_contacts:Vector<long> users:Vector<User> = contacts.ImportedContacts;
contacts.blocked#1c138d15 blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked;
contacts.blockedSlice#900802a1 count:int blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked;
messages.dialogs#15ba6c40 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
messages.dialogsSlice#71e094f3 count:int dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
messages.messages#8c718e87 messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.messagesSlice#b446ae3 count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.channelMessages#99262e37 flags:# pts:int count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.chats#64ff9fd5 chats:Vector<Chat> = messages.Chats;
messages.chatsSlice#9cd81144 count:int chats:Vector<Chat> = messages.Chats;
messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector<Chat> users:Vector<User> = messages.ChatFull;
messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory;
inputMessagesFilterEmpty#57e2f66c = MessagesFilter;
inputMessagesFilterPhotos#9609a51c = MessagesFilter;
inputMessagesFilterVideo#9fc00e65 = MessagesFilter;
inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter;
inputMessagesFilterPhotoVideoDocuments#d95e73bb = MessagesFilter;
inputMessagesFilterDocument#9eddf188 = MessagesFilter;
inputMessagesFilterUrl#7ef0dd87 = MessagesFilter;
inputMessagesFilterGif#ffc86587 = MessagesFilter;
inputMessagesFilterVoice#50f5c392 = MessagesFilter;
inputMessagesFilterMusic#3751b49e = MessagesFilter;
inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter;
inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter;
updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update;
updateMessageID#4e90bfd6 id:int random_id:long = Update;
updateDeleteMessages#a20db0e5 messages:Vector<int> pts:int pts_count:int = Update;
updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update;
updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update;
updateChatParticipants#7761198 participants:ChatParticipants = Update;
updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update;
updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update;
updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update;
updateContactRegistered#2575bbb9 user_id:int date:int = Update;
updateContactLink#9d2e67c5 user_id:int my_link:ContactLink foreign_link:ContactLink = Update;
updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update;
updateEncryptedChatTyping#1710f156 chat_id:int = Update;
updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update;
updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update;
updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update;
updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update;
updateDcOptions#8e5e9873 dc_options:Vector<DcOption> = Update;
updateUserBlocked#80ece81a user_id:int blocked:Bool = Update;
updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update;
updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector<MessageEntity> = Update;
updatePrivacy#ee3b272a key:PrivacyKey rules:Vector<PrivacyRule> = Update;
updateUserPhone#12b9417b user_id:int phone:string = Update;
updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update;
updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update;
updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update;
updateReadMessagesContents#68c13933 messages:Vector<int> pts:int pts_count:int = Update;
updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update;
updateChannel#b6d45656 channel_id:int = Update;
updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update;
updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update;
updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector<int> pts:int pts_count:int = Update;
updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update;
updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update;
updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update;
updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update;
updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector<long> = Update;
updateStickerSets#43ae3dec = Update;
updateSavedGifs#9375341e = Update;
updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo:flags.0?GeoPoint offset:string = Update;
updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update;
updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update;
updateChannelPinnedMessage#98592475 channel_id:int id:int = Update;
updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update;
updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update;
updateInlineBotCallbackQuery#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update;
updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update;
updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update;
updateReadFeaturedStickers#571d2742 = Update;
updateRecentStickers#9a422c20 = Update;
updateConfig#a229dd06 = Update;
updatePtsChanged#3354678f = Update;
updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update;
updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update;
updateDialogPinned#d711a2cc flags:# pinned:flags.0?true peer:Peer = Update;
updatePinnedDialogs#d8caf68d flags:# order:flags.0?Vector<Peer> = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference;
updates.difference#f49ca0 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> state:updates.State = updates.Difference;
updates.differenceSlice#a8fb1981 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> intermediate_state:updates.State = updates.Difference;
updates.differenceTooLong#4afe8f6d pts:int = updates.Difference;
updatesTooLong#e317af7e = Updates;
updateShortMessage#914fbf11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates;
updateShortChatMessage#16812688 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates;
updateShort#78d4dec1 update:Update date:int = Updates;
updatesCombined#725b04c3 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq_start:int seq:int = Updates;
updates#74ae4240 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq:int = Updates;
updateShortSentMessage#11f1331c flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector<MessageEntity> = Updates;
photos.photos#8dca6aa5 photos:Vector<Photo> users:Vector<User> = photos.Photos;
photos.photosSlice#15051f54 count:int photos:Vector<Photo> users:Vector<User> = photos.Photos;
photos.photo#20212ca8 photo:Photo users:Vector<User> = photos.Photo;
upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File;
dcOption#5d8c6cc flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true id:int ip_address:string port:int = DcOption;
config#3af6fb5f flags:# phonecalls_enabled:flags.1?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int rating_e_decay:int stickers_recent_limit:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int disabled_features:Vector<DisabledFeature> = Config;
nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
help.appUpdate#8987f311 id:int critical:Bool url:string text:string = help.AppUpdate;
help.noAppUpdate#c45a6536 = help.AppUpdate;
help.inviteText#18cb9f78 message:string = help.InviteText;
encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat;
encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat;
encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat;
encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat;
encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat;
inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat;
encryptedFileEmpty#c21f497e = EncryptedFile;
encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile;
inputEncryptedFileEmpty#1837c364 = InputEncryptedFile;
inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile;
inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile;
inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile;
encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage;
encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage;
messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig;
messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig;
messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage;
messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage;
inputDocumentEmpty#72f0eaae = InputDocument;
inputDocument#18798952 id:long access_hash:long = InputDocument;
documentEmpty#36f8c871 id:long = Document;
document#87232bc7 id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int version:int attributes:Vector<DocumentAttribute> = Document;
help.support#17c6b5f6 phone_number:string user:User = help.Support;
notifyPeer#9fd40bd8 peer:Peer = NotifyPeer;
notifyUsers#b4c83b4c = NotifyPeer;
notifyChats#c007cec3 = NotifyPeer;
notifyAll#74d07c60 = NotifyPeer;
sendMessageTypingAction#16bf744e = SendMessageAction;
sendMessageCancelAction#fd5ec8f5 = SendMessageAction;
sendMessageRecordVideoAction#a187d66f = SendMessageAction;
sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction;
sendMessageRecordAudioAction#d52f73f7 = SendMessageAction;
sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction;
sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction;
sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction;
sendMessageGeoLocationAction#176f8ba1 = SendMessageAction;
sendMessageChooseContactAction#628cbc6f = SendMessageAction;
sendMessageGamePlayAction#dd6a8f48 = SendMessageAction;
contacts.found#1aa1f784 results:Vector<Peer> chats:Vector<Chat> users:Vector<User> = contacts.Found;
inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey;
inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey;
inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey;
privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey;
privacyKeyChatInvite#500e6dfa = PrivacyKey;
privacyKeyPhoneCall#3d662b7b = PrivacyKey;
inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule;
inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule;
inputPrivacyValueAllowUsers#131cc67f users:Vector<InputUser> = InputPrivacyRule;
inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule;
inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule;
inputPrivacyValueDisallowUsers#90110467 users:Vector<InputUser> = InputPrivacyRule;
privacyValueAllowContacts#fffe1bac = PrivacyRule;
privacyValueAllowAll#65427b82 = PrivacyRule;
privacyValueAllowUsers#4d5bbe0c users:Vector<int> = PrivacyRule;
privacyValueDisallowContacts#f888fa1a = PrivacyRule;
privacyValueDisallowAll#8b73e763 = PrivacyRule;
privacyValueDisallowUsers#c7f49b7 users:Vector<int> = PrivacyRule;
account.privacyRules#554abb6f rules:Vector<PrivacyRule> users:Vector<User> = account.PrivacyRules;
accountDaysTTL#b8d0afdf days:int = AccountDaysTTL;
documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute;
documentAttributeAnimated#11b58939 = DocumentAttribute;
documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute;
documentAttributeVideo#5910cccb duration:int w:int h:int = DocumentAttribute;
documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute;
documentAttributeFilename#15590068 file_name:string = DocumentAttribute;
documentAttributeHasStickers#9801d2f7 = DocumentAttribute;
messages.stickersNotModified#f1749a22 = messages.Stickers;
messages.stickers#8a8ecd32 hash:string stickers:Vector<Document> = messages.Stickers;
stickerPack#12b299d4 emoticon:string documents:Vector<long> = StickerPack;
messages.allStickersNotModified#e86602c3 = messages.AllStickers;
messages.allStickers#edfd405f hash:int sets:Vector<StickerSet> = messages.AllStickers;
disabledFeature#ae636f24 feature:string description:string = DisabledFeature;
messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages;
contactLinkUnknown#5f4f9247 = ContactLink;
contactLinkNone#feedd3ad = ContactLink;
contactLinkHasPhone#268f3f59 = ContactLink;
contactLinkContact#d502c2d0 = ContactLink;
webPageEmpty#eb1477e8 id:long = WebPage;
webPagePending#c586da1c id:long date:int = WebPage;
webPage#5f07b4bc flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page = WebPage;
webPageNotModified#85849473 = WebPage;
authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization;
account.authorizations#1250abde authorizations:Vector<Authorization> = account.Authorizations;
account.noPassword#96dabc18 new_salt:bytes email_unconfirmed_pattern:string = account.Password;
account.password#7c18141c current_salt:bytes new_salt:bytes hint:string has_recovery:Bool email_unconfirmed_pattern:string = account.Password;
account.passwordSettings#b7b72ab3 email:string = account.PasswordSettings;
account.passwordInputSettings#86916deb flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string = account.PasswordInputSettings;
auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery;
receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage;
chatInviteEmpty#69df3769 = ExportedChatInvite;
chatInviteExported#fc2e05bc link:string = ExportedChatInvite;
chatInviteAlready#5a686d7c chat:Chat = ChatInvite;
chatInvite#db74f558 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants_count:int participants:flags.4?Vector<User> = ChatInvite;
inputStickerSetEmpty#ffb62b95 = InputStickerSet;
inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
stickerSet#cd303b41 flags:# installed:flags.0?true archived:flags.1?true official:flags.2?true masks:flags.3?true id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet;
messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
botCommand#c27ac8c7 command:string description:string = BotCommand;
botInfo#98e81d3a user_id:int description:string commands:Vector<BotCommand> = BotInfo;
keyboardButton#a2fa4880 text:string = KeyboardButton;
keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton;
keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton;
keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton;
keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton;
keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton;
keyboardButtonGame#50f41ccf text:string = KeyboardButton;
keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow;
replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup;
replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup;
replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector<KeyboardButtonRow> = ReplyMarkup;
replyInlineMarkup#48a30254 rows:Vector<KeyboardButtonRow> = ReplyMarkup;
help.appChangelogEmpty#af7e0394 = help.AppChangelog;
help.appChangelog#2a137e7c message:string media:MessageMedia entities:Vector<MessageEntity> = help.AppChangelog;
messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity;
messageEntityMention#fa04579d offset:int length:int = MessageEntity;
messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity;
messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity;
messageEntityUrl#6ed02538 offset:int length:int = MessageEntity;
messageEntityEmail#64e475c2 offset:int length:int = MessageEntity;
messageEntityBold#bd610bc9 offset:int length:int = MessageEntity;
messageEntityItalic#826f8b60 offset:int length:int = MessageEntity;
messageEntityCode#28a20571 offset:int length:int = MessageEntity;
messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity;
messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity;
messageEntityMentionName#352dca58 offset:int length:int user_id:int = MessageEntity;
inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity;
inputChannelEmpty#ee8c1e86 = InputChannel;
inputChannel#afeb712e channel_id:int access_hash:long = InputChannel;
contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector<Chat> users:Vector<User> = contacts.ResolvedPeer;
messageRange#ae30253 min_id:int max_id:int = MessageRange;
updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference;
updates.channelDifferenceTooLong#410dee07 flags:# final:flags.0?true pts:int timeout:flags.1?int top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference;
updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector<Message> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference;
channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter;
channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector<MessageRange> = ChannelMessagesFilter;
channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant;
channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant;
channelParticipantModerator#91057fef user_id:int inviter_id:int date:int = ChannelParticipant;
channelParticipantEditor#98192d61 user_id:int inviter_id:int date:int = ChannelParticipant;
channelParticipantKicked#8cc5e69a user_id:int kicked_by:int date:int = ChannelParticipant;
channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant;
channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter;
channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter;
channelParticipantsKicked#3c37bb7a = ChannelParticipantsFilter;
channelParticipantsBots#b0d1865b = ChannelParticipantsFilter;
channelRoleEmpty#b285a0c6 = ChannelParticipantRole;
channelRoleModerator#9618d975 = ChannelParticipantRole;
channelRoleEditor#820bfe8c = ChannelParticipantRole;
channels.channelParticipants#f56ee2a8 count:int participants:Vector<ChannelParticipant> users:Vector<User> = channels.ChannelParticipants;
channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector<User> = channels.ChannelParticipant;
help.termsOfService#f1ee3e90 text:string = help.TermsOfService;
foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif;
foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif;
messages.foundGifs#450a1c0a next_offset:int results:Vector<FoundGif> = messages.FoundGifs;
messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs;
messages.savedGifs#2e0709a5 hash:int gifs:Vector<Document> = messages.SavedGifs;
inputBotInlineMessageMediaAuto#292fed13 flags:# caption:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageMediaGeo#f4a59de1 flags:# geo_point:InputGeoPoint reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageMediaVenue#aaafadc8 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageMediaContact#2daf01a7 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineResult#2cbbe15a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:InputBotInlineMessage = InputBotInlineResult;
inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult;
inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult;
inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult;
botInlineMessageMediaAuto#a74b15b flags:# caption:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageMediaGeo#3a8fd8b8 flags:# geo:GeoPoint reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageMediaVenue#4366232e flags:# geo:GeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageMediaContact#35edb4d4 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineResult#9bebaeb9 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:BotInlineMessage = BotInlineResult;
botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult;
messages.botResults#ccd3563d flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector<BotInlineResult> cache_time:int = messages.BotResults;
exportedMessageLink#1f486803 link:string = ExportedMessageLink;
messageFwdHeader#c786ddcb flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int = MessageFwdHeader;
auth.codeTypeSms#72a3158c = auth.CodeType;
auth.codeTypeCall#741cd3e3 = auth.CodeType;
auth.codeTypeFlashCall#226ccefb = auth.CodeType;
auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType;
auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType;
auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType;
auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType;
messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer;
messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData;
inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID;
inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM;
messages.peerDialogs#3371c354 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> state:updates.State = messages.PeerDialogs;
topPeer#edcdc05b peer:Peer rating:double = TopPeer;
topPeerCategoryBotsPM#ab661b5b = TopPeerCategory;
topPeerCategoryBotsInline#148677e2 = TopPeerCategory;
topPeerCategoryCorrespondents#637b7ed = TopPeerCategory;
topPeerCategoryGroups#bd17a14a = TopPeerCategory;
topPeerCategoryChannels#161d9628 = TopPeerCategory;
topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector<TopPeer> = TopPeerCategoryPeers;
contacts.topPeersNotModified#de266ef5 = contacts.TopPeers;
contacts.topPeers#70b772a8 categories:Vector<TopPeerCategoryPeers> chats:Vector<Chat> users:Vector<User> = contacts.TopPeers;
draftMessageEmpty#ba4baec5 = DraftMessage;
draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector<MessageEntity> date:int = DraftMessage;
messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers;
messages.featuredStickers#f89d88e5 hash:int sets:Vector<StickerSetCovered> unread:Vector<long> = messages.FeaturedStickers;
messages.recentStickersNotModified#b17f890 = messages.RecentStickers;
messages.recentStickers#5ce20970 hash:int stickers:Vector<Document> = messages.RecentStickers;
messages.archivedStickers#4fcba9c8 count:int sets:Vector<StickerSetCovered> = messages.ArchivedStickers;
messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult;
messages.stickerSetInstallResultArchive#35e410a8 sets:Vector<StickerSetCovered> = messages.StickerSetInstallResult;
stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered;
stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector<Document> = StickerSetCovered;
maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords;
inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia;
inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia;
game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game;
inputGameID#32c3e77 id:long access_hash:long = InputGame;
inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame;
highScore#58fffcd0 pos:int user_id:int score:int = HighScore;
messages.highScores#9a3bfd99 scores:Vector<HighScore> users:Vector<User> = messages.HighScores;
textEmpty#dc3d824f = RichText;
textPlain#744694e0 text:string = RichText;
textBold#6724abc4 text:RichText = RichText;
textItalic#d912a59c text:RichText = RichText;
textUnderline#c12622c4 text:RichText = RichText;
textStrike#9bf8bb95 text:RichText = RichText;
textFixed#6c3f19b9 text:RichText = RichText;
textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText;
textEmail#de5a0dd6 text:RichText email:string = RichText;
textConcat#7e6260d7 texts:Vector<RichText> = RichText;
pageBlockUnsupported#13567e8a = PageBlock;
pageBlockTitle#70abc3fd text:RichText = PageBlock;
pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock;
pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock;
pageBlockHeader#bfd064ec text:RichText = PageBlock;
pageBlockSubheader#f12bb6e1 text:RichText = PageBlock;
pageBlockParagraph#467a0766 text:RichText = PageBlock;
pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock;
pageBlockFooter#48870999 text:RichText = PageBlock;
pageBlockDivider#db20b188 = PageBlock;
pageBlockAnchor#ce0d37b0 name:string = PageBlock;
pageBlockList#3a58c7f4 ordered:Bool items:Vector<RichText> = PageBlock;
pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock;
pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock;
pageBlockPhoto#e9c69982 photo_id:long caption:RichText = PageBlock;
pageBlockVideo#d9d71866 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:RichText = PageBlock;
pageBlockCover#39f23300 cover:PageBlock = PageBlock;
pageBlockEmbed#cde200d1 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:int h:int caption:RichText = PageBlock;
pageBlockEmbedPost#292c7be9 url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector<PageBlock> caption:RichText = PageBlock;
pageBlockCollage#8b31c4f items:Vector<PageBlock> caption:RichText = PageBlock;
pageBlockSlideshow#130c8963 items:Vector<PageBlock> caption:RichText = PageBlock;
pagePart#8dee6c44 blocks:Vector<PageBlock> photos:Vector<Photo> videos:Vector<Document> = Page;
pageFull#d7a19d69 blocks:Vector<PageBlock> photos:Vector<Photo> videos:Vector<Document> = Page;
inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall;
phoneCallEmpty#5366c915 id:long = PhoneCall;
phoneCallWaiting#1b8f4ad1 flags:# id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall;
phoneCallRequested#6c448ae8 id:long access_hash:long date:int admin_id:int participant_id:int g_a:bytes protocol:PhoneCallProtocol = PhoneCall;
phoneCall#ffe6ab67 id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connection:PhoneConnection alternative_connections:Vector<PhoneConnection> start_date:int = PhoneCall;
phoneCallDiscarded#50ca4de1 flags:# id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall;
phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection;
phoneCallProtocol#a2bb35cb flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int = PhoneCallProtocol;
phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector<User> = phone.PhoneCall;
phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason;
phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason;
phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason;
phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector<long> query:!X = X;
initConnection#69796de9 {X:Type} api_id:int device_model:string system_version:string app_version:string lang_code:string query:!X = X;
invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X;
invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X;
auth.checkPhone#6fe51dfb phone_number:string = auth.CheckedPhone;
auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode;
auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization;
auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization;
auth.logOut#5717da40 = Bool;
auth.resetAuthorizations#9fab0d1a = Bool;
auth.sendInvites#771c1d97 phone_numbers:Vector<string> message:string = Bool;
auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization;
auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization;
auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool;
auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization;
auth.checkPassword#a63011e password_hash:bytes = auth.Authorization;
auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery;
auth.recoverPassword#4ea56e92 code:string = auth.Authorization;
auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode;
auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool;
auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector<long> = Bool;
account.registerDevice#637ea878 token_type:int token:string = Bool;
account.unregisterDevice#65c55b40 token_type:int token:string = Bool;
account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool;
account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings;
account.resetNotifySettings#db7e1747 = Bool;
account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User;
account.updateStatus#6628562c offline:Bool = Bool;
account.getWallPapers#c04cfac2 = Vector<WallPaper>;
account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool;
account.checkUsername#2714d86c username:string = Bool;
account.updateUsername#3e0bdd7c username:string = User;
account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules;
account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector<InputPrivacyRule> = account.PrivacyRules;
account.deleteAccount#418d4e0b reason:string = Bool;
account.getAccountTTL#8fc711d = AccountDaysTTL;
account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool;
account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode;
account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User;
account.updateDeviceLocked#38df3532 period:int = Bool;
account.getAuthorizations#e320c158 = account.Authorizations;
account.resetAuthorization#df77f3bc hash:long = Bool;
account.getPassword#548a30f5 = account.Password;
account.getPasswordSettings#bc8d11bb current_password_hash:bytes = account.PasswordSettings;
account.updatePasswordSettings#fa7c4b86 current_password_hash:bytes new_settings:account.PasswordInputSettings = Bool;
account.sendConfirmPhoneCode#1516d7bd flags:# allow_flashcall:flags.0?true hash:string current_number:flags.0?Bool = auth.SentCode;
account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool;
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
users.getFullUser#ca30a5b1 id:InputUser = UserFull;
contacts.getStatuses#c4a353ee = Vector<ContactStatus>;
contacts.getContacts#22c6aa08 hash:string = contacts.Contacts;
contacts.importContacts#da30b32d contacts:Vector<InputContact> replace:Bool = contacts.ImportedContacts;
contacts.deleteContact#8e953744 id:InputUser = contacts.Link;
contacts.deleteContacts#59ab389e id:Vector<InputUser> = Bool;
contacts.block#332b49fc id:InputUser = Bool;
contacts.unblock#e54100bd id:InputUser = Bool;
contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked;
contacts.exportCard#84e53737 = Vector<int>;
contacts.importCard#4fe196fe export_card:Vector<int> = User;
contacts.search#11f812d8 q:string limit:int = contacts.Found;
contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer;
contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers;
contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool;
messages.getMessages#4222fa74 id:Vector<int> = messages.Messages;
messages.getDialogs#191ba9c5 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int = messages.Dialogs;
messages.getHistory#afa92846 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
messages.search#d4569248 flags:# peer:InputPeer q:string filter:MessagesFilter min_date:int max_date:int offset:int max_id:int limit:int = messages.Messages;
messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages;
messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true peer:InputPeer max_id:int = messages.AffectedHistory;
messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages;
messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool;
messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates;
messages.sendMedia#c8f16791 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia random_id:long reply_markup:flags.2?ReplyMarkup = Updates;
messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer = Updates;
messages.reportSpam#cf1592db peer:InputPeer = Bool;
messages.hideReportSpam#a8f1709b peer:InputPeer = Bool;
messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings;
messages.getChats#3c6aa187 id:Vector<int> = messages.Chats;
messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull;
messages.editChatTitle#dc452855 chat_id:int title:string = Updates;
messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates;
messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates;
messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates;
messages.createChat#9cb126e users:Vector<InputUser> title:string = Updates;
messages.forwardMessage#33963bf9 peer:InputPeer id:int random_id:long = Updates;
messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig;
messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat;
messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat;
messages.discardEncryption#edd923c5 chat_id:int = Bool;
messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool;
messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool;
messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage;
messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage;
messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage;
messages.receivedQueue#55a5bb66 max_qts:int = Vector<long>;
messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool;
messages.readMessageContents#36a73f77 id:Vector<int> = messages.AffectedMessages;
messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers;
messages.getWebPagePreview#25223e24 message:string = MessageMedia;
messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite;
messages.checkChatInvite#3eadb1bb hash:string = ChatInvite;
messages.importChatInvite#6c50051c hash:string = Updates;
messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet;
messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult;
messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool;
messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates;
messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector<int> increment:Bool = Vector<int>;
messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates;
messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool;
messages.migrateChat#15a3b8e3 chat_id:int = Updates;
messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector<long> = Bool;
messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document;
messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs;
messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs;
messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool;
messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults;
messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector<InputBotInlineResult> cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool;
messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string = Updates;
messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData;
messages.editMessage#ce91e4ca flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates;
messages.editInlineBotMessage#130c2c85 flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Bool;
messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer;
messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool;
messages.getPeerDialogs#2d9776b9 peers:Vector<InputPeer> = messages.PeerDialogs;
messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector<MessageEntity> = Bool;
messages.getAllDrafts#6a3f8d65 = Updates;
messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers;
messages.readFeaturedStickers#5b118126 id:Vector<long> = Bool;
messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = messages.RecentStickers;
messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool;
messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool;
messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers;
messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers;
messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector<StickerSetCovered>;
messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates;
messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool;
messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores;
messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores;
messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = messages.Chats;
messages.getAllChats#eba80ff0 except_ids:Vector<int> = messages.Chats;
messages.getWebPage#32ca8f91 url:string hash:int = WebPage;
messages.toggleDialogPin#3289be6a flags:# pinned:flags.0?true peer:InputPeer = Bool;
messages.reorderPinnedDialogs#959ff644 flags:# force:flags.0?true order:Vector<InputPeer> = Bool;
messages.getPinnedDialogs#e254d64e = messages.PeerDialogs;
updates.getState#edd4882a = updates.State;
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference;
photos.updateProfilePhoto#f0bb5152 id:InputPhoto = UserProfilePhoto;
photos.uploadProfilePhoto#4f32c098 file:InputFile = photos.Photo;
photos.deletePhotos#87cf7f2f id:Vector<InputPhoto> = Vector<long>;
photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos;
upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool;
upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload.File;
upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool;
help.getConfig#c4f9186b = Config;
help.getNearestDc#1fb33026 = NearestDc;
help.getAppUpdate#ae2de196 = help.AppUpdate;
help.saveAppLog#6f02f748 events:Vector<InputAppEvent> = Bool;
help.getInviteText#4d392343 = help.InviteText;
help.getSupport#9cdf08cd = help.Support;
help.getAppChangelog#b921197a = help.AppChangelog;
help.getTermsOfService#350170f3 = help.TermsOfService;
help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool;
channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool;
channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages;
channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory;
channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector<int> = Bool;
channels.getMessages#93d7b347 channel:InputChannel id:Vector<int> = messages.Messages;
channels.getParticipants#24d98f92 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int = channels.ChannelParticipants;
channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant;
channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats;
channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull;
channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates;
channels.editAbout#13e27f1e channel:InputChannel about:string = Bool;
channels.editAdmin#eb7611d0 channel:InputChannel user_id:InputUser role:ChannelParticipantRole = Updates;
channels.editTitle#566decd0 channel:InputChannel title:string = Updates;
channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates;
channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool;
channels.updateUsername#3514b3de channel:InputChannel username:string = Bool;
channels.joinChannel#24b524c5 channel:InputChannel = Updates;
channels.leaveChannel#f836aa95 channel:InputChannel = Updates;
channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector<InputUser> = Updates;
channels.kickFromChannel#a672de14 channel:InputChannel user_id:InputUser kicked:Bool = Updates;
channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite;
channels.deleteChannel#c0111fe3 channel:InputChannel = Updates;
channels.toggleInvites#49609307 channel:InputChannel enabled:Bool = Updates;
channels.exportMessageLink#c846d22d channel:InputChannel id:int = ExportedMessageLink;
channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates;
channels.updatePinnedMessage#a72ded52 flags:# silent:flags.0?true channel:InputChannel id:int = Updates;
channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats;
phone.requestCall#a41aa5e4 user_id:InputUser random_id:int g_a:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
phone.acceptCall#220f0b20 peer:InputPhoneCall g_b:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall;
phone.discardCall#5dfbcddc peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Bool;
phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool;
// LAYER 62

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More