Merge branch 'develop' into master

This commit is contained in:
Kay Marquardt 2020-05-14 12:05:08 +02:00 committed by GitHub
commit 2e446d91f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 602 additions and 305 deletions

View File

@ -1,64 +1,99 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>Bashbot README</title>
<style type="text/css">code{white-space: pre;}</style>
<style type="text/css">
div.sourceCode { overflow-x: auto; }
table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
margin: 0; padding: 0; vertical-align: baseline; border: none; }
table.sourceCode { width: 100%; line-height: 100%; }
td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
td.sourceCode { padding-left: 5px; }
code > span.kw { color: #007020; font-weight: bold; } /* Keyword */
code > span.dt { color: #902000; } /* DataType */
code > span.dv { color: #40a070; } /* DecVal */
code > span.bn { color: #40a070; } /* BaseN */
code > span.fl { color: #40a070; } /* Float */
code > span.ch { color: #4070a0; } /* Char */
code > span.st { color: #4070a0; } /* String */
code > span.co { color: #60a0b0; font-style: italic; } /* Comment */
code > span.ot { color: #007020; } /* Other */
code > span.al { color: #ff0000; font-weight: bold; } /* Alert */
code > span.fu { color: #06287e; } /* Function */
code > span.er { color: #ff0000; font-weight: bold; } /* Error */
code > span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
code > span.cn { color: #880000; } /* Constant */
code > span.sc { color: #4070a0; } /* SpecialChar */
code > span.vs { color: #4070a0; } /* VerbatimString */
code > span.ss { color: #bb6688; } /* SpecialString */
code > span.im { } /* Import */
code > span.va { color: #19177c; } /* Variable */
code > span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code > span.op { color: #666666; } /* Operator */
code > span.bu { } /* BuiltIn */
code > span.ex { } /* Extension */
code > span.pp { color: #bc7a00; } /* Preprocessor */
code > span.at { color: #7d9029; } /* Attribute */
code > span.do { color: #ba2121; font-style: italic; } /* Documentation */
code > span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code > span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
</style>
<style>
a.sourceLine { display: inline-block; line-height: 1.25; }
a.sourceLine { pointer-events: none; color: inherit; text-decoration: inherit; }
a.sourceLine:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode { white-space: pre; position: relative; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
code.sourceCode { white-space: pre-wrap; }
a.sourceLine { text-indent: -1em; padding-left: 1em; }
}
pre.numberSource a.sourceLine
{ position: relative; left: -4em; }
pre.numberSource a.sourceLine::before
{ content: attr(title);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; pointer-events: all; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
a.sourceLine::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
</head>
<body>
<div id="header">
<header id="title-block-header">
<h1 class="title">Bashbot README</h1>
</div>
<h2>
<img align="middle" src="https://raw.githubusercontent.com/odb/official-bash-logo/master/assets/Logos/Icons/PNG/64x64.png" > Bashbot - A Telegram bot written in bash.
</header>
<h2><img align="middle" src="https://raw.githubusercontent.com/odb/official-bash-logo/master/assets/Logos/Icons/PNG/64x64.png" >
Bashbot - A Telegram bot written in bash.
</h2>
<p>Written by Drew (<span class="citation">@topkecleon</span>), Daniil Gentili (<span class="citation">@danogentili</span>), and Kay M (<span class="citation">@gnadelwartz</span>).</p>
Written by Drew (@topkecleon), Daniil Gentili (@danogentili), and Kay M (@gnadelwartz).
<p>Contributions by JuanPotato, BigNerd95, TiagoDanin, and iicc1.</p>
<p>Released to the public domain wherever applicable. Elsewhere, consider it released under the <a href="http://www.wtfpl.net/txt/copying/">WTFPLv2</a>.</p>
<h2 id="prerequisites">Prerequisites</h2>
<h2>Prerequisites</h2>
<p>Uses <a href="http://github.com/dominictarr/JSON.sh">JSON.sh</a>, but no more TMUX.</p>
<p>Even bashbot is written in bash, it depends on commands typically availible in a Unix/Linux Environment. More concret on the common commands provided by <a href="https://en.wikipedia.org/wiki/List_of_GNU_Core_Utilities_commands">coreutils</a>, <a href="https://en.wikipedia.org/wiki/BusyBox#Commands">busybox</a> or <a href="https://landley.net/toybox/help.html">toybox</a>, see <a href="doc/7_develop.md#common-commands">Developer Notes</a></p>
<p>Bashbot <a href="https://github.com/topkecleon/telegram-bot-bash">Documentation</a> and <a href="https://github.com/topkecleon/telegram-bot-bash/releases">Downloads</a> are availible on www.github.com</p>
<h2 id="documentation">Documentation</h2>
<h2>Documentation</h2>
<ul>
<li><a href="https://core.telegram.org/bots">Introdution to Telegram Bots</a></li>
<li><a href="doc/0_install.md">Install Bashbot</a>
@ -114,14 +149,14 @@ code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Inf
</ul></li>
<li><a href="examples/README.md">Examples Dir</a></li>
</ul>
<h3 id="your-really-first-bashbot-in-a-nutshell">Your really first bashbot in a nutshell</h3>
<p>To install and run bashbot you need acess to a linux/unix/bsd command line. If you dont know how to get accces to a linux/unix/bsd like command line you should stop reading here :-(</p>
<p>In addition you need a <a href="https://telegram.org">Telegram client</a> and a mobile phone to <a href="https://telegramguide.com/create-a-telegram-account/">register an account</a>. If you dont want to register for Telegram you should stop reading here ;-)</p>
<p>After youre registered to Telegram send a message to <span class="citation">[@botfather]</span>(https://telegram.me/botfather), <a href="doc/1_firstbot.md">create a new Telegram Bot token</a> and write it down. You need the token to install the bot.</p>
<p>Now open a linux/unix/bsd terminal and check if bash is installed: <code>which bash &amp;&amp; echo &quot;bash installed!&quot;</code>. If you get an error message bash is not installed.</p>
<p>Create a new directory and change to it: <code>mkdir tbb; cd tbb</code> and download the latest *.tar.gz file from <a href="https://github.com/topkecleon/telegram-bot-bash/releases" class="uri">https://github.com/topkecleon/telegram-bot-bash/releases</a>. This can be done with the commands:</p>
<div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="fu">wget</span> -q https://github.com/<span class="va">$(</span><span class="fu">wget</span> -q https://github.com/topkecleon/telegram-bot-bash/releases/latest -O - <span class="kw">|</span> <span class="fu">egrep</span> <span class="st">&#39;/.*/.*/.*tar.gz&#39;</span> -o<span class="va">)</span></code></pre></div>
<p>Extract the *.tar.gz file and change to bashbot directory: <code>tar -xzf *.tar.gz; cd telegram-bot-bash</code>, install bashbot: <code>./bashbot.sh init</code> and enter your bot token when asked. All other questions can be answered by hitting the &lt;Return&gt; key.</p>
<h3>Your really first bashbot in a nutshell</h3>
<p>To install and run bashbot you need acess to a linux/unix/bsd command line. If you don't know how to get accces to a linux/unix/bsd like command line you should stop reading here :-(</p>
<p>In addition you need a <a href="https://telegram.org">Telegram client</a> and a mobile phone to <a href="https://telegramguide.com/create-a-telegram-account/">register an account</a>. If you don't want to register for Telegram you should stop reading here ;-)</p>
<p>After you're registered to Telegram send a message to <a href="https://telegram.me/botfather">@botfather</a>, <a href="doc/1_firstbot.md">create a new Telegram Bot token</a> and write it down. You need the token to install the bot.</p>
<p>Now open a linux/unix/bsd terminal and check if bash is installed: <code>which bash &amp;&amp; echo "bash installed!"</code>. If you get an error message bash is not installed.</p>
<p>Create a new directory and change to it: <code>mkdir tbb; cd tbb</code> and download the latest '*.tar.gz' file from <a href="https://github.com/topkecleon/telegram-bot-bash/releases">https://github.com/topkecleon/telegram-bot-bash/releases</a>. This can be done with the commands:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode bash"><code class="sourceCode bash"><a class="sourceLine" id="cb1-1" title="1"><span class="fu">wget</span> -q https://github.com/<span class="va">$(</span><span class="fu">wget</span> -q https://github.com/topkecleon/telegram-bot-bash/releases/latest -O - <span class="kw">|</span> <span class="fu">egrep</span> <span class="st">&#39;/.*/.*/.*tar.gz&#39;</span> -o<span class="va">)</span></a></code></pre></div>
<p>Extract the '*.tar.gz' file and change to bashbot directory: <code>tar -xzf *.tar.gz; cd telegram-bot-bash</code>, install bashbot: <code>./bashbot.sh init</code> and enter your bot token when asked. All other questions can be answered by hitting the &lt;Return&gt; key.</p>
<p>Thats all, now you can start your bot with <code>./bashbot.sh start</code> and send him messages:</p>
<pre><code>/start
@ -134,59 +169,60 @@ You are Botadmin
/info
his is bashbot, the Telegram bot written entirely in bash.
It features background tasks and interactive chats, and can serve as an interface for CLI programs.</code></pre>
It features background tasks and interactive chats, and can serve as an interface for CLI programs.
</code></pre>
<p>For more Information on how to install, customize and use your new bot, read the <a href="#Documentation">Documentation</a></p>
<hr />
<h2 id="security-considerations">Security Considerations</h2>
<h2>Security Considerations</h2>
<p>Running a Telegram Bot means it is connected to the public and you never know whats send to your Bot.</p>
<p>Bash scripts in general are not designed to be bullet proof, so consider this Bot as a proof of concept. Bash programmers often struggle with quoting hell and globbing, see <a href="https://unix.stackexchange.com/questions/171346/security-implications-of-forgetting-to-quote-a-variable-in-bash-posix-shells">Implications of wrong quoting</a></p>
<p>Whenever you are processing input from from untrusted sources (messages, files, network) you must be as carefull as possible, e.g. set IFS appropriate, disable globbing (set -f) and quote everthing. In addition delete unused scripts and examples from your Bot, e.g. scripts notify, calc, question, and disable all not used commands.</p>
<p>A powerful tool to improve your scripts is <code>shellcheck</code>. You can <a href="https://www.shellcheck.net/">use it online</a> or <a href="https://github.com/koalaman/shellcheck#installing">install shellcheck locally</a>. Shellcheck is used extensive in bashbot development to enshure a high code quality, e.g. its not allowed to push changes without passing all shellcheck tests. In addition bashbot has a <a href="doc/7_develop.md">test suite</a> to check if important functionality is working as expected.</p>
<h3 id="run-your-bot-as-a-restricted-user">Run your Bot as a restricted user</h3>
<p>Bash scripts in general are not designed to be bullet proof, so consider this Bot as a proof of concept. Bash programmers often struggle with 'quoting hell' and globbing, see <a href="https://unix.stackexchange.com/questions/171346/security-implications-of-forgetting-to-quote-a-variable-in-bash-posix-shells">Implications of wrong quoting</a></p>
<p>Whenever you are processing input from from untrusted sources (messages, files, network) you must be as carefull as possible, e.g. set IFS appropriate, disable globbing (set -f) and quote everthing. In addition delete unused scripts and examples from your Bot, e.g. scripts 'notify', 'calc', 'question', and disable all not used commands.</p>
<p>A powerful tool to improve your scripts is <code>shellcheck</code>. You can <a href="https://www.shellcheck.net/">use it online</a> or <a href="https://github.com/koalaman/shellcheck#installing">install shellcheck locally</a>. Shellcheck is used extensive in bashbot development to enshure a high code quality, e.g. it's not allowed to push changes without passing all shellcheck tests. In addition bashbot has a <a href="doc/7_develop.md">test suite</a> to check if important functionality is working as expected.</p>
<h3>Run your Bot as a restricted user</h3>
<p><strong>I recommend to run your bot as a user, with almost no access rights.</strong> All files your Bot have write access to are in danger to be overwritten/deleted if your bot is hacked. For the same reason ervery file your Bot can read is in danger to be disclosed. Restict your Bots access rigths to the absolute minimum.</p>
<p><strong>Never run your Bot as root, this is the most dangerous you can do!</strong> Usually the user nobody has almost no rights on Unix/Linux systems. See <a href="doc/4_expert.md">Expert use</a> on how to run your Bot as an other user.</p>
<h3 id="secure-your-bot-installation">Secure your Bot installation</h3>
<p><strong>Never run your Bot as root, this is the most dangerous you can do!</strong> Usually the user 'nobody' has almost no rights on Unix/Linux systems. See <a href="doc/4_expert.md">Expert use</a> on how to run your Bot as an other user.</p>
<h3>Secure your Bot installation</h3>
<p><strong>Your Bot configuration must no be readable from other users.</strong> Everyone who can read your Bots token can act as your Bot and has access to all chats your Bot is in!</p>
<p>Everyone with read access to your Bot files can extract your Bots data. Especially your Bot Token in <code>token</code> must be protected against other users. No one exept you must have write access to the Bot files. The Bot must be restricted to have write access to <code>count</code> and <code>tmp-bot-bash</code> only, all other files must be write protected.</p>
<p>To set access rights for your bashbot installation to a reasonable default run <code>sudo ./bashbot.sh init</code> after every update or change to your installation directory.</p>
<h2 id="faq">FAQ</h2>
<h3 id="is-this-bot-insecure">Is this Bot insecure?</h3>
<p>Bashbot is not more (in)secure as any other Bot written in any other language, we have done our best to make it as secure as possible. But YOU are responsible for the bot commands you wrote and you should know about the risks </p>
<h3 id="why-bash-and-not-the-much-better-xyz">Why Bash and not the much better xyz?</h3>
<p>Well, thats a damn good question … may be because Im an Unix/Linux admin from stone age. Nevertheless there are more reasons from my side:</p>
<h2>FAQ</h2>
<h3>Is this Bot insecure?</h3>
<p>Bashbot is not more (in)secure as any other Bot written in any other language, we have done our best to make it as secure as possible. But YOU are responsible for the bot commands you wrote and you should know about the risks ...</p>
<h3>Why Bash and not the much better xyz?</h3>
<p>Well, thats a damn good question ... may be because I'm an Unix/Linux admin from stone age. Nevertheless there are more reasons from my side:</p>
<ul>
<li>bashbot will run everywhere where bash is availible, from ebedded linux to mainframe</li>
<li>easy to integrate with other shell script, e.g. for sending system message / health status</li>
<li>easy to integrate with other shell script, e.g. for sending system message / health status</li>
<li>no need to install or learn a new programming language, library or framework</li>
<li>no database, not event driven, not OO </li>
<li>no database, not event driven, not OO ...</li>
</ul>
<h3 id="can-i-have-the-single-bashbot.sh-file-back">Can I have the single bashbot.sh file back?</h3>
<p>At the beginning bashbot was simply the file <code>bashbot.sh</code> you can copy everywhere and run the bot. Now we have commands.sh, mycommands.sh, modules/*.sh and much more.</p>
<p>Hey no Problem, if you are finished with your cool bot run <code>dev/make-standalone.sh</code> to create a stripped down Version of your bot containing only bashbot.sh and commands.sh! For more information see <a href="doc/7_develop.md">Create a stripped down Version of your Bot</a></p>
<h3 id="can-i-send-messages-from-cli-and-scripts">Can I send messages from CLI and scripts?</h3>
<p>Of course, you can send messages from CLI and scripts, simply install bashbot as <a href="#Your-really-first-bashbot-in-a-nutshell">described here</a>, send the messsage /start to set yourself as botadmin and stop the bot with <code>./bashbot.sh kill</code>.</p>
<h3>Can I have the single bashbot.sh file back?</h3>
<p>At the beginning bashbot was simply the file <code>bashbot.sh</code> you can copy everywhere and run the bot. Now we have 'commands.sh', 'mycommands.sh', 'modules/*.sh' and much more.</p>
<p>Hey no Problem, if you are finished with your cool bot run <code>dev/make-standalone.sh</code> to create a stripped down Version of your bot containing only 'bashbot.sh' and 'commands.sh'! For more information see <a href="doc/7_develop.md">Create a stripped down Version of your Bot</a></p>
<h3>Can I send messages from CLI and scripts?</h3>
<p>Of course, you can send messages from CLI and scripts, simply install bashbot as <a href="#Your-really-first-bashbot-in-a-nutshell">described here</a>, send the messsage '/start' to set yourself as botadmin and stop the bot with <code>./bashbot.sh kill</code>.</p>
<p>Run the following commands in your bash shell or script while you are in the installation directory:</p>
<div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="co"># prepare bash / script to send commands</span>
<span class="bu">export</span> <span class="va">BASHBOT_HOME=</span><span class="st">&quot;</span><span class="va">$(</span><span class="bu">pwd</span><span class="va">)</span><span class="st">&quot;</span>
<span class="bu">source</span> ./bashbot.sh source
<span class="co"># send me a test message</span>
<span class="ex">send_message</span> <span class="st">&quot;</span><span class="va">$(</span><span class="fu">cat</span> <span class="st">&quot;</span><span class="va">$BOTADMIN</span><span class="st">&quot;</span><span class="va">)</span><span class="st">&quot;</span> <span class="st">&quot;test&quot;</span>
<span class="co"># send me output of a system command</span>
<span class="ex">send_message</span> <span class="st">&quot;</span><span class="op">$(&lt;</span><span class="st">&quot;</span><span class="va">$BOTADMIN</span><span class="st">&quot;</span><span class="op">)</span><span class="st">&quot;</span> <span class="st">&quot;</span><span class="va">$(</span><span class="fu">df</span> -h<span class="va">)</span><span class="st">&quot;</span></code></pre></div>
<div class="sourceCode" id="cb3"><pre class="sourceCode bash"><code class="sourceCode bash"><a class="sourceLine" id="cb3-1" title="1"><span class="co"># prepare bash / script to send commands</span></a>
<a class="sourceLine" id="cb3-2" title="2"><span class="bu">export</span> <span class="va">BASHBOT_HOME=</span><span class="st">&quot;</span><span class="va">$(</span><span class="bu">pwd</span><span class="va">)</span><span class="st">&quot;</span></a>
<a class="sourceLine" id="cb3-3" title="3"><span class="bu">source</span> ./bashbot.sh source</a>
<a class="sourceLine" id="cb3-4" title="4"></a>
<a class="sourceLine" id="cb3-5" title="5"><span class="co"># send me a test message</span></a>
<a class="sourceLine" id="cb3-6" title="6"><span class="ex">send_message</span> <span class="st">&quot;</span><span class="va">$(</span><span class="fu">cat</span> <span class="st">&quot;</span><span class="va">$BOTADMIN</span><span class="st">&quot;</span><span class="va">)</span><span class="st">&quot;</span> <span class="st">&quot;test&quot;</span></a>
<a class="sourceLine" id="cb3-7" title="7"></a>
<a class="sourceLine" id="cb3-8" title="8"><span class="co"># send me output of a system command</span></a>
<a class="sourceLine" id="cb3-9" title="9"><span class="ex">send_message</span> <span class="st">&quot;</span><span class="op">$(&lt;</span><span class="st">&quot;</span><span class="va">$BOTADMIN</span><span class="st">&quot;</span><span class="op">)</span><span class="st">&quot;</span> <span class="st">&quot;</span><span class="va">$(</span><span class="fu">df</span> -h<span class="va">)</span><span class="st">&quot;</span></a></code></pre></div>
<p>For more information see <a href="doc/8_custom.md">Expert Use</a></p>
<h3 id="why-do-i-get-expected-value-got-eof-on-start">Why do I get “EXPECTED value GOT EOF” on start?</h3>
<h3>Why do I get "EXPECTED value GOT EOF" on start?</h3>
<p>May be your IP is blocked by telegram. You can test this by running curl or wget manually:</p>
<div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="ex">curl</span> -m 10 https://api.telegram.org/bot
<span class="co">#curl: (28) Connection timed out after 10001 milliseconds</span>
<span class="fu">wget</span> -t 1 -T 10 https://api.telegram.org/bot
<span class="co">#Connecting to api.telegram.org (api.telegram.org)|46.38.243.234|:443... failed: Connection timed out.</span></code></pre></div>
<p>This may happen if to many wrong requests are sent to api.telegram.org, e.g. using a wrong token or not existing API calls. If you have a fixed IP you can ask telegram service to unblock your ip or change your IP. If you are running a tor proxy on your server you may uncomment the <code>BASHBOT_CURL_ARGS</code> line in mycommands.sh</p>
<p><span class="citation">@Gnadelwartz</span></p>
<h2 id="thats-it">Thats it!</h2>
<p>If you feel that theres something missing or if you found a bug, feel free to submit a pull request!</p>
<h4 id="version-v0.91-0-g31808a9"><br /><span class="math display"><em>V</em><em>E</em><em>R</em><em>S</em><em>I</em><em>O</em><em>N</em></span><br /> v0.91-0-g31808a9</h4>
<div class="sourceCode" id="cb4"><pre class="sourceCode bash"><code class="sourceCode bash"><a class="sourceLine" id="cb4-1" title="1"><span class="ex">curl</span> -m 10 https://api.telegram.org/bot</a>
<a class="sourceLine" id="cb4-2" title="2"><span class="co">#curl: (28) Connection timed out after 10001 milliseconds</span></a>
<a class="sourceLine" id="cb4-3" title="3"></a>
<a class="sourceLine" id="cb4-4" title="4"><span class="fu">wget</span> -t 1 -T 10 https://api.telegram.org/bot</a>
<a class="sourceLine" id="cb4-5" title="5"><span class="co">#Connecting to api.telegram.org (api.telegram.org)|46.38.243.234|:443... failed: Connection timed out.</span></a></code></pre></div>
<p>This may happen if to many wrong requests are sent to api.telegram.org, e.g. using a wrong token or not existing API calls. If you have a fixed IP you can ask telegram service to unblock your ip or change your IP. If you are running a tor proxy on your server you may uncomment the <code>BASHBOT_CURL_ARGS</code> line in 'mycommands.sh'</p>
<p>@Gnadelwartz</p>
<h2>That's it!</h2>
<p>If you feel that there's something missing or if you found a bug, feel free to submit a pull request!</p>
<h4>$$VERSION$$ v0.94-dev2-0-g3d636f7</h4>
</body>
</html>

View File

@ -180,4 +180,4 @@ This may happen if to many wrong requests are sent to api.telegram.org, e.g. usi
If you feel that there's something missing or if you found a bug, feel free to submit a pull request!
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7

View File

@ -253,4 +253,4 @@ tor proxy on your server you may uncomment the ```BASHBOT_CURL_ARGS``` line in
If you feel that there's something missing or if you found a bug, feel free to
submit a pull request!
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7

View File

@ -4,7 +4,7 @@
# this addon counts how many files, e.g. stickers, are sent to
# a chat and takes actions if threshold is reached
#
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# used events:
#
@ -52,24 +52,34 @@ if [[ "$1" = "start"* ]]; then
BASHBOT_EVENT_CMD["${ANTIFL_ME}"]="${ANTIFL_ME}_cmd"
antiFlood_cmd(){
# shellcheck disable=SC2153
local chat="${CHAT[ID]}"
case "${CMD[0]}" in
# command /afstart starts detection, $1 floodlevel
"/afstart")
ANTIFL_CHATS["${CHAT[ID]}","level"]="${ANTIFL_DEFAULT}"
ANTIFL_CHATS["${CHAT[ID]}","ban"]="${ANTIFL_BAN}"
[[ "${CMD[1]}" =~ ^[0-9]+$ ]] && ANTIFL_CHATS["${CHAT[ID]}","level"]="${CMD[1]}"
[[ "${CMD[2]}" =~ ^[0-9]+$ ]] && ANTIFL_CHATS["${CHAT[ID]}","ban"]="${CMD[2]}"
# allow bot admin to activate for other chats
[[ "${CMD[3]}" =~ ^[-0-9]+$ ]] && user_is_botadmin "${USER[ID]}" && chat="$3"
[[ "${CMD[1]}" =~ ^[0-9]+$ ]] && ANTIFL_CHATS["${chat}","level"]="${CMD[1]}" \
|| ANTIFL_CHATS["${chat}","level"]="${ANTIFL_DEFAULT}"
[[ "${CMD[2]}" =~ ^[0-9]+$ ]] && ANTIFL_CHATS["${chat}","ban"]="${CMD[2]}" \
|| ANTIFL_CHATS["${chat}","ban"]="${ANTIFL_BAN}"
antiFlood_timer
send_normal_message "${USER[ID]}" "Antiflood set for chat ${chat}" &
;;
# command /afactive starts counter meausares
"/afdo" | "/afactive")
ANTIFL_CHATS["${CHAT[ID]}","active"]="yes"
[[ "${CMD[1]}" =~ ^[-0-9]+$ ]] && user_is_botadmin "${USER[ID]}" && chat="$3"
ANTIFL_CHATS["${chat}","active"]="yes"
jssh_writeDB "ANTIFL_CHATS" "addons/$ANTIFL_ME" &
send_normal_message "${USER[ID]}" "Antiflood activated for chat ${chat}" &
;;
# command /afactive starts counter meausares
"/afstop")
ANTIFL_CHATS["${CHAT[ID]}","active"]="no"
[[ "${CMD[1]}" =~ ^[-0-9]+$ ]] && user_is_botadmin "${USER[ID]}" && chat="$3"
ANTIFL_CHATS["${chat}","active"]="no"
jssh_writeDB "ANTIFL_CHATS" "addons/$ANTIFL_ME" &
send_normal_message "${USER[ID]}" "Antiflood stopped for chat ${chat}" &
;;
esac
}

View File

@ -4,7 +4,7 @@
# Addons can register to bashbot events at statup
# by providing their name and a callback per event
#
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
#
# If an event occours each registered event function is called.
#
@ -40,11 +40,12 @@
#
# prameters on events
# $1 event: inline, message, ..., file
# $2 debug: use "[[ "$2" = *"debug"* ]]" if you want to output extra diagnostic
# $2 key: key of array BASHBOT_EVENT_xxx
# $3 debug: use "[[ "$2" = *"debug"* ]]" if you want to output extra diagnostic
#
# export used events
export BASHBOT_EVENT_INLINE BASHBOT_EVENT_CMD BASHBOT_EVENT_REPLY BASHBOT_EVENT_TIMER
export BASHBOT_EVENT_INLINE BASHBOT_EVENT_CMD BASHBOT_EVENT_REPLY BASHBOT_EVENT_TIMER BASHBOT_EVENT_SEND
# any global variable defined by addons MUST be prefixed by addon name
EXAMPLE_ME="example"
@ -63,8 +64,8 @@ if [[ "$1" = "start"* ]]; then
# any function defined by addons MUST be prefixed by addon name
# function local variables can have any name, but must be LOCAL
example_reply(){
local msg="message"
send_markdown_message "${CHAT[ID]}" "User *${USER[USERNAME]}* replied to ${msg} from *${REPLYTO[USERNAME]}*" &
local msg="message" event="$1" key="$2"
send_markdown_message "${CHAT[ID]}" "User *${USER[USERNAME]}* replied to ${msg} from *${REPLYTO[USERNAME]}* (Event: ${event} Key:{${key})" &
}
# register to inline and command
@ -74,11 +75,11 @@ if [[ "$1" = "start"* ]]; then
# any function defined by addons MUST be prefixed by addon name
# function local variables can have any name, but must be LOCAL
example_multievent(){
local type="$1"
local event="$1" key="$2"
local msg="${MESSAGE[0]}"
# shellcheck disable=SC2154
[ "${type}" = "inline" ] && msg="${iQUERY[0]}"
send_normal_message "${CHAT[ID]}" "${type} received: ${msg}" &
send_normal_message "${CHAT[ID]}" "${event} from ${key} received: ${msg}" &
}
BASHBOT_EVENT_TIMER["${EXAMPLE_ME}after5min","-5"]="${EXAMPLE_ME}_after5min"
@ -96,4 +97,18 @@ if [[ "$1" = "start"* ]]; then
example_every2min(){
send_markdown_message "$(< "${BOTADMIN}")" "This a a every 2 minute event ..." &
}
# register to send
BASHBOT_EVENT_SEND["${EXAMPLE_ME}"]="${EXAMPLE_ME}_log"
EXAMPLE_LOG="${BASHBOT_ETC:-.}/addons/${EXAMPLE_ME}.log"
# any function defined by addons MUST be prefixed by addon name
# function local variables can have any name, but must be LOCAL
# $1 = send / upload
# $* remaining args are from sendJson and sendUpload
# Note: do not call any send message functions from EVENT_SEND!
example_log(){
local send="$1"; shift
echo "$(date): Type: ${send} Args: $*" >>"${EXAMPLE_LOG}"
}
fi

View File

@ -1,7 +1,7 @@
#!/bin/sh
# description: Start or stop telegram-bash-bot
#
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# shellcheck disable=SC2009
# shellcheck disable=SC2181

View File

@ -11,7 +11,7 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
#
# Exit Codes:
# - 0 sucess (hopefully)
@ -153,7 +153,7 @@ fi
###############
# load modules
for modules in ${MODULEDIR:-.}/*.sh ; do
for modules in "${MODULEDIR:-.}"/*.sh ; do
# shellcheck source=./modules/aliases.sh
[ -r "${modules}" ] && source "${modules}" "source"
done
@ -232,61 +232,72 @@ if [ "${BASHBOT_WGET}" = "" ] && _exists curl ; then
# simple curl or wget call, output to stdout
getJson(){
# shellcheck disable=SC2086
curl -sL ${BASHBOT_CURL_ARGS} -m "${TIMEOUT}" "$1"
curl -sL -k ${BASHBOT_CURL_ARGS} -m "${TIMEOUT}" "$1"
}
# usage: sendJson "chat" "JSON" "URL"
sendJson(){
local chat="";
[ "${1}" != "" ] && chat='"chat_id":'"${1}"','
# shellcheck disable=SC2086
res="$(curl -s ${BASHBOT_CURL_ARGS} -m "${TIMEOUT}" -d '{'"${chat} $2"'}' -X POST "${3}" \
res="$(curl -s ${BASHBOT_CURL_ARGS} -m "${TIMEOUT}" -d '{'"${chat} $(iconv -f utf-8 -t utf-8 -c <<<$2)"'}' -X POST "${3}" \
-H "Content-Type: application/json" | "${JSONSHFILE}" -s -b -n )"
BOTSENT[OK]="$(JsonGetLine '"ok"' <<< "$res")"
BOTSENT[ID]="$(JsonGetValue '"result","message_id"' <<< "$res")"
[ "${SOURCE}" != "yes" ] && [ "${BASHBOT_EVENT_SEND[*]}" != "" ] && event_send "send" "$@" &
}
#$1 Chat, $2 what , $3 file, $4 URL, $5 caption
sendUpload() {
[ "$#" -lt 4 ] && return
if [ "$5" != "" ]; then
# shellcheck disable=SC2086
res="$(curl -s ${BASHBOT_CURL_ARGS} "$4" -F "chat_id=$1" -F "$2=@$3;${3##*/}" -F "caption=$5" | "${JSONSHFILE}" -s -b -n )"
res="$(curl -s -k ${BASHBOT_CURL_ARGS} "$4" -F "chat_id=$1" -F "$2=@$3;${3##*/}" -F "caption=$5" | "${JSONSHFILE}" -s -b -n )"
else
# shellcheck disable=SC2086
res="$(curl -s ${BASHBOT_CURL_ARGS} "$4" -F "chat_id=$1" -F "$2=@$3;${3##*/}" | "${JSONSHFILE}" -s -b -n )"
res="$(curl -s -k ${BASHBOT_CURL_ARGS} "$4" -F "chat_id=$1" -F "$2=@$3;${3##*/}" | "${JSONSHFILE}" -s -b -n )"
fi
BOTSENT[OK]="$(JsonGetLine '"ok"' <<< "$res")"
[ "${SOURCE}" != "yes" ] && [ "${BASHBOT_EVENT_SEND[*]}" != "" ] && event_send "upload" "$@" &
}
else
# simple curl or wget call outputs result to stdout
getJson(){
# shellcheck disable=SC2086
wget -t 2 -T "${TIMEOUT}" ${BASHBOT_WGET_ARGS} -qO - "$1"
wget --no-check-certificate -t 2 -T "${TIMEOUT}" ${BASHBOT_WGET_ARGS} -qO - "$1"
}
# usage: sendJson "chat" "JSON" "URL"
sendJson(){
local chat="";
[ "${1}" != "" ] && chat='"chat_id":'"${1}"','
# shellcheck disable=SC2086
res="$(wget -t 2 -T "${TIMEOUT}" ${BASHBOT_WGET_ARGS} -qO - --post-data='{'"${chat} $2"'}' \
res="$(wget -t 2 -T "${TIMEOUT}" ${BASHBOT_WGET_ARGS} -qO - --post-data='{'"${chat} $(iconv -f utf-8 -t utf-8 -c <<<$2)"'}' \
--header='Content-Type:application/json' "${3}" | "${JSONSHFILE}" -s -b -n )"
BOTSENT[OK]="$(JsonGetLine '"ok"' <<< "$res")"
BOTSENT[ID]="$(JsonGetValue '"result","message_id"' <<< "$res")"
[ "${SOURCE}" != "yes" ] && [ "${BASHBOT_EVENT_SEND[*]}" != "" ] && event_send "send" "$@" &
}
sendUpload() {
sendJson "$1" '"text":"Sorry, wget does not support file upload"' "${MSG_URL}"
BOTSENT[OK]="false"
[ "${SOURCE}" != "yes" ] && [ "${BASHBOT_EVENT_SEND[*]}" != "" ] && event_send "upload" "$@" &
}
fi
# escape / remove text charaters for json strings, eg. " -> \"
# $1 string
# output escaped string
JsonEscape() {
sed 's/\([-"`´,§$%&ß/(){}#@?*]\)/\\\1/g' <<< "$1"
}
# convert common telegram entities to JSON
# title caption description markup inlinekeyboard
title2Json(){
local title caption desc markup keyboard
[ "$1" != "" ] && title=',"title":"'$1'"'
[ "$2" != "" ] && caption=',"caption":"'$2'"'
[ "$3" != "" ] && desc=',"description":"'$3'"'
[ "$4" != "" ] && markup=',"parse_mode":"'$4'"'
[ "$5" != "" ] && keyboard=',"reply_markup":"'$5'"'
[ "$1" != "" ] && title=',"title":"'$(JsonEscape "$1")'"'
[ "$2" != "" ] && caption=',"caption":"'$(JsonEscape "$2")'"'
[ "$3" != "" ] && desc=',"description":"'$(JsonEscape "$3")'"'
[ "$4" != "" ] && markup=',"parse_mode":"'$(JsonEscape "$4")'"'
[ "$5" != "" ] && keyboard=',"reply_markup":"'$(JsonEscape "$5")'"'
echo "${title}${caption}${desc}${markup}${keyboard}"
}
@ -321,7 +332,7 @@ JsonGetValue() {
# $1 ARRAY name, must be declared with "declare -A ARRAY" before calling
Json2Array() {
# shellcheck source=./commands.sh
[ "$1" = "" ] || source <( printf "$1"'=( %s )' "$(sed -E -e 's/\t/=/g' -e 's/=(true|false)/="\1"/')" )
[ "$1" = "" ] || source <( printf "$1"'=( %s )' "$(sed -E -n -e '/\["[-0-9a-zA-Z_,."]+"\]\t/ s/\t/=/gp' -e 's/=(true|false)/="\1"/')" )
}
# output ARRAY as JSON.sh style data
# $1 ARRAY name, must be declared with "declare -A ARRAY" before calling
@ -372,7 +383,7 @@ process_client() {
grep -q "$tmpcount" <"${COUNTFILE}" &>/dev/null || cat <<< "$tmpcount" >>"${COUNTFILE}"
}
declare -Ax BASBOT_EVENT_INLINE BASBOT_EVENT_MESSAGE BASHBOT_EVENT_CMD BASBOT_EVENT_REPLY BASBOT_EVENT_FORWARD
declare -Ax BASBOT_EVENT_INLINE BASBOT_EVENT_MESSAGE BASHBOT_EVENT_CMD BASBOT_EVENT_REPLY BASBOT_EVENT_FORWARD BASHBOT_EVENT_SEND
declare -Ax BASBOT_EVENT_CONTACT BASBOT_EVENT_LOCATION BASBOT_EVENT_FILE BASHBOT_EVENT_TEXT BASHBOT_EVENT_TIMER
start_timer(){
@ -383,82 +394,93 @@ start_timer(){
done;
}
EVENT_SEND="0"
event_send() {
# max recursion level 5 to avoid fork bombs
(( EVENT_SEND++ )); [ "$EVENT_SEND" -gt "5" ] && return
# shellcheck disable=SC2153
for key in "${!BASHBOT_EVENT_SEND[@]}"
do
_exec_if_function "${BASHBOT_EVENT_SEND[${key}]}" "$@"
done
}
EVENT_TIMER="0"
event_timer() {
local event timer debug="$1"
local key timer debug="$1"
(( EVENT_TIMER++ ))
# shellcheck disable=SC2153
for event in "${!BASHBOT_EVENT_TIMER[@]}"
for key in "${!BASHBOT_EVENT_TIMER[@]}"
do
timer="${event##*,}"
timer="${key##*,}"
[[ ! "$timer" =~ ^-*[1-9][0-9]*$ ]] && continue
if [ "$(( EVENT_TIMER % timer ))" = "0" ]; then
_exec_if_function "${BASHBOT_EVENT_TIMER[${event}]}" "timer" "${debug}"
_exec_if_function "${BASHBOT_EVENT_TIMER[${key}]}" "timer" "${key}" "${debug}"
[ "$(( EVENT_TIMER % timer ))" -lt "0" ] && \
unset BASHBOT_EVENT_TIMER["${event}"]
unset BASHBOT_EVENT_TIMER["${key}"]
fi
done
}
event_inline() {
local event debug="$1"
local key debug="$1"
# shellcheck disable=SC2153
for event in "${!BASHBOT_EVENT_INLINE[@]}"
for key in "${!BASHBOT_EVENT_INLINE[@]}"
do
_exec_if_function "${BASHBOT_EVENT_INLINE[${event}]}" "inline" "${debug}"
_exec_if_function "${BASHBOT_EVENT_INLINE[${key}]}" "inline" "${key}" "${debug}"
done
}
event_message() {
echo "${MESSAGE[0]}"
local event debug="$1"
local key debug="$1"
# ${MESSAEG[*]} event_message
# shellcheck disable=SC2153
for event in "${!BASHBOT_EVENT_MESSAGE[@]}"
for key in "${!BASHBOT_EVENT_MESSAGE[@]}"
do
_exec_if_function "${BASHBOT_EVENT_MESSAGE[${event}]}" "messsage" "${debug}"
_exec_if_function "${BASHBOT_EVENT_MESSAGE[${key}]}" "messsage" "${key}" "${debug}"
done
# ${TEXT[*]} event_text
if [ "${MESSAGE[0]}" != "" ]; then
# shellcheck disable=SC2153
for event in "${!BASHBOT_EVENT_TEXT[@]}"
for key in "${!BASHBOT_EVENT_TEXT[@]}"
do
_exec_if_function "${BASHBOT_EVENT_TEXT[${event}]}" "text" "${debug}"
_exec_if_function "${BASHBOT_EVENT_TEXT[${key}]}" "text" "${key}" "${debug}"
done
# ${CMD[*]} event_cmd
if [ "${CMD[0]}" != "" ]; then
# shellcheck disable=SC2153
for event in "${!BASHBOT_EVENT_CMD[@]}"
for key in "${!BASHBOT_EVENT_CMD[@]}"
do
_exec_if_function "${BASHBOT_EVENT_CMD[${event}]}" "command" "${debug}"
_exec_if_function "${BASHBOT_EVENT_CMD[${key}]}" "command" "${key}" "${debug}"
done
fi
fi
# ${REPLYTO[*]} event_replyto
if [ "${REPLYTO[UID]}" != "" ]; then
# shellcheck disable=SC2153
for event in "${!BASHBOT_EVENT_REPLYTO[@]}"
for key in "${!BASHBOT_EVENT_REPLYTO[@]}"
do
_exec_if_function "${BASHBOT_EVENT_REPLYTO[${event}]}" "replyto" "${debug}"
_exec_if_function "${BASHBOT_EVENT_REPLYTO[${key}]}" "replyto" "${key}" "${debug}"
done
fi
# ${FORWARD[*]} event_forward
if [ "${FORWARD[UID]}" != "" ]; then
# shellcheck disable=SC2153
for event in "${!BASHBOT_EVENT_FORWARD[@]}"
for key in "${!BASHBOT_EVENT_FORWARD[@]}"
do
_exec_if_function && "${BASHBOT_EVENT_FORWARD[${event}]}" "forward" "${debug}"
_exec_if_function && "${BASHBOT_EVENT_FORWARD[${key}]}" "forward" "${key}" "${debug}"
done
fi
# ${CONTACT[*]} event_contact
if [ "${CONTACT[FIRST_NAME]}" != "" ]; then
# shellcheck disable=SC2153
for event in "${!BASHBOT_EVENT_CONTACT[@]}"
for key in "${!BASHBOT_EVENT_CONTACT[@]}"
do
_exec_if_function "${BASHBOT_EVENT_CONTACT[${event}]}" "contact" "${debug}"
_exec_if_function "${BASHBOT_EVENT_CONTACT[${key}]}" "contact" "${key}" "${debug}"
done
fi
@ -466,9 +488,9 @@ echo "${MESSAGE[0]}"
# ${LOCALTION[*]} event_location
if [ "${LOCATION[LONGITUDE]}" != "" ] || [ "${VENUE[TITLE]}" != "" ]; then
# shellcheck disable=SC2153
for event in "${!BASHBOT_EVENT_LOCATION[@]}"
for key in "${!BASHBOT_EVENT_LOCATION[@]}"
do
_exec_if_function "${BASHBOT_EVENT_LOCATION[${event}]}" "location" "${debug}"
_exec_if_function "${BASHBOT_EVENT_LOCATION[${key}]}" "location" "${key}" "${debug}"
done
fi
@ -476,9 +498,9 @@ echo "${MESSAGE[0]}"
# NOTE: compare again #URLS -1 blanks!
if [[ "${URLS[*]}" != " " ]]; then
# shellcheck disable=SC2153
for event in "${!BASHBOT_EVENT_FILE[@]}"
for key in "${!BASHBOT_EVENT_FILE[@]}"
do
_exec_if_function "${BASHBOT_EVENT_FILE[${event}]}" "file" "${debug}"
_exec_if_function "${BASHBOT_EVENT_FILE[${key}]}" "file" "${key}" "${debug}"
done
fi
@ -600,7 +622,7 @@ start_bot() {
find "${DATADIR}" -type p -delete
find "${DATADIR}" -size 0 -name "*.log" -delete
# load addons on startup
for addons in ${ADDONDIR:-.}/*.sh ; do
for addons in "${ADDONDIR:-.}"/*.sh ; do
# shellcheck source=./modules/aliases.sh
[ -r "${addons}" ] && source "${addons}" "startbot" "${DEBUG}"
done
@ -613,7 +635,7 @@ start_bot() {
trap "kill -9 $!; exit" EXIT INT HUP TERM QUIT
fi
while true; do
UPDATE="$(getJson "$UPD_URL$OFFSET" | "${JSONSHFILE}" -s -b -n)"
UPDATE="$(getJson "$UPD_URL$OFFSET" | "${JSONSHFILE}" -s -b -n | iconv -f utf-8 -t utf-8 -c)"
# Offset
OFFSET="$(grep <<< "${UPDATE}" '\["result",[0-9]*,"update_id"\]' | tail -1 | cut -f 2)"
@ -638,7 +660,7 @@ bot_init() {
[ -d "${OLDTMP}" ] && { mv -n "${OLDTMP}/"* "${DATADIR}"; rmdir "${OLDTMP}"; }
[ -f "modules/inline.sh" ] && rm -f "modules/inline.sh"
# load addons on startup
for addons in ${ADDONDIR:-.}/*.sh ; do
for addons in "${ADDONDIR:-.}"/*.sh ; do
# shellcheck source=./modules/aliases.sh
[ -r "${addons}" ] && source "${addons}" "init" "${DEBUG}"
done
@ -683,11 +705,15 @@ if [ ! -f "${JSONSHFILE}" ]; then
chmod +x "${JSONSHFILE}"
fi
if [ "${SOURCE}" != "yes" ] && [ "$1" != "init" ] && [ "$1" != "help" ] && [ "$1" != "" ]; then
if [ "${SOURCE}" != "yes" ] && [ "$1" != "init" ] && [ "$1" != "help" ]; then
ME="$(getBotName)"
if [ "$ME" = "" ]; then
echo -e "${RED}ERROR: Can't connect to Telegram Bot! May be your TOKEN is invalid ...${NC}"
exit 1
echo -e "${RED}ERROR: Can't connect to Telegram! Your TOKEN is invalid or you are blocked by ${URL%/*} ...${NC}"
case "$1" in
"" | "stop" | "kill"* | "suspendb"* ) # warn, but do not exit
echo -e "${RED}Ignored to continue for $1 ... ${NC}";;
*) exit 1;;
esac
fi
fi

View File

@ -5,7 +5,7 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
#
# adjust your language setting here, e.g.when run from other user or cron.
@ -39,7 +39,7 @@ Get the code in my [GitHub](http://github.com/topkecleon/telegram-bot-bash)
# load modues on startup and always on on debug
if [ "${1}" = "source" ] || [[ "${1}" = *"debug"* ]] ; then
# load all readable modules
for modules in ${MODULEDIR:-.}/*.sh ; do
for modules in "${MODULEDIR:-.}"/*.sh ; do
# shellcheck source=./modules/aliases.sh
[ -r "${modules}" ] && source "${modules}" "${1}"
done
@ -77,7 +77,7 @@ if [ "${1}" != "source" ];then
################################################
# GLOBAL commands start here, edit messages only
'/info'*)
send_markdown_message "${bashbot_info}"
send_markdown_message "${CHAT[ID]}" "${bashbot_info}"
;;
'/start'*)
send_action "${CHAT[ID]}" "typing"

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash
# this has to run once atfer git clone
# and every time we create new hooks
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# magic to ensure that we're always inside the root of our application,
# no matter from which directory we'll run script

View File

@ -3,7 +3,7 @@
#
# works together with git pre-push.sh and ADD all changed files since last push
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# magic to ensure that we're always inside the root of our application,
# no matter from which directory we'll run script

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
############
# NOTE: you MUST run install-hooks.sh again when updating this file!
@ -21,7 +21,7 @@ echo "............................"
unset IFS; set -f
# check for shellcheck
if which shellcheck >/dev/null 2>&1; then
if command -v shellcheck >/dev/null 2>&1; then
echo " Test all scripts with shellcheck ..."
else
echo "Error: shellcheck is not installed. Install shellcheck or delete $0"

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
############
# NOTE: you MUST run install-hooks.sh again when updating this file!

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash
# this has to run once atfer git clone
# and every time we create new hooks
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# magic to ensure that we're always inside the root of our application,
# no matter from which directory we'll run script

View File

@ -2,7 +2,7 @@
# file: make-distribution.sh
# creates files and arcchives to dirtribute bashbot
#
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# magic to ensure that we're always inside the root of our application,
# no matter from which directory we'll run script
@ -54,8 +54,8 @@ fi
# make html doc
mkdir html 2>/dev/null
cp README.html html/index.html
find doc -iname "*.md" -type f -exec sh -c 'pandoc -s -S -M "title=Bashobot Documentation - ${0%.md}.html" "${0}" -o "./html/$(basename ${0%.md}.html)"' {} \;
find examples -iname "*.md" -type f -exec sh -c 'pandoc -s -S -M "title=Bashobot Documentation - ${0%.md}.html" "${0}" -o "${0%.md}.html"' {} \;
find doc -iname "*.md" -type f -exec sh -c 'pandoc -s -f commonmark -M "title=Bashobot Documentation - ${0%.md}.html" "${0}" -o "./html/$(basename ${0%.md}.html)"' {} \;
find examples -iname "*.md" -type f -exec sh -c 'pandoc -s -f commonmark -M "title=Bashobot Documentation - ${0%.md}.html" "${0}" -o "${0%.md}.html"' {} \;
find README.html html examples -iname "*.html" -type f -exec sh -c 'sed -i -E "s/href=\"(\.\.\/)*doc\//href=\"\1html\//g;s/href=\"(.*).md(#.*)*\"/href=\"\1.html\"/g" ${0}' {} \;
# create archive

View File

@ -5,7 +5,7 @@
# If you your bot is finished you can use make-standalone.sh to create the
# the old all-in-one bashbot: bashbot.sh and commands.sh only!
#
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# magic to ensure that we're always inside the root of our application,
# no matter from which directory we'll run script

View File

@ -1,3 +1,3 @@
# list of additional files to check from shellcheck
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
bashbot.rc

View File

@ -1,6 +1,6 @@
#!/bin/bash
#
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# shellcheck disable=SC2016
#
# Easy Versioning in git:
@ -61,7 +61,7 @@ do
done
# try to compile README.txt
echo -n " README.txt" >&2
type -f pandoc >/dev/null && pandoc -s -S -M "title=Bashbot README" README.md >README.html
type -f pandoc >/dev/null && pandoc -s -f commonmark -M "title=Bashbot README" README.md >README.html
fold -s README.md >README.txt
echo " done."

View File

@ -87,5 +87,5 @@ The old format is supported for backward compatibility, but may fail for corner
#### [Next Create Bot](1_firstbot.md)
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7

View File

@ -65,5 +65,5 @@ group. This step is up to you actually.
#### [Prev Installation](0_install.md)
#### [Next Getting started](2_usage.md)
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7

View File

@ -223,5 +223,5 @@ send_action "${CHAT[ID]}" "action"
#### [Prev Create Bot](1_firstbot.md)
#### [Next Advanced Usage](3_advanced.md)
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7

View File

@ -180,5 +180,5 @@ See also [answer_inline_multi, answer_inline_compose](6_reference.md#answer_inli
#### [Prev Getting started](2_usage.md)
#### [Next Expert Use](4_expert.md)
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7

View File

@ -348,5 +348,5 @@ for every poll until the maximum of BASHBOT_SLEEP ms.
#### [Prev Advanced Use](3_advanced.md)
#### [Next Best Practice](5_practice.md)
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7

View File

@ -152,5 +152,5 @@ The second warning is about an unused variable, this is true because in our exam
#### [Prev Best Practice](5_practice.md)
#### [Next Functions Reference](6_reference.md)
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7

View File

@ -74,12 +74,10 @@ See also [Text formating options](https://core.telegram.org/bots/api#formatting-
----
##### delete_message
If your Bot is admin of a Chat he can delete every message, if not he can delete only his messages.
A bot can only delete messages if he is admin of a Chat, if not he can delete his own messages only.
*usage:* delete_message "${CHAT[ID]}" "${MESSAGE[ID]}"
*alias:* _del_message "${MESSAGE[ID]}"
See also [deleteMessage limitations](https://core.telegram.org/bots/api#deletemessage)
----
@ -107,6 +105,7 @@ Starting with version 0.80 send_file implements the following rules:
- file names must not start with "."
- file names not starting wit "/" are realtive to $TMPDIR, e.g. ./data-bot-bash
- abolute filenames must match $FILE_REGEX
- FILE_REGEX is a regular expression, not shell globbing, test you rexexes: http://www.softlion.com/webTools/RegExpTest/
*usage:* send_file "${CHAT[ID]}" "file" "caption"
@ -143,9 +142,13 @@ Note: since version 0.6 send_keyboard was changed to use native "JSON Array" not
*example:*
```bash
send_keyboard "${CHAT[ID]}" "Say yes or no" "[ \\"yes\" , \\"no\" ]""
send_keyboard "${CHAT[ID]}" "Say yes or no" "[ \\"yes\\" ] , [ \\"no\\" ]"
send_keyboard "${CHAT[ID]}" "Enter digit" "[ \\"1\\" , \\"2\\" , \\"3\\" ] , [ \\"4\\" , \\"5\\" , \\"6\\" ] , [ \\"7\\" , \\"8\\" , \\"9\\" ] , [ \\"0\\" ]"
send_keyboard "${CHAT[ID]}" "Say yes or no" '[ "yes" , "no" ]' # in one row
send_keyboard "${CHAT[ID]}" "Say yes or no" '[ "yes" ] , [ "no" ]' # 2 rows
send_keyboard "${CHAT[ID]}" "Enter digit" '[ "1" , "2" , "3" ] , [ "4" , "5" , "6" ] , [ "7" , "8" , "9" ] , [ "0" ]'
_keyboard_yesno # see aliases
_keyboard_numpad
```
##### remove_keyboard
@ -190,6 +193,8 @@ send_inline_keyboard "${CHAT[ID]}" "" '[{"text":"b 1", url"":"u 1"}, {"text":"b
----
### User Access Control
The following basic user control functions are part of the Telegram API.
More advanced API functions are currently not implemented in bashbot.
##### kick_chat_member
If your Bot is a chat admin he can kick and ban a user.
@ -223,6 +228,8 @@ fi
----
The following functions are bashbot only and not part of the Telegram API.
##### user_is_botadmin
Return true (0) if user is admin of bot, user id if botadmin is read from file './botadmin'.
@ -274,8 +281,6 @@ fi
----
### Inline Queries - answer direct queries to bot
You must include ```source modules/inline.sh``` in 'commands.sh' to have the following functions availible.
Inline Queries allows users to interact with your bot directly without sending extra commands.
As an answer to an inline query you can send back one or more results to the Telegram client.
The Telegram client will then show the results to the user and let him select one.
@ -304,7 +309,7 @@ answer_inline_multi "${iQUERY[ID]}" "
"
```
#### inline_query_compose
##### inline_query_compose
inline_query_compose composes one response element to to send back.
*usage:* inline_query_compose ID type args ....
@ -346,7 +351,8 @@ see [InlineQueryResult for more information](https://core.telegram.org/bots/api#
### Background and Interactive jobs
You must include ```source modules/background.sh``` in 'commands.sh' to have the following functions availible.
Background functions and interactive jobs extends the bot functionality to not only react to user input. You can start scripts for interative
chats and send messages based on time or other external events.
##### start_proc
```startproc``` starts a script, the output of the script is sent to the user or chat, user input will be sent back to the script. see [Advanced Usage](3_advanced.md#Interactive-Chats)
@ -453,29 +459,72 @@ Usually message is automatically forwarded in 'commands.sh', but you can forwar
*replaces:*' incproc
### JSON.sh DB
Since output of JSON.sh is so handy to use in bash, we provide a simple wrapper to read and write JSON.sh style data from and to files.
File name is prefixed with BASHBOT_ETC and the suffix '.jssh' is added to file name! File names must not contain '..'
----
### jsshDB
Since output generated by JSON.sh is so handy to use in bash, we use the format for a simple keys/value storage and providing
fucntions to read and write JSON.sh style data from and to files.
The file extions is '.jssh' and for security reasons location of jssh files is restricted to BASHBOT_ETC.
Note: File names containg '..' and absolute file names pointing outside BASHBOT_ETC are refused by jsshDB functions.
*Example:* for file name:
```bash
# bashbot is installed in /usr/local/telegram-bot-bash, no BASHBOT_ETC set.
# bashbot is installed in /usr/local/telegram-bot-bash, BASHBOT_ETC is not set.
"myfile" -> /usr/local/telegram-bot-bash/myfile.jssh
"addons/myfile" -> /usr/local/telegram-bot-bash/addons/myfile.jssh
"${DATADIR}/myfile usr/local/telegram-bot-bash/data-bot-bash/myfile.jssh
"${DATADIR}/myfile" -> /usr/local/telegram-bot-bash/data-bot-bash/myfile.jssh
"/home/someuser/myfile" -> function returns false, nothing done.
```
You must include ```source modules/jsshDB.sh``` in 'commands.sh' to have the following functions availible.
##### jssh_newDB
Creats new empty "DB" file if not exist.
Creats new empty jsshDB file if not exist.
*usage:* jssh_newDB "filename"
##### jssh_checkDB
Check if DB name respects the rules mentioned above and returns the real/final path to DB file.
Used internally by all jssh DB functions, but can also used to get the real filename for a jssh DB.
*usage:* jssh_checkDB "filename"
```bash
if file=$(jssh_checkDB somename); then
echo "Final filename is ${file}"
else
echo "Something wrong with somename"
fi
# somename = data-bot-bash/somevalues
Final filename is data-bot-bash/somevalues.jssh
# somename = /home/someuser/myfile
Something wrong with /home/someuser/myfile
# somename = data-bot-bash/../../../somevalues
Something wrong with data-bot-bash/../../../somevalues
```
##### jssh_readDB
Read content of a .jssh file in JSON.sh format into given ARRAY. ARRAY name must be delared with "declare -A ARRAY" before calling readDB.
*usage:* jssh_readDB "ARRAY" "filename"
*example:*
```bash
# read file data-bot-bash/somevalues.jssh into array SOMEVALUES
jssh_readDB "SOMEVALUES" "${DATADIR:-.}/somevalues"
print "${SOMEVALUES[*]}"
```
##### jssh_writeDB
wWrite content of given ARRAY into file. ARRAY name must be delared with "declare -A ARRAY" upfront,
Write content of an ARRAY into jsshDB file. ARRAY name must be delared with "declare -A ARRAY" before calling writeDB.
"DB" file MUST exist or nothing is written.
Note: Existing content is overwritten.
*usage:* jssh_writeDB "ARRAY" "filename"
*example:*
@ -490,7 +539,7 @@ WRITEVALUES["whynot","subindex2"]="whynot B"
WRITEVALUES["whynot","subindex2","text"]="This is an example content for pseudo multidimensional bash array"
# create DB
jssh_newDB "${DATADIR:-}/myvalues"
jssh_newDB "${DATADIR:-.}/myvalues"
# write to file data-bot-bash/somevalues.jssh from array MYVALUES
jssh_writeDB "WRITEVALUES" "${DATADIR:-}/myvalues"
@ -504,6 +553,62 @@ cat "${DATADIR:-}/myvalues.jssh"
["whynot","subindex1"] "whynot A"```
```
##### jssh_updateDB
Update/Add content of an ARRAY into a jsshDB file. ARRAY name must be delared with "declare -A ARRAY" before calling updateDB.
"DB" file MUST exist or nothing is written.
Note: Existing content not in ARRAY is kept in file.
*usage:* jssh_updateDB "ARRAY" "filename"
*example:*
```bash
# continued example from writeDB
MYVALUES=()
MYVALUES["newvalue"]="this is new"
# update file data-bot-bash/somevalues.jssh from array MYVALUES
jssh_updateDB "MYVALUES" "${DATADIR:-.}/myvalues"
# show whats written
["value1"] "value1"
["loveit"] "value2"
["whynot"] "value3"
["newvalue"] "this is new"
# now writeDB
cat "$DBfile"
jssh_writeDB "MYVALUES" "${DATADIR:-.}/myvalues"
# show whats written, ups!
cat "$DBfile"
["newvalue"] "this is new"
```
##### jssh_insertDB
Insert, update, append a key=value pair to a jsshDB file, key name is only allowed to contain '-a-zA-Z0-9,._'
*usage:* jssh_insertDB "key" "value" "filename"
*example:*
```bash
jssh_insertDB "newkey" "an other value" "${DATADIR:-.}/myvalues"
```
##### jssh_getDB
Read a key=value pair from a jsshDB file, key name is only allowed to contain '-a-zA-Z0-9,._'
*usage:* jssh_getDB "key" "filename"
*example:*
```bash
result="$(jssh_getDB "newvalue" "${DATADIR:-.}/myvalues")"
# lets see whats the value of key newvalue
echo "$result"
this is new
```
----
@ -562,7 +667,8 @@ https://linuxconfig.org/how-to-use-arrays-in-bash-script
### Aliases - shortcuts for often used funtions
You must include ```source modules/aliases.sh``` in 'commands.sh' to have the following functions availible.
Aliases are handy shortcuts for using in 'mycommands.sh', they avoid error prone typing of "${CHAT[ID]}" "${USER[ID]}" as much as possible.
Do not use them in bashbot.sh, modules and addons.
##### _is_botadmin
@ -655,7 +761,7 @@ You must include ```source modules/aliases.sh``` in 'commands.sh' to have the f
*alias for:* remove_keyboard "${CHAT[ID]}" ""
----
### Helper functions
@ -764,11 +870,12 @@ killallproc "_${CHAT[ID]}"
# kill all bot processes, including YOURSELF!
killallproc
```
##### get_file
*usage:* url="$(get_file "${CHAT[ID]}" "message")"
----
##### get_file
*usage:* url="$(get_file "${CHAT[ID]}" "message")"
##### send_text
*usage:* send_text "${CHAT[ID]}" "message"
@ -840,5 +947,5 @@ The name of your bot is availible as bash variable "$ME", there is no need to ca
#### [Prev Best Practice](5_practice.md)
#### [Next Notes for Developers](7_develop.md)
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-1-g4f90215

View File

@ -1,89 +1,106 @@
#### [Home](../README.md)
## Notes for bashbot developers
This section is about help and best practices for new bashbot developers. The main focus on is creating new versions of bashbot, not on develop your individual bot. Nevertheless the rules and tools described here can also help you with your bot development.
This section is about help and best practices for new bashbot developers. The main focus on is creating new versions of bashbot, modules and addons, not on develop your individual bot. Nevertheless the information provided here should help your bot development also.
bashbot development is done on github. If you want to provide fixes or new features [fork bashbot on githup](https://help.github.com/en/articles/fork-a-repo) and provide changes as [pull request on github](https://help.github.com/en/articles/creating-a-pull-request).
If you want to provide fixes or new features [fork bashbot on githup](https://help.github.com/en/articles/fork-a-repo) and provide changes as [pull request on github](https://help.github.com/en/articles/creating-a-pull-request).
### Debugging Bashbot
In normal mode of operation all bashbot output is discarded.
To get these messages (and more) you can start bashbot in the current shell with ```./bashbot.sh startbot &```.
Now you can see all output or erros from bashbot.
In addition you can change the change the level of verbosity by adding a third argument after startbot.
Usually all bashbot output is discarded.
If you want to get error messages (and more) start bashbot in the current shell with ```./bashbot.sh startbot```.
In addition you can the change the level of verbosity by adding a 'debug' as third argument.
```
"debug" redirects all output to "DEBUG.log", in addtion every update is logged in "MESSAGE.LOG" and "INLINE.log"
"debugterm" same as debug but output and errors are sent to terminal
"debugx" debug output and errors are sent to terminal
"xdebugx" same as debugx plus set bash option '-x' to show any executed command
"xdebug" same as debug plus set bash option '-x' to log any executed command
"xdebugterm" same as xdebug but output and errors are sent to terminal
"debug" all output is redirected to "DEBUG.log", in addtion every incomming message is logged in "MESSAGE.LOG" and "INLINE.log"
"xdebug" same as debug plus set bash option '-x' to log any executed command in "DEBUG.log"
```
To stop bashhbot in debugging mode run ```ps -uf | grep debug``` and use 'kill -9' to kill all processes shwon.
To stop bashhbot in debugging mode press CRTL+C. If this does not stop bashbot or you run it in background execute ```ps -uf | grep debug``` and kill all shown processes.
### Modules and Addons
**Modules** live in ```modules/*.sh``` and are bashbot functions factored out in seperate files, gouped by functionality. Main reason for creating modules was
to keep 'bashbot.sh' small, while extending functionality. In addition not every functionality is needed by a bot, so you can
disable modules by removing them, e.g. rename the respective module files to 'module.sh.off'.
**Modules** resides in ```modules/*.sh``` and are colletions of optional bashbot functions grouped by functionality. Main reason for creating modules was
to keep 'bashbot.sh' small, while extending functionality. In addition not every funtion is needed by all bots, so you can
disable modules, e.g. by rename the respective module file to 'module.sh.off'.
Modules must use only functions provided by 'bahsbot.sh' or the module itself, no depedencies to other modules or addons must exist.
If a module function is called from 'bashbot.sh', bashbot must work if the module is disabled, so the use of ```_is_function``` and
```_execute_if_function``` is mandatory.
Modules must use functions provided by 'bahsbot.sh' or the module itself and sould not depend on other modules or addons.
The only mandatory module is 'module/sendMessage.sh'.
**Addons** live in ```addons/*.sh.dist``` and are disabled by default. To activate an addon remove '.dist' from the filename, e.g.
```cp addons/example.sh.dist addons/example.sh```. Addons must register to BASHBOT_EVENTS at startup, e.g. to call a function everytime a message is recieved.
Registering to EVENTS is similar on how 'commands.sh' is executed, but more flexible and one major difference:
**Addons are executed in the context of the main script**, while 'commands.sh' is executed as a seperate process.
If a not mandatory module is used in 'bashbot.sh' or 'commands.sh', the use of ```_is_function``` or
```_execute_if_function``` is mandatory to catch absense of the module.
This is why event functions are time critical and must return as fast as possible. Spawn actions as a seperate process or function with '&', e.g.
send a message as respone from an addon: ```send_message "${CHAT[ID]}" "Message to send ..." &```.
**Addons** resides in ```addons/*.sh.dist``` and are not endabled by default. To activate an addon rename it to end with '.sh', e.g. by
```cp addons/example.sh.dist addons/example.sh```.
Addons must register themself to BASHBOT_EVENTS at startup, e.g. to call a function everytime a message is recieved.
Addons works similar as 'commands.sh' and 'mycommands.sh' but are much more flexible on when functions/commands are triggered.
Another major difference is: **Addons are executed in the context of the main script**, while 'commands.sh' and 'macommands.sh' are executed as a seperate process.
This is why event functions are time critical and must return as fast as possible.
#### Bashbot Events
Addons must register functions to bashbot events at startup by providing their name and a callback function.
Addons must register functions to bashbot events by providing their name, and internal identifier and a callback function.
If an event occours each registered function for the event is called.
Events run in the same context as the main bashbot loop, so variables set here are persistent as long bashbot is running.
Registered functions run in the same process as bashbot, not as a sub process, so variables set here are persistent as long bashbot is running.
Note: For the same reason event function MUST return imideatly! Time consuming tasks must be run in background or as a subshell, e.g. "long running &"
Note: For the same reason event function MUST return immediately! Time consuming tasks must be run as a background process, e.g. "long running &"
Availible events:
##### MESSAGE events (all iQuery and/or Message variables are avalible):
* BASHBOT_EVENT_INLINE an inline query is received
* BASHBOT_EVENT_MESSAGE any type of message is received
* BASHBOT_EVENT_TEXT a message containing text is recieved
* BASHBOT_EVENT_CMD a command is recieved (fist word starts with /)
* BASHBOT_EVENT_REPLYTO a reply to a message is received
* BASHBOT_EVENT_FORWARD a forwarded message is received
* BASHBOT_EVENT_CONTACT a contact is received
* BASHBOT_EVENT_LOCATION a location or a venue is received
* BASHBOT_EVENT_FILE a file is received
*usage*: BASHBOT_EVENT_xxx[ "uniqe-name" ]="callback"
* BASHBOT_EVENT_MESSAGE any of the following message types is received
* BASHBOT_EVENT_TEXT a message containing text is recieved
* BASHBOT_EVENT_CMD a message containing a command is recieved (starts with /)
* BASHBOT_EVENT_REPLYTO a reply to a message is received
* BASHBOT_EVENT_FORWARD a forwarded message is received
* BASHBOT_EVENT_CONTACT a contact is received
* BASHBOT_EVENT_LOCATION a location or a venue is received
* BASHBOT_EVENT_FILE a file is received
"unique-name" can be every alphanumeric string incl. '-' and '_'. Per convention it is the name of the addon followed by an internal identyfier.
*usage*: BASHBOT_EVENT_xxx[ "unique-name" ]="callback"
*Example:* Register a function to echo to any Text send to the bot
"unique-name" can be every alphanumeric string incl. '-' and '_'. Per convention the name of the addon followed by an internal identyfier should be used.
"callback" is called as the the parameters "event" "unique-name" "debug", where "event" is the event name in lower case, e.g. inline, messagei, text ... ,
and "unique-name" is the name provided when registering the event.
*Example:* Register a function to echo to any Text sent to the bot
```bash
# register callback:
BASHBOT_EVENT_TEXT["example_1"]="example_echo"
# function called if a text is received
example_echo() {
local event="$1" key="$2"
# all availible bashbot functions and variables can be used
send_normal_message "${CHAT[ID]}" "${MESSAGE[0]}" & # note the &!
send_normal_message "${CHAT[ID]}" "Event: ${event} Key: ${key} : ${MESSAGE[0]}" & # note the &!
}
```
* BAHSBOT_EVENT_TIMER is executed every minute and can be used in 3 variants: oneshot, every minute, every X minutes.
Registering to BASHBOT_EVENT_TIMER works isimilar as for message events, but you must add a timing argument to the index name.
##### Other types of events
* BAHSBOT_EVENT_TIMER executed every minute and can be used in 3 variants: oneshot, once a minute, every X minutes.
Registering to BASHBOT_EVENT_TIMER works similar as for message events, but you must add a timing argument to the name.
EVENT_TIMER is triggered every 60s and waits until the current running command is finished, so ist not excactly every
minute, but once a minute.
Every time EVENT_TIMER is triggered the variable "EVENT_TIMER" is increased. each callback is executed if ```EVENT_TIMER % time``` is '0' (true).
This means if you register an every 5 minutes callback first execution may < 5 Minutes, all subsequent executions are once every 5. Minute.
*usage:* BAHSBOT_EVENT_TIMER[ "name" , "time" ], where time is:
* -x execute ONCE in x minutes
* 0 ignored
* 1 execute every minute
* 1 execute once every minute
* x execute every x minutes
* -x execute ONCE in (next) x minutes *
*Examples:*
*\* if you really want "in x minutes" you must use ```-(EVENT_TIMER+x)```*
*Example:*
```bash
# register callback:
BAHSBOT_EVENT_TIMER["example_every","1"]="example_everymin"
@ -95,10 +112,39 @@ example_everymin() {
}
# register other callback:
BAHSBOT_EVENT_TIMER["example_10min","-10"]="example_in10min"
BAHSBOT_EVENT_TIMER["example_every5","5"]="example_every5min"
# execute once in the next 10 minutes
BAHSBOT_EVENT_TIMER["example_10min","-10"]="example_in10min"
# once in 10 minutes
BAHSBOT_EVENT_TIMER["example_10min","$(( (EVENT_TIMER+10) * -1 ))"]="example_in10min"
```
* BASHBOT_EVENT_SEND is exceuted if data is send or uploaded to Telegram server
In contrast to other events, BASHBOT_EVENT_SEND is excecuted in a subshell, so there is no need to spawn
a background process for longer running commands and changes to variables are not persistent!
BASHBOT_EVENT_SEND is for logging purposes, you must not send messages while processing this event.
To avoid wrong use of EVENT_SEND, e.g. fork bomb, event processing is suspended if recursion is detected.
*usage*: BASHBOT_EVENT_SEND[ "unique-name" ]="callback"
"callback" is called with paramter "send" or "upload", followed by the arguments used for 'sendJson' or 'upload' functions.
*Example:*
```bash
# register callback:
BAHSBOT_EVENT_SEND["example_log","1"]="example_log"
EXAMPLE_LOG="${BASHBOT_ETC:-.}/addons/${EXAMPLE_ME}.log"
# Note: do not call any send message functions from EVENT_SEND!
example_log(){
local send="$1"; shift
echo "$(date): Type: ${send} Args: $*" >>"${EXAMPLE_LOG}"
}
```
@ -275,5 +321,5 @@ fi
#### [Prev Function Reference](6_reference.md)
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7

View File

@ -55,6 +55,6 @@ convert existing bots.
**external-use** will contain some examples on how to send messages from external scripts to Telegram chats or users.
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7

View File

@ -4,7 +4,7 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# adjust your language setting here
# https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment

View File

@ -2,7 +2,7 @@
# file: run_filename
# background job to display content of all new files in WATCHDIR
#
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# adjust your language setting here
# https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment

View File

@ -2,7 +2,7 @@
# file: run_filename
# background job to display all new files in WATCHDIR
#
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# adjust your language setting here
# https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment

View File

@ -4,7 +4,7 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# adjust your language setting here
# https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment

View File

@ -2,7 +2,7 @@
# file. multibot.sh
# description: run multiple telegram bots from one installation
#
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
if [ "${2}" = "" ] || [ "${2}" = "-h" ]; then
echo "Usage: $0 botname command"

View File

@ -7,7 +7,7 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
SHELL=/bin/sh

View File

@ -5,7 +5,7 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# adjust your language setting here
# https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment

View File

@ -4,7 +4,7 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# adjust your language setting here
# https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment

View File

@ -5,7 +5,7 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# adjust your language setting here
# https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment

View File

@ -1,7 +1,7 @@
# file: botacl
# a user not listed here, will return false from 'user_is_allowed'
#
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# Format:
# user:ressource:chat

View File

@ -5,7 +5,7 @@
# to show how you can customize bashbot by only editing mycommands.sh
# NOTE: this is not tested, simply copied from original source and reworked!
#
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
#
# shellcheck disable=SC2154
# shellcheck disable=SC2034

View File

@ -5,7 +5,7 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
#
# source from commands.sh to use the aliases

View File

@ -5,7 +5,7 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# source from commands.sh to use the inline functions

View File

@ -5,7 +5,7 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# source from commands.sh if you want ro use interactive or background jobs

View File

@ -5,7 +5,7 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# source from commands.sh to use the member functions

View File

@ -5,46 +5,100 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
#
# source from commands.sh to use jsonDB functions
#
# jsonDB rovides simple functions to read and store bash Arrays
# from to file in JSON.sh output format
# jsonDB provides simple functions to read and store bash Arrays
# from to file in JSON.sh output format, its a simple key/value storage.
# read content of a file in JSON.sh format into given ARRAY
# $1 ARRAY name, must be delared with "declare -A ARRAY" upfront
# $2 filename, must be relative to BASHBOT_ETC, and not contain '..'
jssh_readDB() {
local DB; DB="$(jssh_checkname "$2")"
local DB; DB="$(jssh_checkDB "$2")"
[ "${DB}" = "" ] && return 1
[ ! -f "${DB}" ] && return 1
[ ! -f "${DB}" ] && return 2
Json2Array "$1" <"${DB}"
}
# write ARRAY content to a file in JSON.sh format
# Warning: old content is overwritten
# $1 ARRAY name, must be delared with "declare -A ARRAY" upfront
# $2 filename (must exist!), must be relative to BASHBOT_ETC, and not contain '..'
jssh_writeDB() {
local DB; DB="$(jssh_checkname "$2")"
local DB; DB="$(jssh_checkDB "$2")"
[ "${DB}" = "" ] && return 1
[ ! -f "${DB}" ] && return 1
[ ! -f "${DB}" ] && return 2
Array2Json "$1" >"${DB}"
}
# update/write ARRAY content in file without deleting keys not in ARRAY
# $1 ARRAY name, must be delared with "declare -A ARRAY" upfront
# $2 filename (must exist!), must be relative to BASHBOT_ETC, and not contain '..'
jssh_updateDB() {
declare -n ARRAY="$1"
[ "${ARRAY[*]}" = "" ] && return 1
declare -A oldARR newARR
jssh_readDB "oldARR" "$2" || return "$?"
if [ "${oldARR[*]}" = "" ]; then
# no old content
jssh_writeDB "$1" "$2"
else
# merge arrays
local o1 o2 n1 n2
o1="$(declare -p oldARR)"; o2="${o1#*\(}"
n1="$(declare -p ARRAY)"; n2="${n1#*\(}"
unset IFS; set -f
#shellcheck disable=SC2034,SC2190,SC2206
newARR=( ${o2:0:${#o2}-1} ${n2:0:${#n2}-1} )
set +f
jssh_writeDB "newARR" "$2"
fi
}
# insert, update, apped key/value to jsshDB
# $1 key name, can onyl contain -a-zA-Z0-9,._
# $2 key value
# $3 filename (must exist!), must be relative to BASHBOT_ETC, and not contain '..'
jssh_insertDB() {
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3
local key="$1" value="$2"
local DB; DB="$(jssh_checkDB "$3")"
[ "${DB}" = "" ] && return 1
[ ! -f "${DB}" ] && return 2
# its append, but last one counts, its a simple DB ...
printf '["%s"]\t"%s"\n' "${key//,/\",\"}" "${value//\"/\\\"}" >>"${DB}"
}
# get key/value from jsshDB
# $1 key name, can onyl contain -a-zA-Z0-9,._
# $2 key value
# $3 filename (must exist!), must be relative to BASHBOT_ETC, and not contain '..'
# returns value
jssh_getDB() {
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3
declare -A getARR
jssh_readDB "getARR" "$3" || return "$?"
printf '%s\n' "${getARR[${key}]}"
}
# $1 filename (must exist!), must be relative to BASHBOT_ETC, and not contain '..'
jssh_newDB() {
local DB; DB="$(jssh_checkname "$1")"
local DB; DB="$(jssh_checkDB "$1")"
[ "${DB}" = "" ] && return 1
[ -f "${DB}" ] && return 1 # already exist, do not zero out
[ -f "${DB}" ] && return 2 # already exist, do not zero out
printf '\n' >"${DB}"
}
# $1 filename, check if must be relative to BASHBOT_ETC, and not contain '..'
jssh_checkname(){
# $1 filename, check filename, it must be relative to BASHBOT_ETC, and not contain '..'
# returns real path to DB file if everything is ok
jssh_checkDB(){
[ "$1" = "" ] && return 1
local DB="${BASHBOT_ETC:-.}/$1.jssh"
[[ "$1" = "${BASHBOT_ETC:-.}"* ]] && DB="$1.jssh"
[[ "$1" = *'..'* ]] && return 1
[[ "$1" = *'..'* ]] && return 2
printf '%s\n' "${DB}"
}

View File

@ -5,7 +5,7 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# source from commands.sh to use the sendMessage functions
@ -22,7 +22,7 @@ ACTION_URL=$URL'/sendChatAction'
FORWARD_URL=$URL'/forwardMessage'
send_normal_message() {
local text="${2}"
local text="$(JsonEscape "${2}")"
until [ -z "${text}" ]; do
sendJson "${1}" '"text":"'"${text:0:4096}"'"' "${MSG_URL}"
text="${text:4096}"
@ -30,7 +30,7 @@ send_normal_message() {
}
send_markdown_message() {
local text="${2}"
local text="$(JsonEscape "${2}")"
until [ -z "${text}" ]; do
sendJson "${1}" '"text":"'"${text:0:4096}"'","parse_mode":"markdown"' "${MSG_URL}"
text="${text:4096}"
@ -38,7 +38,7 @@ send_markdown_message() {
}
send_html_message() {
local text="${2}"
local text="$(JsonEscape "${2}")"
until [ -z "${text}" ]; do
sendJson "${1}" '"text":"'"${text:0:4096}"'","parse_mode":"html"' "${MSG_URL}"
text="${text:4096}"
@ -46,7 +46,7 @@ send_html_message() {
}
old_send_keyboard() {
local text='"text":"'"${2}"'"'
local text='"text":"'$(JsonEscape "${2}")'"'
shift 2
local keyboard="init"
OLDIFS="$IFS"
@ -64,24 +64,24 @@ sendEmpty() {
}
send_keyboard() {
if [[ "$3" != *'['* ]]; then old_send_keyboard "${@}"; return; fi
local text='"text":"'"${2}"'"'; [ "${2}" = "" ] && text='"text":"'"${ISEMPTY}"'"'
local text='"text":"'$(JsonEscape "${2}")'"'; [ "${2}" = "" ] && text='"text":"'"${ISEMPTY}"'"'
local one_time=', "one_time_keyboard":true' && [ "$4" != "" ] && one_time=""
sendEmpty "${1}" "${text}"', "reply_markup": {"keyboard": [ '"${3}"' ] '"${one_time}"'}' "$MSG_URL"
# '"text":"$2", "reply_markup": {"keyboard": [ ${3} ], "one_time_keyboard": true}'
}
remove_keyboard() {
local text='"text":"'"${2}"'"'; [ "${2}" = "" ] && text='"text":"'"${ISEMPTY}"'"'
local text='"text":"'$(JsonEscape "${2}")'"'; [ "${2}" = "" ] && text='"text":"'"${ISEMPTY}"'"'
sendEmpty "${1}" "${text}"', "reply_markup": {"remove_keyboard":true}' "$MSG_URL"
#JSON='"text":"$2", "reply_markup": {"remove_keyboard":true}'
}
send_inline_keyboard() {
local text='"text":"'"${2}"'"'; [ "${2}" = "" ] && text='"text":"'"${ISEMPTY}"'"'
local text='"text":"'$(JsonEscape "${2}")'"'; [ "${2}" = "" ] && text='"text":"'"${ISEMPTY}"'"'
sendEmpty "${1}" "${text}"', "reply_markup": {"inline_keyboard": [ '"${3}"' ]}' "$MSG_URL"
# JSON='"text":"$2", "reply_markup": {"inline_keyboard": [ $3->[{"text":"text", "url":"url"}]<- ]}'
}
send_button() {
send_inline_keyboard "${1}" "${2}" '[ {"text":"'"${3}"'", "url":"'"${4}"'"}]'
send_inline_keyboard "${1}" "${2}" '[ {"text":"'$(JsonEscape "${3}")'", "url":"'"${4}"'"}]'
}

View File

@ -2,7 +2,7 @@
# files: mycommands.sh.dist
# copy to mycommands.sh and add all your commands and functions here ...
#
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
#
# uncomment the following lines to overwrite info and help messages
@ -16,7 +16,10 @@ res=""
# To enable this option in your bot, send the /setinline command to @BotFather.
export INLINE="0"
# Set to .* to allow sending files from all locations
export FILE_REGEX='/home/user/allowed/.*'
# NOTE: this is a regex, not shell globbing! you must use a valid egex,
# '.' matches any charater and '.*' matches all remaining charatcers!
# additionally you must escape special charaters with '\', e.g. '\. \? \[ \*" to match them literally
export FILE_REGEX='^/home/user/allowed/.*'
# example: run bashbot over TOR
# export BASHBOT_CURL_ARGS="--socks5-hostname 127.0.0.1:9050"

View File

@ -2,7 +2,7 @@
#
# ADD a new test skeleton to test dir, but does not activate test
#
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# magic to ensure that we're always inside the root of our application,
# no matter from which directory we'll run script

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# common variables
export TESTME DIRME TESTDIR LOGFILE REFDIR TESTNAME

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
../dev/hooks/pre-commit.sh

View File

@ -1,6 +1,6 @@
#!/usr/bin/env bash
# file: b-example-test.sh
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# include common functions and definitions
# shellcheck source=test/ALL-tests.inc.sh

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# include common functions and definitions
# shellcheck source=test/ALL-tests.inc.sh

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# include common functions and definitions
# shellcheck source=test/ALL-tests.inc.sh
@ -20,7 +20,7 @@ do
[ "${i}" = "1" ] && echo " ... JSON.sh -s -b -n"
[ "${i}" = "2" ] && echo " ... JSON.sh"
set +f
for jsonfile in ${REFDIR}/*.in
for jsonfile in "${REFDIR}"/*.in
do
set -f
[ "${i}" = "1" ] && "${JSON}" -s -b -n <"${jsonfile}" >"${jsonfile}.out-${i}"

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# include common functions and definitions
# shellcheck source=test/ALL-tests.inc.sh
@ -29,7 +29,7 @@ source <( printf 'UPD=( %s )' "$(sed <<<"${UPDATE}" -E -e 's/\t/=/g' -e 's/=(tru
echo "Check process_inline ..."
for i in 1 2
do
[ "${i}" = "1" ] && ! which python >/dev/null 2>&1 && continue
[ "${i}" = "1" ] && ! command -v python >/dev/null 2>&1 && continue
[ "${i}" = "1" ] && echo " ... with JsonDecode Phyton" && unset BASHBOT_DECODE
[ "${i}" = "2" ] && echo " ... with JsonDecode Bash" && export BASHBOT_DECODE="yes"
set -x

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# include common functions and definitions
# shellcheck source=test/ALL-tests.inc.sh

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# include common functions and definitions
# shellcheck source=test/ALL-tests.inc.sh

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# include common functions and definitions
# shellcheck source=test/ALL-tests.inc.sh

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
#### $$VERSION$$ v0.91-0-g31808a9
#### $$VERSION$$ v0.94-dev2-0-g3d636f7
# include common functions and definitions
# shellcheck source=test/ALL-tests.inc.sh