Merge pull request #171: Bashbot Version 1.30

Bashbot Version 1.30
This commit is contained in:
Kay Marquardt 2021-01-18 13:16:48 +01:00 committed by GitHub
commit ad532cce54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
75 changed files with 1609 additions and 1209 deletions

View File

@ -316,10 +316,10 @@ Written by Drew (@topkecleon) and Kay M (@gnadelwartz).
<pre><code>/start <pre><code>/start
You are Botadmin You are Botadmin
*Available commands*: Available commands:
*• /start*: _Start bot and get this message_. /start: _Start bot and get this message_.
*• /help*: _Get this message_. /help: _Get this message_.
*• /info*: _Get shorter info message about this bot_.... /info: _Get shorter info message about this bot_....
/info /info
@ -329,12 +329,12 @@ It features background tasks and interactive chats, and can serve as an interfac
<h3>Log files</h3> <h3>Log files</h3>
<p>Bashbot actions are logged to <code>BASHBOT.log</code>. Telegram send/receive errors are logged to <code>ERROR.log</code>. Start bashbot in debug mode to see all messages sent to / received from Telegram, as well as bash command error messages.</p> <p>Bashbot actions are logged to <code>BASHBOT.log</code>. Telegram send/receive errors are logged to <code>ERROR.log</code>. Start bashbot in debug mode to see all messages sent to / received from Telegram, as well as bash command error messages.</p>
<p>To enable debug mode, start bashbot with debug as third argument: <code>bashbot start debug</code></p> <p>To enable debug mode, start bashbot with debug as third argument: <code>bashbot start debug</code></p>
<pre><code>├── logs <pre><code>|__ logs
│   ├── BASHBOT.log # log what your bot is doing ... | |__ BASHBOT.log # log what your bot is doing ...
│   ├── ERROR.log # connection errors from / to Telegram API | |__ ERROR.log # connection errors from / to Telegram API
│   │ | |
│   ├── DEBUG.log # stdout/stderr of you bot (debug mode enabled) | |__ DEBUG.log # stdout/stderr of you bot (debug mode enabled)
│   └── MESSAGE.log # full text of all message send/received (debug mode enabled)</code></pre> | |__ MESSAGE.log # full text of all message send/received (debug mode enabled)</code></pre>
<hr /> <hr />
<h2>Security Considerations</h2> <h2>Security Considerations</h2>
<p>Running a Telegram Bot means it is connected to the public and you never know what's send to your Bot.</p> <p>Running a Telegram Bot means it is connected to the public and you never know what's send to your Bot.</p>
@ -390,6 +390,6 @@ It features background tasks and interactive chats, and can serve as an interfac
<p>@Gnadelwartz</p> <p>@Gnadelwartz</p>
<h2>That's it all guys!</h2> <h2>That's it all guys!</h2>
<p>If you feel that there's something missing or if you found a bug, feel free to submit a pull request!</p> <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$$ v1.21-0-gc85af77</h4> <h4>$$VERSION$$ v1.30-0-g3266427</h4>
</body> </body>
</html> </html>

View File

@ -104,10 +104,10 @@ Now open the Telegram App on your mobile phone and start a chat with your bot (_
/start /start
You are Botadmin You are Botadmin
*Available commands*: Available commands:
*• /start*: _Start bot and get this message_. /start: _Start bot and get this message_.
*• /help*: _Get this message_. /help: _Get this message_.
*• /info*: _Get shorter info message about this bot_.... /info: _Get shorter info message about this bot_....
/info /info
@ -124,12 +124,12 @@ Start bashbot in debug mode to see all messages sent to / received from Telegram
To enable debug mode, start bashbot with debug as third argument: `bashbot start debug` To enable debug mode, start bashbot with debug as third argument: `bashbot start debug`
``` ```
├── logs |__ logs
│   ├── BASHBOT.log # log what your bot is doing ... | |__ BASHBOT.log # log what your bot is doing ...
│   ├── ERROR.log # connection errors from / to Telegram API | |__ ERROR.log # connection errors from / to Telegram API
│   │ | |
│   ├── DEBUG.log # stdout/stderr of you bot (debug mode enabled) | |__ DEBUG.log # stdout/stderr of you bot (debug mode enabled)
│   └── MESSAGE.log # full text of all message send/received (debug mode enabled) | |__ MESSAGE.log # full text of all message send/received (debug mode enabled)
``` ```
---- ----
@ -238,4 +238,4 @@ See `mycommnds.sh.dist` for an example.
If you feel that there's something missing or if you found a bug, feel free to submit a pull request! If you feel that there's something missing or if you found a bug, feel free to submit a pull request!
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427

View File

@ -1,324 +1,313 @@
<h2><img align="middle"
src="https://raw.githubusercontent.com/odb/official-bash-logo/master/assets/Logo ..
s/Icons/PNG/64x64.png" > ****
Bashbot - A Telegram bot written in bash. ****oooooo*****
</h2> *****ooooooooooooo*****
*****oooooooooooooooooooooo****
****oooooooooooooooooooooooooooooooo**
*.*oooooooooooooooooooooooooooooooooooo**
*.ooooooooooooooooooooooooooooooooo**....
*.oooooooooooooooooooooooooooo**.........
*.oooooooooooooooooooooooo**.............
*.ooooooooooooooooooo**.................. ____ _ _ _
*.ooooooooooooooooo*.......,............. | _ \ | | | | | |
*.ooooooooooooooooo*.....,***,........... | |_) | __ _ ___ | |__ | |__ ___ | |_
*.ooooooooooooooooo*....o*............... | _ < / _` |/ __|| '_ \ | '_ \ / _ \ | __|
*.ooooooooooooooooo*....*o***,........... | |_) || (_| |\__ \| | | || |_) || (_) || |_
*.*oooooooooooooooo*........o*.....oo.... |____/ \__,_||___/|_| |_||_.__/ \___/ \__|
****ooooooooooooo*....`***....oo.....*
*****oooooooo*......*..oo.....**
******ooo*.............*
***o*........**
**...**
Bashbot README
Bashbot - A Telegram bot written in bash.
Written by Drew (@topkecleon) and Kay M (@gnadelwartz). Written by Drew (@topkecleon) and Kay M (@gnadelwartz).
Contributions by Daniil Gentili (@danog), JuanPotato, BigNerd95, TiagoDanin, iicc1 and
dcoomber.
Released to the public domain wherever applicable. Elsewhere, consider it released under
the WTFPLv2 [http://www.wtfpl.net/txt/copying/].
Linted by #ShellCheck
Contributions by Daniil Gentili (@danog), JuanPotato, BigNerd95, TiagoDanin, Prerequisites
iicc1 and dcoomber.
Released to the public domain wherever applicable. Uses JSON.sh [http://github.com/dominictarr/JSON.sh] and the magic of sed.
Elsewhere, consider it released under the Bashbot is written in bash. It depends on commands typically available in a Linux/Unix
[WTFPLv2](http://www.wtfpl.net/txt/copying/). Environment. For more concrete information on the common commands provided by recent
versions of coreutils [https://en.wikipedia.org/wiki/List_of_GNU_Core_Utilities_commands],
busybox or toybox, see Developer_Notes.
Note for MacOS and BSD Users: Bashbot will not run without installing additional software
as it uses modern bash and (gnu) grep/sed features. See Install Bashbot [doc/
0_install.md].
Note for embedded systems: You need to install a "real" bash as the vanilla installation
of busybox or toybox is not sufficient. See Install Bashbot [doc/0_install.md].
Bashbot Documentation [https://github.com/topkecleon/telegram-bot-bash] and Downloads are
available on www.github.com.
Linted by [#ShellCheck](https://github.com/koalaman/shellcheck) Documentation
## Prerequisites
Uses [JSON.sh](http://github.com/dominictarr/JSON.sh) and the magic of sed.
Bashbot is written in bash. It depends on commands typically available in a * Introduction to Telegram Bots [https://core.telegram.org/bots]
Linux/Unix Environment. * Install Bashbot [doc/0_install.md]
For more concrete information on the common commands provided by recent
versions of
[coreutils](https://en.wikipedia.org/wiki/List_of_GNU_Core_Utilities_commands),
[busybox](https://en.wikipedia.org/wiki/BusyBox#Commands) or
[toybox](https://landley.net/toybox/help.html), see [Developer
Notes](doc/7_develop.md#common-commands).
**Note for MacOS and BSD Users:** Bashbot will not run without installing o Install release
additional software as it uses modern bash and (gnu) grep/sed features. See o Install from github
[Install Bashbot](doc/0_install.md). o Update Bashbot
o Notes on Updates
**Note for embedded systems:** You need to install a "real" bash as the vanilla * Get Bottoken from Botfather [doc/1_firstbot.md]
installation of busybox or toybox is not sufficient. See [Install * Getting Started [doc/2_usage.md]
Bashbot](doc/0_install.md).
Bashbot [Documentation](https://github.com/topkecleon/telegram-bot-bash) and o Managing your Bot
[Downloads](https://github.com/topkecleon/telegram-bot-bash/releases) are o Receive data
available on [www.github.com](https://www.github.com). o Send messages
o Send files, locations, keyboards
## Documentation * Advanced Features [doc/3_advanced.md]
* [Introduction to Telegram Bots](https://core.telegram.org/bots)
* [Install Bashbot](doc/0_install.md)
* Install release
* Install from github
* Update Bashbot
* Notes on Updates
* [Get Bottoken from Botfather](doc/1_firstbot.md)
* [Getting Started](doc/2_usage.md)
* Managing your Bot
* Receive data
* Send messages
* Send files, locations, keyboards
* [Advanced Features](doc/3_advanced.md)
* Access Control
* Interactive Chats
* Background Jobs
* Inline queries
* Send message errors
* [Expert Use](doc/4_expert.md)
* Handling UTF-8 character sets
* Run as other user or system service
* Schedule bashbot from Cron
* Use from CLI and Scripts
* Customize Bashbot Environment
* [Best Practices](doc/5_practice.md)
* Customize mycommands.sh
* Overwrite/disable commands
* Separate logic from commands
* Test your Bot with shellcheck
* [Function Reference](doc/6_reference.md)
* Sending Messages, Files, Keyboards
* User Access Control
* Inline Queries
* jsshDB Bashbot key-value storage
* Background and Interactive Jobs
* [Developer Notes](doc/7_develop.md)
* Debug bashbot
* Modules, addons, events
* Setup your environment
* Bashbot test suite
* [Examples Directory](examples/README.md)
### Your very first bashbot in a nutshell o Access Control
o Interactive Chats
o Background Jobs
o Inline queries
o Send message errors
To install and run bashbot you need access to a Linux/Unix command line with * Expert Use [doc/4_expert.md]
bash, a [Telegram client](https://telegram.org) and a mobile phone [with a
Telegram account](https://telegramguide.com/create-a-telegram-account/).
First you need to [create a new Telegram Bot token](doc/1_firstbot.md) for your o Handling UTF-8 character sets
bot and write it down. o Run as other user or system service
o Schedule bashbot from Cron
o Use from CLI and Scripts
o Customize Bashbot Environment
Now open a Linux/Unix terminal with bash, create a new directory, change to it * Best Practices [doc/5_practice.md]
and install telegram-bot-bash:
```bash o Customize mycommands.sh
# create bot dir o Overwrite/disable commands
mkdir mybot o Separate logic from commands
cd mybot o Test your Bot with shellcheck
# download latest release with wget or from * Function Reference [doc/6_reference.md]
https://github.com/topkecleon/telegram-bot-bash/releases/latest
wget "https://github.com/$(wget -q
"https://github.com/topkecleon/telegram-bot-bash/releases/latest" -O - | egrep
'/.*/download/.*/.*tar.gz' -o)"
# Extract the tar archive and go into bot dir o Sending Messages, Files, Keyboards
tar -xzf *.tar.gz o User Access Control
cd telegram-bot-bash o Inline Queries
o jsshDB Bashbot key-value storage
o Background and Interactive Jobs
# initialize your bot * Developer Notes [doc/7_develop.md]
# Enter your bot token when asked, all other questions can be answered by
hitting the \<Return\> key.
./bashbot.sh init
# Now start your bot o Debug bashbot
./bashbot.sh start o Modules, addons, events
o Setup your environment
o Bashbot test suite
Bottoken is valid ... * Examples Directory [examples/README.md]
Bot Name: yourbotname_bot
Session Name: yourbotname_bot-startbot
Bot started successfully.
```
Now open the Telegram App on your mobile phone and start a chat with your bot
(_your bot's username is shown after 'Bot Name:'_):
``` Your very first bashbot in a nutshell
/start
You are Botadmin To install and run bashbot you need access to a Linux/Unix command line with bash, a
*Available commands*: Telegram client [https://telegram.org] and a mobile phone with_a_Telegram_account.
*• /start*: _Start bot and get this message_. First you need to create a new Telegram Bot token [doc/1_firstbot.md] for your bot and
*• /help*: _Get this message_. write it down.
*• /info*: _Get shorter info message about this bot_.... Now open a Linux/Unix terminal with bash, create a new directory, change to it and install
telegram-bot-bash:
/info # create bot dir
mkdir mybot
cd mybot
This is bashbot, the Telegram bot written entirely in bash. # download latest release with wget or from https://github.com/topkecleon/telegram-bot-
It features background tasks and interactive chats, and can serve as an bash/releases/latest
interface for CLI programs. wget &quot;https://github.com/$(wget -q &quot;https://github.com/topkecleon/telegram-
``` bot-bash/releases/latest&quot; -O - | egrep '/.*/download/.*/.*tar.gz' -o)&quot;
For more Information on how to install, customize and use your new bot, read
the [Documentation](#Documentation).
### Log files # Extract the tar archive and go into bot dir
tar -xzf *.tar.gz
cd telegram-bot-bash
Bashbot actions are logged to `BASHBOT.log`. Telegram send/receive errors are # initialize your bot
logged to `ERROR.log`. # Enter your bot token when asked, all other questions can be answered by hitting the
Start bashbot in debug mode to see all messages sent to / received from \<Return\> key.
./bashbot.sh init
# Now start your bot
./bashbot.sh start
Bottoken is valid ...
Bot Name: yourbotname_bot
Session Name: yourbotname_bot-startbot
Bot started successfully.
Now open the Telegram App on your mobile phone and start a chat with your bot (your bot's
username is shown after 'Bot Name:'):
/start
You are Botadmin
Available commands:
/start: _Start bot and get this message_.
/help: _Get this message_.
/info: _Get shorter info message about this bot_....
/info
This 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.
For more Information on how to install, customize and use your new bot, read the
Documentation [#Documentation].
Log files
Bashbot actions are logged to BASHBOT.log. Telegram send/receive errors are logged to
ERROR.log. Start bashbot in debug mode to see all messages sent to / received from
Telegram, as well as bash command error messages. Telegram, as well as bash command error messages.
To enable debug mode, start bashbot with debug as third argument: bashbot start debug
To enable debug mode, start bashbot with debug as third argument: `bashbot |__ logs
start debug` | |__ BASHBOT.log # log what your bot is doing ...
| |__ ERROR.log # connection errors from / to Telegram API
| |
| |__ DEBUG.log # stdout/stderr of you bot (debug mode enabled)
| |__ MESSAGE.log # full text of all message send/received (debug mode enabled)
``` ------------------------------------------------------------------------------------------
├── logs
│   ├── BASHBOT.log # log what your bot is doing ...
│   ├── ERROR.log # connection errors from / to Telegram API
│   │
│   ├── DEBUG.log # stdout/stderr of you bot (debug mode enabled)
│   └── MESSAGE.log # full text of all message send/received (debug mode
enabled)
```
---- Security Considerations
## Security Considerations Running a Telegram Bot means it is connected to the public and you never know what's send
Running a Telegram Bot means it is connected to the public and you never know to your Bot.
what's send to your Bot. Bash scripts in general are not designed to be bulletproof, so consider this Bot as a
proof of concept. Bash programmers often struggle with 'quoting hell' and globbing, see
Implications of wrong quoting [https://unix.stackexchange.com/questions/171346/security-
implications-of-forgetting-to-quote-a-variable-in-bash-posix-shells].
Whenever you are processing input from untrusted sources (messages, files, network) you
must be as careful as possible (e.g. set IFS appropriately, disable globbing with set -
f and quote everything). In addition remove unused scripts and examples from your Bot
(e.g. everything in example/) and disable/remove all unused bot commands.
It's important to escape or remove $ in input from user, files or network (as bashbot
does). One of the powerful features of Unix shells is variable and command substitution
using ${} and$() can lead to remote code execution (RCE) or remote information disclosure
(RID) bugs if unescaped $ is included in untrusted input (e.g. $$ or $(rm -rf /*)).
A powerful tool to improve your scripts is shellcheck. You can use it online [https://
www.shellcheck.net/] or install_shellcheck_locally. Shellcheck is used extensively in
bashbot development to ensure a high code quality (e.g. it's not allowed to push changes
without passing all shellcheck tests). In addition bashbot has a test_suite to check if
important functionality is working as expected.
Bash scripts in general are not designed to be bulletproof, so consider this Use printf whenever possible
Bot as a proof of concept.
Bash programmers often struggle with 'quoting hell' and globbing,
see [Implications of wrong
quoting](https://unix.stackexchange.com/questions/171346/security-implications-o
f-forgetting-to-quote-a-variable-in-bash-posix-shells).
Whenever you are processing input from untrusted sources (messages, files, If you're writing a script that accepts external input (e.g. from the user as arguments or
network) you must be as careful as possible the file system), you shouldn't use echo to display it. Use printf whenever possible
(e.g. set IFS appropriately, disable globbing with `set -f` and quote [https://unix.stackexchange.com/a/6581].
everything). In addition remove unused scripts and examples
from your Bot (e.g. everything in `example/`) and disable/remove all unused bot
commands.
It's important to escape or remove `$` in input from user, files or network Run your Bot as a restricted user
(_as bashbot does_).
One of the powerful features of Unix shells is variable and command
substitution using `${}` and`$()` can lead to remote code execution (RCE) or
remote information disclosure (RID) bugs if unescaped `$` is included in
untrusted input (e.g. `$$` or `$(rm -rf /*)`).
A powerful tool to improve your scripts is `shellcheck`. You can [use it I recommend running your bot as a user with almost no access rights. All files your Bot
online](https://www.shellcheck.net/) or has write access to are in danger of being overwritten/deleted if your bot is hacked. For
[install shellcheck the same reason every file your Bot can read is in danger of being disclosed. Restrict
locally](https://github.com/koalaman/shellcheck#installing). Shellcheck is used your Bots access rights to the absolute minimum.
extensively in bashbot development Never run your Bot as root, this is the most dangerous you can do! Usually the user
to ensure a high code quality (e.g. it's not allowed to push changes without 'nobody' has almost no rights on Linux/Unix systems. See Expert use [doc/4_expert.md] on
passing all shellcheck tests). how to run your Bot as an other user.
In addition bashbot has a [test suite](doc/7_develop.md) to check if important
functionality is working as expected.
### Use printf whenever possible Secure your Bot installation
If you're writing a script that accepts external input (e.g. from the user as Your Bot configuration must not be readable by other users. Everyone who can read your
arguments or the file system), Bots token is able to act as your Bot and has access to all chats the Bot is in!
you shouldn't use echo to display it. [Use printf whenever Everyone with read access to your Bot files can extract your Bots data. Especially your
possible](https://unix.stackexchange.com/a/6581). Bot config inconfig.jssh must be protected against other users. No one except you should
have write access to the Bot files. The Bot should be restricted to have write access
tocount.jssh and data-bot-bash only, all other files must be write protected.
To set access rights for your bashbot installation to a reasonable default runsudo ./
bashbot.sh init after every update or change to your installation directory.
### Run your Bot as a restricted user FAQ
**I recommend running your bot as a user with almost no access rights.**
All files your Bot has write access to are in danger of being
overwritten/deleted if your bot is hacked.
For the same reason every file your Bot can read is in danger of being
disclosed. Restrict your Bots access rights to the absolute minimum.
**Never run your Bot as root, this is the most dangerous you can do!** Usually
the user 'nobody' has almost no rights on Linux/Unix systems. See [Expert
use](doc/4_expert.md) on how to run your Bot as an other user.
### Secure your Bot installation
**Your Bot configuration must not be readable by other users.** Everyone who
can read your Bots token is able to act as your Bot and has access to all chats
the Bot is in!
Everyone with read access to your Bot files can extract your Bots data.
Especially your Bot config in`config.jssh` must be protected against other
users. No one except you should have write access to the Bot files. The Bot
should be restricted to have write access to`count.jssh` and `data-bot-bash`
only, all other files must be write protected.
To set access rights for your bashbot installation to a reasonable default
run`sudo ./bashbot.sh init` after every update or change to your installation
directory.
## FAQ
### Is this Bot insecure?
Bashbot is not more (in)secure than a Bot written in another 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 ...
**Note:** Up to version 0.941 (mai/22/2020) telegram-bot-bash had a remote code
execution bug, please update if you use an older version!
### Why Bash and not the much better xyz?
Well, that's a damn good question... maybe because I'm a Unix admin from the
stone age. Nevertheless there are more reasons from my side:
- bashbot will run wherever bash and (gnu) sed is available, from embedded
Linux to mainframe
- easy to integrate with other shell scripts, e.g. for sending system message /
health status
- no need to install or learn a new programming language, library or framework
- no database, not event driven, not object oriented ...
### Can I have the single bashbot.sh file back?
At the beginning bashbot was simply the file`bashbot.sh` that you could copy
everywhere and run the bot. Now we have 'commands.sh', 'mycommands.sh',
'modules/*.sh' and much more.
Hey no problem, if you are finished with your cool bot,
run`dev/make-standalone.sh` to create a stripped down version of your bot
containing only
'bashbot.sh' and 'commands.sh'! For more information see [Create a stripped
down version of your Bot](doc/7_develop.md).
### Can I send messages from CLI and scripts?
Of course you can send messages from command line and scripts! Simply install
bashbot as [described here](#Your-really-first-bashbot-in-a-nutshell),
send the message '/start' to set yourself as botadmin and then stop the bot
with `./bashbot.sh stop`.
Bashbot provides some ready to use scripts for sending messages from command
line in `bin/` dir, e.g. `send_message.sh`.
```bash
bin/send_message.sh BOTADMIN "This is my first message send from CLI"
bin/send_message.sh --help
```
You can also source bashbot for use in your scripts, for more information see
[Expert Use](doc/4_expert.md).
### Blocked by telegram? Is this Bot insecure?
This may happen if too many or wrong requests are sent to api.telegram.org,
e.g. using a invalid token or invalid API calls.
If the block stay for longer time you can ask telegram service to unblock your
IP-Address.
Bashbot is not more (in)secure than a Bot written in another 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 ...
Note: Up to version 0.941 (mai/22/2020) telegram-bot-bash had a remote code execution bug,
please update if you use an older version!
Why Bash and not the much better xyz?
Well, that's a damn good question... maybe because I'm a Unix admin from the stone age.
Nevertheless there are more reasons from my side:
* bashbot will run wherever bash and (gnu) sed is available, from embedded Linux to
mainframe
* easy to integrate with other shell scripts, e.g. for sending system message / health
status
* no need to install or learn a new programming language, library or framework
* no database, not event driven, not object oriented ...
Can I have the single bashbot.sh file back?
At the beginning bashbot was simply the filebashbot.sh that you could copy everywhere and
run the bot. Now we have 'commands.sh', 'mycommands.sh', 'modules/*.sh' and much more.
Hey no problem, if you are finished with your cool bot, rundev/make-standalone.sh to
create a stripped down version of your bot containing only 'bashbot.sh' and 'commands.sh'!
For more information see Create a stripped down version of your Bot [doc/7_develop.md].
Can I send messages from CLI and scripts?
Of course you can send messages from command line and scripts! Simply install bashbot as
described here [#Your-really-first-bashbot-in-a-nutshell], send the message '/start' to
set yourself as botadmin and then stop the bot with ./bashbot.sh stop.
Bashbot provides some ready to use scripts for sending messages from command line in bin/
dir, e.g. send_message.sh.
bin/send_message.sh BOTADMIN &quot;This is my first message send from CLI&quot;
bin/send_message.sh --help
You can also source bashbot for use in your scripts, for more information see Expert Use
[doc/4_expert.md].
Blocked by telegram?
This may happen if too many or wrong requests are sent to api.telegram.org, e.g. using a
invalid token or invalid API calls. If the block stay for longer time you can ask telegram
service to unblock your IP-Address.
You can check with curl or wget if you are blocked by Telegram: You can check with curl or wget if you are blocked by Telegram:
```bash
curl -m 10 https://api.telegram.org/bot
#curl: (28) Connection timed out after 10001 milliseconds
wget -t 1 -T 10 https://api.telegram.org/bot curl -m 10 https://api.telegram.org/bot
#Connecting to api.telegram.org (api.telegram.org)|46.38.243.234|:443... #curl: (28) Connection timed out after 10001 milliseconds
failed: Connection timed out.
nc -w 2 api.telegram.org 443 || echo "your IP seems blocked by telegram" wget -t 1 -T 10 https://api.telegram.org/bot
#your IP seems blocked by telegram #Connecting to api.telegram.org (api.telegram.org)|46.38.243.234|:443... failed:
``` Connection timed out.
Bashbot offers the option to recover from broken connections (blocked). nc -w 2 api.telegram.org 443 || echo &quot;your IP seems blocked by telegram&quot;
Therefore you can provide a function #your IP seems blocked by telegram
named `bashbotBlockRecover()` in `mycommands.sh`, the function is called every
time when a broken connection is detected.
Possible actions are: Check if network is working, change IP-Address or simply
wait some time.
See `mycommnds.sh.dist` for an example.
---
Bashbot offers the option to recover from broken connections (blocked). Therefore you can
provide a function named bashbotBlockRecover() in mycommands.sh, the function is called
every time when a broken connection is detected.
Possible actions are: Check if network is working, change IP-Address or simply wait some
time. See mycommnds.sh.dist for an example.
------------------------------------------------------------------------------------------
@Gnadelwartz @Gnadelwartz
## That's it all guys! That's it all guys!
If you feel that there's something missing or if you found a bug, feel free to If you feel that there's something missing or if you found a bug, feel free to submit a
submit a pull request! pull request!
$$VERSION$$ v1.30-0-g3266427
#### $$VERSION$$ v1.21-0-gc85af77

View File

@ -4,7 +4,7 @@
# this addon counts how many files, e.g. stickers, are sent to # this addon counts how many files, e.g. stickers, are sent to
# a chat and takes actions if threshold is reached # a chat and takes actions if threshold is reached
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
# used events: # used events:
# #
@ -37,7 +37,7 @@ ANTIFL_BAN="5" # 5 minutes
# initialize after installation or update # initialize after installation or update
if [[ "$1" = "init"* ]]; then if [[ "$1" = "init"* ]]; then
jssh_newDB "addons/$ANTIFL_ME" jssh_newDB "addons/${ANTIFL_ME}"
fi fi
@ -46,7 +46,7 @@ fi
if [[ "$1" = "start"* ]]; then if [[ "$1" = "start"* ]]; then
ANTIFL_ADMIN="$(getConfigKey "botadmin")" ANTIFL_ADMIN="$(getConfigKey "botadmin")"
#load existing chat settings on start #load existing chat settings on start
jssh_readDB "ANTIFL_CHATS" "addons/$ANTIFL_ME" jssh_readDB "ANTIFL_CHATS" "addons/${ANTIFL_ME}"
# register to CMD # register to CMD
BASHBOT_EVENT_CMD["${ANTIFL_ME}"]="${ANTIFL_ME}_cmd" BASHBOT_EVENT_CMD["${ANTIFL_ME}"]="${ANTIFL_ME}_cmd"
@ -71,14 +71,14 @@ if [[ "$1" = "start"* ]]; then
"/afdo" | "/afactive") "/afdo" | "/afactive")
[[ "${CMD[1]}" =~ ^[-0-9]+$ ]] && user_is_botadmin "${USER[ID]}" && chat="$3" [[ "${CMD[1]}" =~ ^[-0-9]+$ ]] && user_is_botadmin "${USER[ID]}" && chat="$3"
ANTIFL_CHATS["${chat}","active"]="yes" ANTIFL_CHATS["${chat}","active"]="yes"
jssh_writeDB "ANTIFL_CHATS" "addons/$ANTIFL_ME" & jssh_writeDB "ANTIFL_CHATS" "addons/${ANTIFL_ME}" &
send_normal_message "${USER[ID]}" "Antiflood activated for chat ${chat}" & send_normal_message "${USER[ID]}" "Antiflood activated for chat ${chat}" &
;; ;;
# command /afactive starts counter meausares # command /afactive starts counter meausares
"/afstop") "/afstop")
[[ "${CMD[1]}" =~ ^[-0-9]+$ ]] && user_is_botadmin "${USER[ID]}" && chat="$3" [[ "${CMD[1]}" =~ ^[-0-9]+$ ]] && user_is_botadmin "${USER[ID]}" && chat="$3"
ANTIFL_CHATS["${chat}","active"]="no" ANTIFL_CHATS["${chat}","active"]="no"
jssh_writeDB "ANTIFL_CHATS" "addons/$ANTIFL_ME" & jssh_writeDB "ANTIFL_CHATS" "addons/${ANTIFL_ME}" &
send_normal_message "${USER[ID]}" "Antiflood stopped for chat ${chat}" & send_normal_message "${USER[ID]}" "Antiflood stopped for chat ${chat}" &
;; ;;
esac esac
@ -90,7 +90,7 @@ if [[ "$1" = "start"* ]]; then
# save settings and reset flood level every BAN Min # save settings and reset flood level every BAN Min
antiFlood_timer(){ antiFlood_timer(){
ANTIFL_ACTUALS=( ) ANTIFL_ACTUALS=( )
jssh_writeDB "ANTIFL_CHATS" "addons/$ANTIFL_ME" & jssh_writeDB "ANTIFL_CHATS" "addons/${ANTIFL_ME}" &
} }
# register to inline and command # register to inline and command

View File

@ -4,7 +4,7 @@
# Addons can register to bashbot events at startup # Addons can register to bashbot events at startup
# by providing their name and a callback per event # by providing their name and a callback per event
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
# #
# If an event occurs each registered event function is called. # If an event occurs each registered event function is called.
# #

View File

@ -5,7 +5,7 @@
# #
# tested on: ubuntu, opensuse, debian # tested on: ubuntu, opensuse, debian
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
# shellcheck disable=SC2009 # shellcheck disable=SC2009
# shellcheck disable=SC2181 # shellcheck disable=SC2181
@ -30,34 +30,40 @@ runcmd="echo Dry run:" # not activated until you edit lines below
runas="nobody" runas="nobody"
# uncomment one of the example lines to fit your system # uncomment one of the example lines to fit your system
# runcmd="su $runas -s /bin/bash -c " # runasuser with *su* # runcmd="su ${runas} -s /bin/bash -c " # runasuser with *su*
# runcmd="runuser $runas -s /bin/bash -c " # runasuser with *runuser* # runcmd="runuser ${runas} -s /bin/bash -c " # runasuser with *runuser*
# edit the values of the following lines to fit your config: # edit the values of the following lines to fit your config:
start="cd /usr/local/telegram-bot-bash; /usr/local/telegram-bot-bash/bashbot.sh" # location of your bashbot.sh script # your bot installation dir
name='' # your bot name as given to botfather, e.g. mysomething_bot bashbot="cd /usr/local/telegram-bot-bash; /usr/local/telegram-bot-bash/bashbot.sh"
# your bot name as given to botfather, e.g. mysomething_bot
name=""
# set additionl parameter, e.g. debug
mode=""
# END Configuration # END Configuration
####################### #######################
[ "$name" = "" ] && name="$runas" [ "${name}" = "" ] && name="${runas}"
case "$1" in case "$1" in
'start') 'start')
$runcmd "$start start" # >/dev/null 2>&1 </dev/null # shellcheck disable=SC2250
$runcmd "$bashbot start $mode" # >/dev/null 2>&1 </dev/null
RETVAL=$? RETVAL=$?
;; ;;
'stop') 'stop')
$runcmd "$start stop" # shellcheck disable=SC2250
$runcmd "$bashbot stop $mode"
RETVAL=$? RETVAL=$?
;; ;;
'status') 'status')
ps -f -u "$runas" | grep "$name" | grep -qF "bashbot.sh startbot" ps -f -u "${runas}" | grep "${name}" | grep -qF "bashbot.sh startbot"
if [ "$?" = "0" ]; then if [ "$?" = "0" ]; then
printf "bashbot (%s) is runningi\n" "$name" printf "bashbot (%s) is running\n" "${name}"
RETVAL=0 RETVAL=0
else else
printf "bashbot (%s) is stopped\n" "$name" printf "bashbot (%s) is stopped\n" "${name}"
RETVAL=1 RETVAL=1
fi fi
;; ;;
@ -70,12 +76,13 @@ case "$1" in
RETVAL=$? RETVAL=$?
;; ;;
'suspendback'|'resumeback'|'killback') 'suspendback'|'resumeback'|'killback')
$runcmd "$start $1" # shellcheck disable=SC2250
$runcmd "$bashbot $1 $mode"
RETVAL=$? RETVAL=$?
# kill inotifywait from runuser # kill inotifywait from runuser
if [ "$1" != "resumeback" ]; then if [ "$1" != "resumeback" ]; then
# shellcheck disable=SC2046 # shellcheck disable=SC2046
kill -9 $(ps -u "$runas" | grep inotifywait | sed 's/ .*//') >/dev/null 2>&1 kill -9 $(ps -u "${runas}" | grep inotifywait | sed 's/ .*//') >/dev/null 2>&1
fi fi
;; ;;
*) *)
@ -83,4 +90,4 @@ case "$1" in
RETVAL=1 RETVAL=1
;; ;;
esac esac
exit $RETVAL exit "${RETVAL}"

View File

@ -15,8 +15,8 @@
# This file is public domain in the USA and all free countries. # This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
# #
# Usage: bashbot.sh [-h|--help|BOTCOMMANDS] # Usage: bashbot.sh BOTCOMMAND
BOTCOMMANDS="start, stop, status, help, init, suspendback, resumeback, killback" BOTCOMMANDS="-h help init start stop status suspendback resumeback killback"
# #
# Exit Codes: # Exit Codes:
# 0 - success (hopefully) # 0 - success (hopefully)
@ -30,7 +30,7 @@
# 8 - curl/wget missing # 8 - curl/wget missing
# 10 - not bash! # 10 - not bash!
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
################################################################## ##################################################################
# emmbeded system may claim bash but it is not # emmbeded system may claim bash but it is not
@ -42,7 +42,7 @@ fi
# are we running in a terminal? # are we running in a terminal?
NN="\n" NN="\n"
if [ -t 1 ] && [ -n "$TERM" ]; then if [ -t 1 ] && [ -n "${TERM}" ]; then
INTERACTIVE='yes' INTERACTIVE='yes'
RED='\e[31m' RED='\e[31m'
GREEN='\e[32m' GREEN='\e[32m'
@ -63,47 +63,80 @@ if [ "$({ LC_ALL=C.utf-8 printf "%b" "\u1111"; } 2>/dev/null)" = "\u1111" ]; the
fi fi
# in UTF-8 äöü etc. are part of [:alnum:] and ranges (e.g. a-z), but we want ASCII a-z ranges!
# for more information see doc/4_expert.md#Character_classes
azazaz='abcdefghijklmnopqrstuvwxyz' # a-z :lower:
AZAZAZ='ABCDEFGHIJKLMNOPQRSTUVWXYZ' # A-Z :upper:
o9o9o9='0123456789' # 0-9 :digit:
azAZaz="${azazaz}${AZAZAZ}" # a-zA-Z :alpha:
azAZo9="${azAZaz}${o9o9o9}" # a-zA-z0-9 :alnum:
# some important helper functions # some important helper functions
# returns true if command exist # returns true if command exist
_exists() { _exists() {
[ "$(type -t "${1}")" = "file" ] [ "$(type -t "$1")" = "file" ]
} }
# execute function if exists # execute function if exists
_exec_if_function() { _exec_if_function() {
[ "$(type -t "${1}")" != "function" ] && return 1 [ "$(type -t "$1")" != "function" ] && return 1
"$@" "$@"
} }
# returns true if function exist # returns true if function exist
_is_function() { _is_function() {
[ "$(type -t "${1}")" = "function" ] [ "$(type -t "$1")" = "function" ]
} }
# round $1 in international notation! , returns float with $2 decimal digits # round $1 in international notation! , returns float with $2 decimal digits
# if $2 is not given or is not a positive number zero is assumed # if $2 is not given or is not a positive number zero is assumed
_round_float() { _round_float() {
local digit="${2}"; [[ "${2}" =~ ^[0-9]+$ ]] || digit="0" local digit="$2"; [[ "$2" =~ ^[${o9o9o9}]+$ ]] || digit="0"
{ LC_ALL=C.utf-8 printf "%.${digit}f" "${1}"; } 2>/dev/null { LC_ALL=C.utf-8 printf "%.${digit}f" "$1"; } 2>/dev/null
}
# date is external, printf is much faster
_date(){
printf "%(%c)T\n" -1
} }
setConfigKey() { setConfigKey() {
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3 [[ "$1" =~ ^[-${azAZo9},._]+$ ]] || return 3
[ -z "${BOTCONFIG}" ] && return 1 [ -z "${BOTCONFIG}" ] && return 1
printf '["%s"]\t"%s"\n' "${1//,/\",\"}" "${2//\"/\\\"}" >>"${BOTCONFIG}.jssh" printf '["%s"]\t"%s"\n' "${1//,/\",\"}" "${2//\"/\\\"}" >>"${BOTCONFIG}.jssh"
} }
getConfigKey() { getConfigKey() {
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3 [[ "$1" =~ ^[-${azAZo9},._]+$ ]] || return 3
[ -r "${BOTCONFIG}.jssh" ] && sed -n 's/\["'"$1"'"\]\t*"\(.*\)"/\1/p' <"${BOTCONFIG}.jssh" | tail -n 1 [ -r "${BOTCONFIG}.jssh" ] && sed -n 's/\["'"$1"'"\]\t*"\(.*\)"/\1/p' "${BOTCONFIG}.jssh" | tail -n 1
} }
# check if $1 seems a valid token # check if $1 seems a valid token
# return true if token seems to be valid # return true if token seems to be valid
check_token(){ check_token(){
[[ "${1}" =~ ^[0-9]{8,10}:[a-zA-Z0-9_-]{35}$ ]] && return 0 [[ "$1" =~ ^[${o9o9o9}]{8,10}:[${azAZo9}_-]{35}$ ]] && return 0
return 1 return 1
} }
# log $1 with date # log $1 with date
log_error(){ printf "%s: %s\n" "$(date)" "$*" >>"${ERRORLOG}"; } log_error(){ printf "%(%c)T: %s\n" -1 "$*" >>"${ERRORLOG}"; }
log_debug(){ printf "%s: %s\n" "$(date)" "$*" >>"${DEBUGLOG}"; } log_debug(){ printf "%(%c)T: %s\n" -1 "$*" >>"${DEBUGLOG}"; }
log_update(){ printf "%s: %s\n" "$(date)" "$*" >>"${UPDATELOG}"; } log_update(){ printf "%(%c)T: %s\n" -1 "$*" >>"${UPDATELOG}"; }
# log $1 with date, special first \n # log $1 with date, special first \n
log_message(){ printf "\n%s: %s\n" "$(date)" "${1/\\n/$'\n'}" >>"${MESSAGELOG}"; } log_message(){ printf "\n%(%c)T: %s\n" -1 "${1/\\n/$'\n'}" >>"${MESSAGELOG}"; }
# curl is preferred, try detect curl even not in PATH
# sets BASHBOT_CURL to point to curl
DETECTED_CURL="curl"
detect_curl() {
local file warn="Warning: Curl not detected, try fallback to wget! pls install curl or adjust BASHBOT_CURL/BASHBOT_WGET environment variables."
# custom curl command
[ -n "${BASHBOT_CURL}" ] && return 0
# use wget
[ -n "${BASHBOT_WGET}" ] && DETECTED_CURL="wget" && return 1
# default use curl in PATH
BASHBOT_CURL="curl"
_exists curl && return 0
# search in usual locations
for file in /usr/bin /bin /usr/local/bin; do
[ -x "${file}/curl" ] && BASHBOT_CURL="${file}/curl" && return 0
done
# curl not in PATH and not in usual locations
DETECTED_CURL="wget"
log_update "${warn}"; [ -n "${BASHBOTDEBUG}" ] && log_debug "${warn}"
return 1
}
# additional tests if we run in debug mode # additional tests if we run in debug mode
export BASHBOTDEBUG export BASHBOTDEBUG
@ -113,16 +146,16 @@ export BASHBOTDEBUG
# shellcheck disable=SC2094 # shellcheck disable=SC2094
debug_checks(){ { debug_checks(){ {
[ -z "${BASHBOTDEBUG}" ] && return [ -z "${BASHBOTDEBUG}" ] && return
local DATE WHERE MYTOKEN; DATE="$(date)"; WHERE="${1}"; shift local token where="$1"; shift
printf "%s: debug_checks: %s: bashbot.sh %s\n" "${DATE}" "${WHERE}" "${@##*/}" printf "%(%c)T: debug_checks: %s: bashbot.sh %s\n" -1 "${where}" "${1##*/}"
# shellcheck disable=SC2094 # shellcheck disable=SC2094
[ -z "${DEBUGLOG}" ] && printf "%s: %s\n" "${DATE}" "DEBUGLOG not set! ==========" [ -z "${DEBUGLOG}" ] && printf "%(%c)T: %s\n" -1 "DEBUGLOG not set! =========="
MYTOKEN="$(getConfigKey "bottoken")" token="$(getConfigKey "bottoken")"
[ -z "${MYTOKEN}" ] && printf "%s: %s\n" "${DATE}" "Bot token is missing! ==========" [ -z "${token}" ] && printf "%(%c)T: %s\n" -1 "Bot token is missing! =========="
check_token "${MYTOKEN}" || printf "%s: %s\n" "${DATE}" "Invalid bot token! ==========" check_token "${token}" || printf "%(%c)T: %s\n%s\n" -1 "Invalid bot token! ==========" "${token}"
[ -z "$(getConfigKey "botadmin")" ] && printf "%s: %s\n" "${DATE}" "Bot admin is missing! ==========" [ -z "$(getConfigKey "botadmin")" ] && printf "%(%c)T: %s\n" -1 "Bot admin is missing! =========="
# call user defined debug_checks if exists # call user defined debug_checks if exists
_exec_if_function my_debug_checks "${DATE}" "${WHERE}" "$*" _exec_if_function my_debug_checks "$(_date)" "${where}" "$*"
} >>"${DEBUGLOG}" } >>"${DEBUGLOG}"
} }
@ -142,35 +175,37 @@ MODULEDIR="${SCRIPTDIR}/modules"
# adjust locations based on source and real name # adjust locations based on source and real name
[[ "${SCRIPT}" != "${REALME}" || "$1" == "source" ]] && SOURCE="yes" [[ "${SCRIPT}" != "${REALME}" || "$1" == "source" ]] && SOURCE="yes"
if [ -n "$BASHBOT_HOME" ]; then if [ -n "${BASHBOT_HOME}" ]; then
SCRIPTDIR="$BASHBOT_HOME" SCRIPTDIR="${BASHBOT_HOME}"
else else
BASHBOT_HOME="${SCRIPTDIR}" BASHBOT_HOME="${SCRIPTDIR}"
fi fi
[ -z "${BASHBOT_ETC}" ] && BASHBOT_ETC="$BASHBOT_HOME" [ -z "${BASHBOT_ETC}" ] && BASHBOT_ETC="${BASHBOT_HOME}"
[ -z "${BASHBOT_VAR}" ] && BASHBOT_VAR="$BASHBOT_HOME" [ -z "${BASHBOT_VAR}" ] && BASHBOT_VAR="${BASHBOT_HOME}"
ADDONDIR="${BASHBOT_ETC:-.}/addons" ADDONDIR="${BASHBOT_ETC:-.}/addons"
RUNUSER="${USER}" # USER is overwritten by bashbot array :-(, save original RUNUSER="${USER}" # USER is overwritten by bashbot array :-(, save original
# provide help # provide help
case "$1" in case "$1" in
""|"-h"*) [ -z "${SOURCE}" ] && printf "${ORANGE}Available commands: ${GREY}${BOTCOMMANDS}${NN}" && exit "") [ -z "${SOURCE}" ] && printf "${ORANGE}Available commands: ${GREY}${BOTCOMMANDS}${NN}" && exit
;; ;;
"--h"*) sed -nE -e '/(NOT EDIT)|(shellcheck)/d' -e '3,/###/p' <"$0" "-h"*) LOGO="${BASHBOT_HOME:-.}/doc/bashbot.ascii"
{ [ -r "${LOGO}" ] && cat "${LOGO}"
sed -nE -e '/(NOT EDIT)|(shellcheck)/d' -e '3,/###/p' "$0"; } | more
exit;; exit;;
"help") HELP="${BASHBOT_HOME:-.}/README" "help") HELP="${BASHBOT_HOME:-.}/README"
if [ -n "${INTERACTIVE}" ];then if [ -n "${INTERACTIVE}" ];then
_exists w3m && w3m "$HELP.html" && exit _exists w3m && w3m "${HELP}.html" && exit
_exists lynx && lynx "$HELP.html" && exit _exists lynx && lynx "${HELP}.html" && exit
_exists less && less "$HELP.txt" && exit _exists less && less "${HELP}.txt" && exit
fi fi
cat "$HELP.txt" cat "${HELP}.txt"
exit;; exit;;
esac esac
# OK, ENVIRONMENT is set up, let's do some additional tests # OK, ENVIRONMENT is set up, let's do some additional tests
if [[ -z "${SOURCE}" && -z "$BASHBOT_HOME" ]] && ! cd "${RUNDIR}" ; then if [[ -z "${SOURCE}" && -z "${BASHBOT_HOME}" ]] && ! cd "${RUNDIR}" ; then
printf "${RED}ERROR: Can't change to ${RUNDIR} ...${NN}" printf "${RED}ERROR: Can't change to ${RUNDIR} ...${NN}"
exit 1 exit 1
fi fi
@ -253,7 +288,6 @@ ERRORLOG="${LOGDIR}/ERROR.log"
UPDATELOG="${LOGDIR}/BASHBOT.log" UPDATELOG="${LOGDIR}/BASHBOT.log"
MESSAGELOG="${LOGDIR}/MESSAGE.log" MESSAGELOG="${LOGDIR}/MESSAGE.log"
debug_checks "start SOURCE=${SOURCE:-no}" "$@"
# read BOTTOKEN from bot database if not set # read BOTTOKEN from bot database if not set
if [ -z "${BOTTOKEN}" ]; then if [ -z "${BOTTOKEN}" ]; then
BOTTOKEN="$(getConfigKey "bottoken")" BOTTOKEN="$(getConfigKey "bottoken")"
@ -278,11 +312,11 @@ if ! check_token "${BOTTOKEN}"; then
"<your_bot_id>${RED}:${NC}<35_alphanumeric_characters-hash> ${RED}e.g. =>${NC} 123456789${RED}:${NC}Aa-Zz_0Aa-Zz_1Aa-Zz_2Aa-Zz_3Aa-Zz_4\n\n"\ "<your_bot_id>${RED}:${NC}<35_alphanumeric_characters-hash> ${RED}e.g. =>${NC} 123456789${RED}:${NC}Aa-Zz_0Aa-Zz_1Aa-Zz_2Aa-Zz_3Aa-Zz_4\n\n"\
"${GREY}Your bot token: '${NC}${BOTTOKEN//:/${RED}:${NC}}'\n" "${GREY}Your bot token: '${NC}${BOTTOKEN//:/${RED}:${NC}}'\n"
if [[ ! "${BOTTOKEN}" =~ ^[0-9]{8,10}: ]]; then if [[ ! "${BOTTOKEN}" =~ ^[${o9o9o9}]{8,10}: ]]; then
printf "${GREY}\tHint: Bot id not a number or wrong len: ${NC}$(($(wc -c <<<"${BOTTOKEN%:*}")-1)) ${GREY}but should be${NC} 8-10\n" printf "${GREY}\tHint: Bot id not a number or wrong len: ${NC}$(($(wc -c <<<"${BOTTOKEN%:*}")-1)) ${GREY}but should be${NC} 8-10\n"
[ -n "$(getConfigKey "botid")" ] && printf "\t${GREEN}Did you mean: \"${NC}$(getConfigKey "botid")${GREEN}\" ?${NN}" [ -n "$(getConfigKey "botid")" ] && printf "\t${GREEN}Did you mean: \"${NC}$(getConfigKey "botid")${GREEN}\" ?${NN}"
fi fi
[[ ! "${BOTTOKEN}" =~ :[a-zA-Z0-9_-]{35}$ ]] &&\ [[ ! "${BOTTOKEN}" =~ :[${azAZo9}_-]{35}$ ]] &&\
printf "${GREY}\tHint: Hash contains invalid character or has not len${NC} 35 ${GREY}, hash len is ${NC}$(($(wc -c <<<"${BOTTOKEN#*:}")-1))\n" printf "${GREY}\tHint: Hash contains invalid character or has not len${NC} 35 ${GREY}, hash len is ${NC}$(($(wc -c <<<"${BOTTOKEN#*:}")-1))\n"
printf "\n" printf "\n"
fi fi
@ -293,16 +327,13 @@ fi
BASHBOT_RETRY="" # retry by default BASHBOT_RETRY="" # retry by default
URL="${BASHBOT_URL:-https://api.telegram.org/bot}${BOTTOKEN}" URL="${BASHBOT_URL:-https://api.telegram.org/bot}${BOTTOKEN}"
ME_URL=$URL'/getMe' ME_URL=${URL}'/getMe'
UPD_URL=$URL'/getUpdates?offset='
GETFILE_URL=$URL'/getFile'
################# #################
# BASHBOT COMMON functions # BASHBOT COMMON functions
declare -rx SCRIPT SCRIPTDIR MODULEDIR RUNDIR ADDONDIR BOTACL DATADIR COUNTFILE declare -rx SCRIPT SCRIPTDIR MODULEDIR RUNDIR ADDONDIR BOTACL DATADIR COUNTFILE
declare -rx BOTTOKEN URL ME_URL UPD_URL GETFILE_URL declare -rx BOTTOKEN URL ME_URL
declare -ax CMD declare -ax CMD
declare -Ax UPD BOTSENT USER MESSAGE URLS CONTACT LOCATION CHAT FORWARD REPLYTO VENUE iQUERY declare -Ax UPD BOTSENT USER MESSAGE URLS CONTACT LOCATION CHAT FORWARD REPLYTO VENUE iQUERY
@ -319,6 +350,7 @@ if [ -r "${COMMANDS}" ]; then
else else
[ -z "${SOURCE}" ] && printf "${RED}Warning: ${COMMANDS} does not exist or is not readable!.${NN}" [ -z "${SOURCE}" ] && printf "${RED}Warning: ${COMMANDS} does not exist or is not readable!.${NN}"
fi fi
debug_checks "start SOURCE=${SOURCE:-no}" "$@"
############### ###############
# load modules # load modules
@ -343,8 +375,8 @@ fi
# outputs final filename # outputs final filename
download() { download() {
local empty="no.file" file="${2:-${empty}}" local empty="no.file" file="${2:-${empty}}"
if [[ "$file" = *"/"* ]] || [[ "$file" = "."* ]]; then file="${empty}"; fi if [[ "${file}" = *"/"* ]] || [[ "${file}" = "."* ]]; then file="${empty}"; fi
while [ -f "${DATADIR:-.}/${file}" ] ; do file="$RAMDOM-${file}"; done while [ -f "${DATADIR:-.}/${file}" ] ; do file="${RANDOM}-${file}"; done
getJson "$1" >"${DATADIR:-.}/${file}" || return getJson "$1" >"${DATADIR:-.}/${file}" || return
printf '%s\n' "${DATADIR:-.}/${file}" printf '%s\n' "${DATADIR:-.}/${file}"
} }
@ -373,69 +405,38 @@ killallproc() {
# shellcheck disable=SC2046 # shellcheck disable=SC2046
[ -n "${procid}" ] && kill $(proclist -9 "$1") [ -n "${procid}" ] && kill $(proclist -9 "$1")
fi fi
debug_checks "end killallproc" "${1}" debug_checks "end killallproc" "$1"
} }
# $ chat $2 msg_id $3 nolog # $ chat $2 msg_id $3 nolog
declare -xr DELETE_URL=$URL'/deleteMessage' declare -xr DELETE_URL=${URL}'/deleteMessage'
delete_message() { delete_message() {
[ -z "$3" ] && log_update "Delete Message CHAT=${1} MSG_ID=${2}" [ -z "$3" ] && log_update "Delete Message CHAT=$1 MSG_ID=$2"
sendJson "${1}" '"message_id": '"${2}"'' "${DELETE_URL}" sendJson "$1" '"message_id": '"$2"'' "${DELETE_URL}"
} }
get_file() { get_file() {
[ -z "$1" ] && return [ -z "$1" ] && return
sendJson "" '"file_id": "'"${1}"'"' "${GETFILE_URL}" sendJson "" '"file_id": "'"$1"'"' "${URL}/getFile"
printf '%s\n' "${URL}"/"$(JsonGetString <<< "${res}" '"result","file_path"')" printf '%s\n' "${URL}"/"$(JsonGetString <<< "${res}" '"result","file_path"')"
} }
# curl is preferred, try detect curl even not in PATH
# return TRUE if curl is found or custom curl detected
# return FALSE if no curl is found or wget is forced by BASHBOT_WGET
# sets BASHBOT_CURL to point to curl
DETECTED_CURL="curl"
function detect_curl() {
# custom curl command
[ -n "${BASHBOT_CURL}" ] && return 0
# use wget
if [ -n "${BASHBOT_WGET}" ]; then
DETECTED_CURL="wget"
return 1
fi
# default use curl in PATH
BASHBOT_CURL="curl"
_exists curl && return 0
# search in usual locations
local file
for file in /usr/bin /bin /usr/local/bin; do
if [ -x "${file}/curl" ]; then
BASHBOT_CURL="${file}/curl"
return 0
fi
done
# curl not in PATH and not in usual locations
DETECTED_CURL="wget"
local warn="Warning: Curl not detected, try fallback to wget! pls install curl or adjust BASHBOT_CURL/BASHBOT_WGET environment variables."
log_update "${warn}"; [ -n "${BASHBOTDEBUG}" ] && log_debug "${warn}"
return 1
}
# iconv used to filter out broken utf characters, if not installed fake it # iconv used to filter out broken utf characters, if not installed fake it
if ! _exists iconv; then if ! _exists iconv; then
log_update "Warning: iconv not installed, pls imstall iconv!" log_update "Warning: iconv not installed, pls imstall iconv!"
function iconv() { cat; } function iconv() { cat; }
fi fi
TIMEOUT="${BASHBOT_TIMEOUT}" TIMEOUT="${BASHBOT_TIMEOUT:-20}"
[[ "$TIMEOUT" =~ ^[0-9]+$ ]] || TIMEOUT="20" [[ "${TIMEOUT}" =~ ^[${o9o9o9}]+$ ]] || TIMEOUT="20"
# usage: sendJson "chat" "JSON" "URL" # usage: sendJson "chat" "JSON" "URL"
sendJson(){ sendJson(){
local json chat="" local json chat=""
if [ -n "${1}" ]; then if [ -n "$1" ]; then
chat='"chat_id":'"${1}"',' chat='"chat_id":'"$1"','
[[ "${1}" == *[!0-9-]* ]] && chat='"chat_id":"'"${1}"' NAN",' # chat id not a number! [[ "$1" == *[!${o9o9o9}-]* ]] && chat='"chat_id":"'"$1"' NAN",' # chat id not a number!
fi fi
# compose final json # compose final json
json='{'"${chat} $(iconv -f utf-8 -t utf-8 -c <<<"$2")"'}' json='{'"${chat} $(iconv -f utf-8 -t utf-8 -c <<<"$2")"'}'
@ -451,7 +452,7 @@ sendJson(){
fi fi
# OK here we go ... # OK here we go ...
# route to curl/wget specific function # route to curl/wget specific function
res="$(sendJson_do "${json}" "${3}")" res="$(sendJson_do "${json}" "$3")"
# check telegram response # check telegram response
sendJsonResult "${res}" "sendJson (${DETECTED_CURL})" "$@" sendJsonResult "${res}" "sendJson (${DETECTED_CURL})" "$@"
[ -n "${BASHBOT_EVENT_SEND[*]}" ] && event_send "send" "${@}" & [ -n "${BASHBOT_EVENT_SEND[*]}" ] && event_send "send" "${@}" &
@ -463,8 +464,8 @@ sendJson(){
if detect_curl ; then if detect_curl ; then
# here we have curl ---- # here we have curl ----
[ -z "${BASHBOT_CURL}" ] && BASHBOT_CURL="curl" [ -z "${BASHBOT_CURL}" ] && BASHBOT_CURL="curl"
# $1 URL, $2 hack: log getJson if not ""
getJson(){ getJson(){
[[ -n "${BASHBOTDEBUG}" && -n "${3}" ]] && log_debug "getJson (curl) URL=${1##*/}"
# shellcheck disable=SC2086 # shellcheck disable=SC2086
"${BASHBOT_CURL}" -sL -k ${BASHBOT_CURL_ARGS} -m "${TIMEOUT}" "$1" "${BASHBOT_CURL}" -sL -k ${BASHBOT_CURL_ARGS} -m "${TIMEOUT}" "$1"
} }
@ -473,19 +474,19 @@ if detect_curl ; then
sendJson_do(){ sendJson_do(){
# shellcheck disable=SC2086 # shellcheck disable=SC2086
"${BASHBOT_CURL}" -s -k ${BASHBOT_CURL_ARGS} -m "${TIMEOUT}"\ "${BASHBOT_CURL}" -s -k ${BASHBOT_CURL_ARGS} -m "${TIMEOUT}"\
-d "${1}" -X POST "${2}" -H "Content-Type: application/json" | "${JSONSHFILE}" -b -n 2>/dev/null -d "$1" -X POST "$2" -H "Content-Type: application/json" | "${JSONSHFILE}" -b -n 2>/dev/null
} }
#$1 Chat, $2 what, $3 file, $4 URL, $5 caption #$1 Chat, $2 what, $3 file, $4 URL, $5 caption
sendUpload() { sendUpload() {
[ "$#" -lt 4 ] && return [ "$#" -lt 4 ] && return
if [ -n "$5" ]; then if [ -n "$5" ]; then
[ -n "${BASHBOTDEBUG}" ] &&\ [ -n "${BASHBOTDEBUG}" ] &&\
log_update "sendUpload CHAT=${1} WHAT=${2} FILE=${3} CAPT=${5}" log_update "sendUpload CHAT=$1 WHAT=$2 FILE=$3 CAPT=$5"
# shellcheck disable=SC2086 # shellcheck disable=SC2086
res="$("${BASHBOT_CURL}" -s -k ${BASHBOT_CURL_ARGS} "$4" -F "chat_id=$1"\ res="$("${BASHBOT_CURL}" -s -k ${BASHBOT_CURL_ARGS} "$4" -F "chat_id=$1"\
-F "$2=@$3;${3##*/}" -F "caption=$5" | "${JSONSHFILE}" -b -n 2>/dev/null )" -F "$2=@$3;${3##*/}" -F "caption=$5" | "${JSONSHFILE}" -b -n 2>/dev/null )"
else else
# shellcheck disable=SC2086 # shellcheck disable=SC2086
res="$("${BASHBOT_CURL}" -s -k ${BASHBOT_CURL_ARGS} "$4" -F "chat_id=$1"\ res="$("${BASHBOT_CURL}" -s -k ${BASHBOT_CURL_ARGS} "$4" -F "chat_id=$1"\
-F "$2=@$3;${3##*/}" | "${JSONSHFILE}" -b -n 2>/dev/null )" -F "$2=@$3;${3##*/}" | "${JSONSHFILE}" -b -n 2>/dev/null )"
fi fi
@ -496,7 +497,6 @@ else
# NO curl, try wget # NO curl, try wget
if _exists wget; then if _exists wget; then
getJson(){ getJson(){
[[ -n "${BASHBOTDEBUG}" && -z "${3}" ]] && log_debug "getJson (wget) URL=${1##*/}"
# shellcheck disable=SC2086 # shellcheck disable=SC2086
wget --no-check-certificate -t 2 -T "${TIMEOUT}" ${BASHBOT_WGET_ARGS} -qO - "$1" wget --no-check-certificate -t 2 -T "${TIMEOUT}" ${BASHBOT_WGET_ARGS} -qO - "$1"
} }
@ -504,8 +504,8 @@ else
# usage: "JSON" "URL" # usage: "JSON" "URL"
sendJson_do(){ sendJson_do(){
# shellcheck disable=SC2086 # shellcheck disable=SC2086
wget --no-check-certificate -t 2 -T "${TIMEOUT}" ${BASHBOT_WGET_ARGS} -qO - --post-data="${1}" \ wget --no-check-certificate -t 2 -T "${TIMEOUT}" ${BASHBOT_WGET_ARGS} -qO - --post-data="$1" \
--header='Content-Type:application/json' "${2}" | "${JSONSHFILE}" -b -n 2>/dev/null --header='Content-Type:application/json' "$2" | "${JSONSHFILE}" -b -n 2>/dev/null
} }
sendUpload() { sendUpload() {
log_error "Sorry, wget does not support file upload" log_error "Sorry, wget does not support file upload"
@ -526,9 +526,9 @@ fi
# retry sendJson # retry sendJson
# $1 function $2 sleep $3 ... $n arguments # $1 function $2 sleep $3 ... $n arguments
sendJsonRetry(){ sendJsonRetry(){
local retry="${1}"; shift local retry="$1"; shift
[[ "${1}" =~ ^\ *[0-9.]+\ *$ ]] && sleep "${1}"; shift [[ "$1" =~ ^\ *[${o9o9o9}.]+\ *$ ]] && sleep "$1"; shift
printf "%s: RETRY %s %s %s\n" "$(date)" "${retry}" "${1}" "${2:0:60}" printf "%(%c)T: RETRY %s %s %s\n" -1 "${retry}" "$1" "${2:0:60}"
case "${retry}" in case "${retry}" in
'sendJson'*) 'sendJson'*)
sendJson "$@" sendJson "$@"
@ -544,7 +544,7 @@ sendJsonRetry(){
return return
;; ;;
esac esac
[ "${BOTSENT[OK]}" = "true" ] && log_error "Retry OK:${retry} ${1} ${2:0:60}" [ "${BOTSENT[OK]}" = "true" ] && log_error "Retry OK:${retry} $1 ${2:0:60}"
} >>"${ERRORLOG}" } >>"${ERRORLOG}"
# process sendJson result # process sendJson result
@ -553,19 +553,21 @@ sendJsonRetry(){
sendJsonResult(){ sendJsonResult(){
local offset=0 local offset=0
BOTSENT=( ) BOTSENT=( )
Json2Array 'UPD' <<<"$1"
[ -n "${BASHBOTDEBUG}" ] && log_message "New Result ==========\n$1" [ -n "${BASHBOTDEBUG}" ] && log_message "New Result ==========\n$1"
BOTSENT[OK]="$(JsonGetLine '"ok"' <<< "${1}")" BOTSENT[OK]="${UPD["ok"]}"
if [ "${BOTSENT[OK]}" = "true" ]; then if [ "${BOTSENT[OK]}" = "true" ]; then
BOTSENT[ID]="$(JsonGetValue '"result","message_id"' <<< "${1}")" BOTSENT[ID]="${UPD["result","message_id"]}"
BOTSENT[CHAT]="${UPD["result","chat","id"]}"
[ -n "${UPD["result"]}" ] && BOTSENT[RESULT]="${UPD["result"]}"
return return
# hot path everything OK! # hot path everything OK!
else else
# oops something went wrong! # oops something went wrong!
if [ "${1}" != "" ]; then if [ -n "$1" ]; then
BOTSENT[ERROR]="$(JsonGetValue '"error_code"' <<< "${1}")" BOTSENT[ERROR]="${UPD["error_code"]}"
BOTSENT[DESCRIPTION]="$(JsonGetString '"description"' <<< "${1}")" BOTSENT[DESCRIPTION]="${UPD["description"]}"
grep -qs -F '"parameters","retry_after"' <<< "${1}" &&\ [ -n "${UPD["parameters","retry_after"]}" ] && BOTSENT[RETRY]="${UPD["parameters","retry_after"]}"
BOTSENT[RETRY]="$(JsonGetValue '"parameters","retry_after"' <<< "${1}")"
else else
BOTSENT[OK]="false" BOTSENT[OK]="false"
BOTSENT[ERROR]="999" BOTSENT[ERROR]="999"
@ -574,8 +576,8 @@ sendJsonResult(){
# log error # log error
[[ "${BOTSENT[ERROR]}" = "400" && "${BOTSENT[DESCRIPTION]}" == *"starting at byte offset"* ]] &&\ [[ "${BOTSENT[ERROR]}" = "400" && "${BOTSENT[DESCRIPTION]}" == *"starting at byte offset"* ]] &&\
offset="${BOTSENT[DESCRIPTION]%* }" offset="${BOTSENT[DESCRIPTION]%* }"
printf "%s: RESULT=%s FUNC=%s CHAT[ID]=%s ERROR=%s DESC=%s ACTION=%s\n" "$(date)"\ printf "%(%c)T: RESULT=%s FUNC=%s CHAT[ID]=%s ERROR=%s DESC=%s ACTION=%s\n" -1\
"${BOTSENT[OK]}" "${2}" "${3}" "${BOTSENT[ERROR]}" "${BOTSENT[DESCRIPTION]}" "${4:${offset}:100}" "${BOTSENT[OK]}" "$2" "$3" "${BOTSENT[ERROR]}" "${BOTSENT[DESCRIPTION]}" "${4:${offset}:100}"
# warm path, do not retry on error, also if we use wegt # warm path, do not retry on error, also if we use wegt
[ -n "${BASHBOT_RETRY}${BASHBOT_WGET}" ] && return [ -n "${BASHBOT_RETRY}${BASHBOT_WGET}" ] && return
@ -583,8 +585,8 @@ sendJsonResult(){
# throttled, telegram say we send too many messages # throttled, telegram say we send too many messages
if [ -n "${BOTSENT[RETRY]}" ]; then if [ -n "${BOTSENT[RETRY]}" ]; then
BASHBOT_RETRY="$(( ++BOTSENT[RETRY] ))" BASHBOT_RETRY="$(( ++BOTSENT[RETRY] ))"
printf "Retry %s in %s seconds ...\n" "${2}" "${BASHBOT_RETRY}" printf "Retry %s in %s seconds ...\n" "$2" "${BASHBOT_RETRY}"
sendJsonRetry "${2}" "${BASHBOT_RETRY}" "${@:3}" sendJsonRetry "$2" "${BASHBOT_RETRY}" "${@:3}"
unset BASHBOT_RETRY unset BASHBOT_RETRY
return return
fi fi
@ -592,12 +594,12 @@ sendJsonResult(){
if [ "${BOTSENT[ERROR]}" == "999" ];then if [ "${BOTSENT[ERROR]}" == "999" ];then
# check if default curl and args are OK # check if default curl and args are OK
if ! curl -sL -k -m 2 "${URL}" >/dev/null 2>&1 ; then if ! curl -sL -k -m 2 "${URL}" >/dev/null 2>&1 ; then
printf "%s: BASHBOT IP Address seems blocked!\n" "$(date)" printf "%(%c)T: BASHBOT IP Address seems blocked!\n" -1
# user provided function to recover or notify block # user provided function to recover or notify block
if _exec_if_function bashbotBlockRecover; then if _exec_if_function bashbotBlockRecover; then
BASHBOT_RETRY="2" BASHBOT_RETRY="2"
printf "bashbotBlockRecover returned true, retry %s ...\n" "${2}" printf "bashbotBlockRecover returned true, retry %s ...\n" "$2"
sendJsonRetry "${2}" "${BASHBOT_RETRY}" "${@:3}" sendJsonRetry "$2" "${BASHBOT_RETRY}" "${@:3}"
unset BASHBOT_RETRY unset BASHBOT_RETRY
fi fi
return return
@ -605,9 +607,9 @@ sendJsonResult(){
# are not blocked, default curl and args are working # are not blocked, default curl and args are working
if [ -n "${BASHBOT_CURL_ARGS}" ] || [ "${BASHBOT_CURL}" != "curl" ]; then if [ -n "${BASHBOT_CURL_ARGS}" ] || [ "${BASHBOT_CURL}" != "curl" ]; then
printf "Problem with \"%s %s\"? retry %s with default config ...\n"\ printf "Problem with \"%s %s\"? retry %s with default config ...\n"\
"${BASHBOT_CURL}" "${BASHBOT_CURL_ARGS}" "${2}" "${BASHBOT_CURL}" "${BASHBOT_CURL_ARGS}" "$2"
BASHBOT_RETRY="2"; BASHBOT_CURL="curl"; BASHBOT_CURL_ARGS="" BASHBOT_RETRY="2"; BASHBOT_CURL="curl"; BASHBOT_CURL_ARGS=""
sendJsonRetry "${2}" "${BASHBOT_RETRY}" "${@:3}" sendJsonRetry "$2" "${BASHBOT_RETRY}" "${@:3}"
unset BASHBOT_RETRY unset BASHBOT_RETRY
fi fi
fi fi
@ -636,7 +638,7 @@ title2Json(){
# get bot name and id from telegram # get bot name and id from telegram
getBotName() { getBotName() {
declare -A BOTARRAY declare -A BOTARRAY
Json2Array 'BOTARRAY' <<<"$(getJson "$ME_URL" | "${JSONSHFILE}" -b -n 2>/dev/null)" Json2Array 'BOTARRAY' <<<"$(getJson "${ME_URL}" | "${JSONSHFILE}" -b -n 2>/dev/null)"
[ -z "${BOTARRAY["result","username"]}" ] && return 1 [ -z "${BOTARRAY["result","username"]}" ] && return 1
# save botname and id # save botname and id
setConfigKey "botname" "${BOTARRAY["result","username"]}" setConfigKey "botname" "${BOTARRAY["result","username"]}"
@ -647,15 +649,14 @@ getBotName() {
# pure bash implementation, done by KayM (@gnadelwartz) # pure bash implementation, done by KayM (@gnadelwartz)
# see https://stackoverflow.com/a/55666449/9381171 # see https://stackoverflow.com/a/55666449/9381171
JsonDecode() { JsonDecode() {
local out="$1" remain="" U="" local remain U out="$1"
local regexp='(.*)\\u[dD]([0-9a-fA-F]{3})\\u[dD]([0-9a-fA-F]{3})(.*)' local regexp='(.*)\\u[dD]([0-9a-fA-F]{3})\\u[dD]([0-9a-fA-F]{3})(.*)'
while [[ "${out}" =~ $regexp ]] ; do while [[ "${out}" =~ ${regexp} ]] ; do
U=$(( ( (0xd${BASH_REMATCH[2]} & 0x3ff) <<10 ) | ( 0xd${BASH_REMATCH[3]} & 0x3ff ) + 0x10000 )) U=$(( ( (0xd${BASH_REMATCH[2]} & 0x3ff) <<10 ) | ( 0xd${BASH_REMATCH[3]} & 0x3ff ) + 0x10000 ))
remain="$(printf '\\U%8.8x' "${U}")${BASH_REMATCH[4]}${remain}" remain="$(printf '\\U%8.8x' "${U}")${BASH_REMATCH[4]}${remain}"
out="${BASH_REMATCH[1]}" out="${BASH_REMATCH[1]}"
done done
#printf "%b\n" "${out}${remain}" # seems to work ... dealyed to next dev printf "%b\n" "${out}${remain}"
echo -e "${out}${remain}"
} }
JsonGetString() { JsonGetString() {
@ -675,7 +676,7 @@ process_updates() {
max="$(grep -F ',"update_id"]' <<< "${UPDATE}" | tail -1 | cut -d , -f 2 )" max="$(grep -F ',"update_id"]' <<< "${UPDATE}" | tail -1 | cut -d , -f 2 )"
Json2Array 'UPD' <<<"${UPDATE}" Json2Array 'UPD' <<<"${UPDATE}"
for ((num=0; num<=max; num++)); do for ((num=0; num<=max; num++)); do
process_client "$num" "${debug}" process_client "${num}" "${debug}"
done done
} }
@ -698,12 +699,12 @@ process_client() {
MESSAGE[0]="/_edited_message " MESSAGE[0]="/_edited_message "
fi fi
process_message "${num}" "${debug}" process_message "${num}" "${debug}"
printf "%s: update received FROM=%s CHAT=%s CMD=%s\n" "$(date)" "${USER[USERNAME]:0:20} (${USER[ID]})"\ printf "%(%c)T: update received FROM=%s CHAT=%s CMD=%s\n" -1 "${USER[USERNAME]:0:20} (${USER[ID]})"\
"${CHAT[USERNAME]:0:20}${CHAT[TITLE]:0:30} (${CHAT[ID]})"\ "${CHAT[USERNAME]:0:20}${CHAT[TITLE]:0:30} (${CHAT[ID]})"\
"${MESSAGE:0:30}${CAPTION:0:30}${URLS[*]:0:30}" >>"${UPDATELOG}" "${MESSAGE:0:30}${CAPTION:0:30}${URLS[*]:0:30}" >>"${UPDATELOG}"
else else
process_inline "${num}" "${debug}" process_inline "${num}" "${debug}"
printf "%s: iQuery received FROM=%s iQUERY=%s\n" "$(date)"\ printf "%(%c)T: iQuery received FROM=%s iQUERY=%s\n" -1\
"${iQUERY[USERNAME]:0:20} (${iQUERY[USER_ID]})" "${iQUERY[0]}" >>"${UPDATELOG}" "${iQUERY[USERNAME]:0:20} (${iQUERY[USER_ID]})" "${iQUERY[0]}" >>"${UPDATELOG}"
fi fi
##### #####
@ -723,7 +724,7 @@ process_client() {
jssh_countKeyDB_async "${CHAT[ID]}" "${COUNTFILE}" jssh_countKeyDB_async "${CHAT[ID]}" "${COUNTFILE}"
} }
declare -Ax BASHBOT_EVENT_INLINE BASHBOT_EVENT_MESSAGE BASHBOT_EVENT_CMD BASHBOT_EVENT_REPLY BASHBOT_EVENT_FORWARD BASHBOT_EVENT_SEND declare -Ax BASHBOT_EVENT_INLINE BASHBOT_EVENT_MESSAGE BASHBOT_EVENT_CMD BASHBOT_EVENT_REPLYTO BASHBOT_EVENT_FORWARD BASHBOT_EVENT_SEND
declare -Ax BASHBOT_EVENT_CONTACT BASHBOT_EVENT_LOCATION BASHBOT_EVENT_FILE BASHBOT_EVENT_TEXT BASHBOT_EVENT_TIMER BASHBOT_BLOCKED declare -Ax BASHBOT_EVENT_CONTACT BASHBOT_EVENT_LOCATION BASHBOT_EVENT_FILE BASHBOT_EVENT_TEXT BASHBOT_EVENT_TIMER BASHBOT_BLOCKED
start_timer(){ start_timer(){
@ -737,7 +738,7 @@ start_timer(){
EVENT_SEND="0" EVENT_SEND="0"
event_send() { event_send() {
# max recursion level 5 to avoid fork bombs # max recursion level 5 to avoid fork bombs
(( EVENT_SEND++ )); [ "$EVENT_SEND" -gt "5" ] && return (( EVENT_SEND++ )); [ "${EVENT_SEND}" -gt "5" ] && return
# shellcheck disable=SC2153 # shellcheck disable=SC2153
for key in "${!BASHBOT_EVENT_SEND[@]}" for key in "${!BASHBOT_EVENT_SEND[@]}"
do do
@ -753,7 +754,7 @@ event_timer() {
for key in "${!BASHBOT_EVENT_TIMER[@]}" for key in "${!BASHBOT_EVENT_TIMER[@]}"
do do
timer="${key##*,}" timer="${key##*,}"
[[ ! "$timer" =~ ^-*[1-9][0-9]*$ ]] && continue [[ ! "${timer}" =~ ^-*[1-9][0-9]*$ ]] && continue
if [ "$(( EVENT_TIMER % timer ))" = "0" ]; then if [ "$(( EVENT_TIMER % timer ))" = "0" ]; then
_exec_if_function "${BASHBOT_EVENT_TIMER[${key}]}" "timer" "${key}" "${debug}" _exec_if_function "${BASHBOT_EVENT_TIMER[${key}]}" "timer" "${key}" "${debug}"
[ "$(( EVENT_TIMER % timer ))" -lt "0" ] && \ [ "$(( EVENT_TIMER % timer ))" -lt "0" ] && \
@ -845,7 +846,7 @@ event_message() {
} }
pre_process_message(){ pre_process_message(){
local num="${1}" local num="$1"
# unset everything to not have old values # unset everything to not have old values
CMD=( ); iQUERY=( ); MESSAGE=(); CHAT=(); USER=(); CONTACT=(); LOCATION=(); unset CAPTION CMD=( ); iQUERY=( ); MESSAGE=(); CHAT=(); USER=(); CONTACT=(); LOCATION=(); unset CAPTION
REPLYTO=( ); FORWARD=( ); URLS=(); VENUE=( ); SERVICE=( ); NEWMEMBER=( ); LEFTMEMBER=( ); PINNED=( ); MIGRATE=( ) REPLYTO=( ); FORWARD=( ); URLS=(); VENUE=( ); SERVICE=( ); NEWMEMBER=( ); LEFTMEMBER=( ); PINNED=( ); MIGRATE=( )
@ -858,7 +859,7 @@ pre_process_message(){
return 0 return 0
} }
process_inline() { process_inline() {
local num="${1}" local num="$1"
iQUERY[0]="$(JsonDecode "${UPD["result",${num},"inline_query","query"]}")" iQUERY[0]="$(JsonDecode "${UPD["result",${num},"inline_query","query"]}")"
iQUERY[USER_ID]="${UPD["result",${num},"inline_query","from","id"]}" iQUERY[USER_ID]="${UPD["result",${num},"inline_query","from","id"]}"
iQUERY[FIRST_NAME]="$(JsonDecode "${UPD["result",${num},"inline_query","from","first_name"]}")" iQUERY[FIRST_NAME]="$(JsonDecode "${UPD["result",${num},"inline_query","from","first_name"]}")"
@ -1006,7 +1007,6 @@ process_message() {
######################### #########################
# main get updates loop, should never terminate # main get updates loop, should never terminate
declare -A BASHBOTBLOCKED declare -A BASHBOTBLOCKED
export BASHBOT_UPDATELOG="${BASHBOT_UPDATELOG-nolog}" # allow to be ""
start_bot() { start_bot() {
local DEBUGMSG OFFSET=0 local DEBUGMSG OFFSET=0
# adaptive sleep defaults # adaptive sleep defaults
@ -1017,9 +1017,9 @@ start_bot() {
DEBUGMSG="Start BASHBOT updates in Mode \"${1:-normal}\" ==========" DEBUGMSG="Start BASHBOT updates in Mode \"${1:-normal}\" =========="
log_update "${DEBUGMSG}" log_update "${DEBUGMSG}"
# redirect to Debug.log # redirect to Debug.log
[[ "${1}" == *"debug" ]] && exec &>>"${DEBUGLOG}" [[ "$1" == *"debug" ]] && exec &>>"${DEBUGLOG}"
log_debug "${DEBUGMSG}"; DEBUGMSG="${1}" log_debug "${DEBUGMSG}"; DEBUGMSG="$1"
[[ "${DEBUGMSG}" == "xdebug"* ]] && set -x && unset BASHBOT_UPDATELOG [[ "${DEBUGMSG}" == "xdebug"* ]] && set -x
# cleaup old pipes and empty logfiles # cleaup old pipes and empty logfiles
find "${DATADIR}" -type p -delete find "${DATADIR}" -type p -delete
find "${DATADIR}" -size 0 -name "*.log" -delete find "${DATADIR}" -size 0 -name "*.log" -delete
@ -1033,7 +1033,7 @@ start_bot() {
# start timer events # start timer events
if [ -n "${BASHBOT_START_TIMER}" ] ; then if [ -n "${BASHBOT_START_TIMER}" ] ; then
# shellcheck disable=SC2064 # shellcheck disable=SC2064
trap "event_timer $DEBUGMSG" ALRM trap "event_timer ${DEBUGMSG}" ALRM
start_timer & start_timer &
# shellcheck disable=SC2064 # shellcheck disable=SC2064
trap "kill -9 $!; exit" EXIT INT HUP TERM QUIT trap "kill -9 $!; exit" EXIT INT HUP TERM QUIT
@ -1042,7 +1042,7 @@ start_bot() {
jssh_deleteKeyDB "CLEAN_COUNTER_DATABASE_ON_STARTUP" "${COUNTFILE}" jssh_deleteKeyDB "CLEAN_COUNTER_DATABASE_ON_STARTUP" "${COUNTFILE}"
[ -f "${COUNTFILE}.jssh.flock" ] && rm -f "${COUNTFILE}.jssh.flock" [ -f "${COUNTFILE}.jssh.flock" ] && rm -f "${COUNTFILE}.jssh.flock"
# store start time and cleanup botconfig on startup # store start time and cleanup botconfig on startup
jssh_updateKeyDB "startup" "$(date)" "${BOTCONFIG}" jssh_updateKeyDB "startup" "$(_date)" "${BOTCONFIG}"
[ -f "${BOTCONFIG}.jssh.flock" ] && rm -f "${BOTCONFIG}.jssh.flock" [ -f "${BOTCONFIG}.jssh.flock" ] && rm -f "${BOTCONFIG}.jssh.flock"
# read blocked users # read blocked users
jssh_readDB_async "BASHBOTBLOCKED" "${BLOCKEDFILE}" jssh_readDB_async "BASHBOTBLOCKED" "${BLOCKEDFILE}"
@ -1054,7 +1054,7 @@ start_bot() {
# adaptive sleep in ms rounded to next 0.1 s # adaptive sleep in ms rounded to next 0.1 s
sleep "$(_round_float "${nextsleep}e-3" "1")" sleep "$(_round_float "${nextsleep}e-3" "1")"
# get next update # get next update
UPDATE="$(getJson "${UPD_URL}${OFFSET}" "${BASHBOT_UPDATELOG}" 2>/dev/null | "${JSONSHFILE}" -b -n 2>/dev/null | iconv -f utf-8 -t utf-8 -c)" UPDATE="$(getJson "${URL}/getUpdates?offset=${OFFSET}" 2>/dev/null | "${JSONSHFILE}" -b -n 2>/dev/null | iconv -f utf-8 -t utf-8 -c)"
# did we get an response? # did we get an response?
if [ -n "${UPDATE}" ]; then if [ -n "${UPDATE}" ]; then
# we got something, do processing # we got something, do processing
@ -1067,7 +1067,7 @@ start_bot() {
OFFSET="$(grep <<< "${UPDATE}" '\["result",[0-9]*,"update_id"\]' | tail -1 | cut -f 2)" OFFSET="$(grep <<< "${UPDATE}" '\["result",[0-9]*,"update_id"\]' | tail -1 | cut -f 2)"
((OFFSET++)) ((OFFSET++))
if [ "$OFFSET" != "1" ]; then if [ "${OFFSET}" != "1" ]; then
nextsleep="100" nextsleep="100"
process_updates "${DEBUGMSG}" process_updates "${DEBUGMSG}"
fi fi
@ -1091,7 +1091,7 @@ start_bot() {
# initialize bot environment, user and permissions # initialize bot environment, user and permissions
bot_init() { bot_init() {
[ -n "${BASHBOT_HOME}" ] && cd "${BASHBOT_HOME}" || exit 1 [ -n "${BASHBOT_HOME}" ] && cd "${BASHBOT_HOME}" || exit 1
local DEBUG="$1" local runuser chown touser botname DEBUG="$1"
# upgrade from old version # upgrade from old version
# currently no action # currently no action
printf "Check for Update actions ...\n" printf "Check for Update actions ...\n"
@ -1103,24 +1103,37 @@ bot_init() {
[ -r "${addons}" ] && source "${addons}" "init" "${DEBUG}" [ -r "${addons}" ] && source "${addons}" "init" "${DEBUG}"
done done
printf "Done.\n" printf "Done.\n"
# setup bashbot # ask for bashbot user
[[ "${UID}" -eq "0" ]] && RUNUSER="nobody" runuser="${RUNUSER}"; [ "${UID}" = "0" ] && runuser="nobody"
printf "Enter User to run bashbot [$RUNUSER]: " printf "Enter User to run bashbot [${runuser}]: "
read -r TOUSER read -r chown
[ -z "$TOUSER" ] && TOUSER="$RUNUSER" [ -z "${chown}" ] && chown="${runuser}"; touser="${chown%:*}"
if ! id "$TOUSER" &>/dev/null; then # check user ...
printf "${RED}User \"$TOUSER\" not found!${NN}" if ! id "${touser}" &>/dev/null; then
printf "${RED}User \"${touser}\" does not exist!${NN}"
exit 3 exit 3
else elif [[ "${UID}" != "0" && "${touser}" != "${runuser}" ]]; then
printf "Adjusting files and permissions for user \"${TOUSER}\" ...\n" # different user but not root ...
[ -w "bashbot.rc" ] && sed -i '/^[# ]*runas=/ s/runas=.*$/runas="'$TOUSER'"/' "bashbot.rc" printf "${ORANGE}You are not root, adjusting permissions may fail. Try \"sudo ./bashbot.sh init\"${NN}Press <CTRL+C> to stop or <Enter> to continue..." 1>&2
chmod 711 . [ -n "${INTERACTIVE}" ] && read -r runuser
chmod -R o-w ./* fi
chmod -R u+w "${COUNTFILE}"* "${BLOCKEDFILE}"* "${DATADIR}" logs "${LOGDIR}/"*.log 2>/dev/null # adjust permissions
chmod -R o-r,o-w "${COUNTFILE}"* "${BLOCKEDFILE}"* "${DATADIR}" "${BOTACL}" 2>/dev/null printf "Adjusting files and permissions for user \"${touser}\" ...\n"
# jsshDB must writeable by owner chmod 711 .
find . -name '*.jssh*' -exec chmod u+w \{\} + chmod -R o-w ./*
chown -R "$TOUSER" . ./* chmod -R u+w "${COUNTFILE}"* "${BLOCKEDFILE}"* "${DATADIR}" logs "${LOGDIR}/"*.log 2>/dev/null
chmod -R o-r,o-w "${COUNTFILE}"* "${BLOCKEDFILE}"* "${DATADIR}" "${BOTACL}" 2>/dev/null
# jsshDB must writeable by owner
find . -name '*.jssh*' -exec chmod u+w \{\} +
chown -Rf "${chown}" . ./*
printf "Done.\n"
# adjust values in bashbot.rc
if [ -w "bashbot.rc" ]; then
printf "Adjust user and botname in bashbot.rc ...\n"
sed -i '/^[# ]*runas=/ s|runas=.*$|runas="'"${touser}"'"|' "bashbot.rc"
sed -i '/^[# ]*bashbot=/ s|bashbot=.*$|bashbot="cd '"${PWD}"'; '"${PWD}"'/'"${0##*/}"'"|' "bashbot.rc"
botname="$(getConfigKey "botname")"
[ -n "${botname}" ] && sed -i '/^[# ]*name=/ s|name=.*$|name="'"${botname}"'"|' "bashbot.rc"
printf "Done.\n" printf "Done.\n"
fi fi
# ask to check bottoken online # ask to check bottoken online
@ -1135,7 +1148,7 @@ bot_init() {
# check if botconf seems valid # check if botconf seems valid
printf "${GREEN}This is your bot config:${NN}" printf "${GREEN}This is your bot config:${NN}"
sed 's/^/\t/' "${BOTCONFIG}.jssh" | grep -vF '["bot_config_key"]' sed 's/^/\t/' "${BOTCONFIG}.jssh" | grep -vF '["bot_config_key"]'
if check_token "$(getConfigKey "bottoken")" && [[ "$(getConfigKey "botadmin")" =~ ^[0-9]+$ ]]; then if check_token "$(getConfigKey "bottoken")" && [[ "$(getConfigKey "botadmin")" =~ ^[${o9o9o9}]+$ ]]; then
printf "Bot config seems to be valid. Should I make a backup copy? (Y/n) Y\b" printf "Bot config seems to be valid. Should I make a backup copy? (Y/n) Y\b"
read -r ANSWER read -r ANSWER
if [[ -z "${ANSWER}" || "${ANSWER}" =~ ^[^Nn] ]]; then if [[ -z "${ANSWER}" || "${ANSWER}" =~ ^[^Nn] ]]; then
@ -1167,7 +1180,7 @@ if [ -z "${SOURCE}" ]; then
############## ##############
# internal options only for use from bashbot and developers # internal options only for use from bashbot and developers
# shellcheck disable=SC2221,SC2222 # shellcheck disable=SC2221,SC2222
case "${1}" in case "$1" in
# update botname when starting only # update botname when starting only
"botname"|"start"*) "botname"|"start"*)
ME="$(getBotName)" ME="$(getBotName)"
@ -1179,7 +1192,7 @@ if [ -z "${SOURCE}" ]; then
else else
printf "${GREY}Info: Can't get Botname from Telegram, try cached one ...${NN}" printf "${GREY}Info: Can't get Botname from Telegram, try cached one ...${NN}"
ME="$(getConfigKey "botname")" ME="$(getConfigKey "botname")"
if [ -z "$ME" ]; then if [ -z "${ME}" ]; then
printf "${RED}ERROR: No cached botname, can't continue! ...${NN}" printf "${RED}ERROR: No cached botname, can't continue! ...${NN}"
exit 1 exit 1
fi fi
@ -1194,7 +1207,7 @@ if [ -z "${SOURCE}" ]; then
ME="$(getConfigKey "botname")" ME="$(getConfigKey "botname")"
# read until terminated # read until terminated
while read -r line ;do while read -r line ;do
[ -n "$line" ] && send_message "$2" "$line" [ -n "${line}" ] && send_message "$2" "${line}"
done done
# cleanup datadir, keep logfile if not empty # cleanup datadir, keep logfile if not empty
rm -f -r "${DATADIR:-.}/$3" rm -f -r "${DATADIR:-.}/$3"
@ -1248,7 +1261,7 @@ if [ -z "${SOURCE}" ]; then
BOTPID="$(proclist "${SESSION}")" BOTPID="$(proclist "${SESSION}")"
# shellcheck disable=SC2086 # shellcheck disable=SC2086
[ -n "${BOTPID}" ] && kill ${BOTPID} [ -n "${BOTPID}" ] && kill ${BOTPID}
nohup "$SCRIPT" "startbot" "$2" "${SESSION}" &>/dev/null & nohup "${SCRIPT}" "startbot" "$2" "${SESSION}" &>/dev/null &
printf "Session Name: %s\n" "${SESSION}" printf "Session Name: %s\n" "${SESSION}"
sleep 1 sleep 1
if [ -n "$(proclist "${SESSION}")" ]; then if [ -n "$(proclist "${SESSION}")" ]; then

View File

@ -13,7 +13,7 @@
# AUTHOR: KayM (gnadelwartz), kay@rrr.de # AUTHOR: KayM (gnadelwartz), kay@rrr.de
# CREATED: 18.12.2020 12:27 # CREATED: 18.12.2020 12:27
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
#=============================================================================== #===============================================================================
############ ############

View File

@ -3,7 +3,7 @@
# #
# FILE: bin/bashbot_stats.sh # FILE: bin/bashbot_stats.sh
# #
# USAGE: bashbot_stats.sh [-h|--help] [debug] USAGE='bashbot_stats.sh [-h|--help] [debug]'
# #
# DESCRIPTION: output bashbot user stats # DESCRIPTION: output bashbot user stats
# #
@ -16,14 +16,14 @@
# AUTHOR: KayM (gnadelwartz), kay@rrr.de # AUTHOR: KayM (gnadelwartz), kay@rrr.de
# CREATED: 23.12.2020 20:34 # CREATED: 23.12.2020 20:34
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
#=============================================================================== #===============================================================================
#### ####
# parse args # parse args
case "$1" in case "$1" in
"-h"*) "-h"*)
echo "usage: send_message [-h|--help] [debug]" printf "usage: %s\n" "${USAGE}"
exit 1 exit 1
;; ;;
'--h'*) '--h'*)

63
bin/delete_message.sh Executable file
View File

@ -0,0 +1,63 @@
#!/bin/bash
#===============================================================================
#
# FILE: bin/delete_message.sh
#
USAGE='delete_message.sh [-h|--help] "CHAT[ID]" "MESSAGE[ID]" [debug]'
#
# DESCRIPTION: delete a message in the given user/group
#
# OPTIONS: CHAT[ID] - ID number of CHAT or BOTADMIN
# MESSAGE[ID] - message to delete
#
# -h - display short help
# --help - this help
#
# Set BASHBOT_HOME to your installation directory
#
# LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/
# AUTHOR: KayM (gnadelwartz), kay@rrr.de
# CREATED: 03.01.2021 15:37
#
#### $$VERSION$$ v1.30-0-g3266427
#===============================================================================
####
# parse args
DELETE="delete_message"
case "$1" in
'')
printf "missing arguments\n"
;&
"-h"*)
printf 'usage: %s\n' "${USAGE}"
exit 1
;;
'--h'*)
sed -n '3,/###/p' <"$0"
exit 1
;;
esac
# set bashbot environment
# shellcheck disable=SC1090
source "${0%/*}/bashbot_env.inc.sh" "${3:-debug}" # $3 debug
####
####
# ready, do stuff here -----
if [ "$1" == "BOTADMIN" ]; then
CHAT="${BOT_ADMIN}"
else
CHAT="$1"
fi
# delete message
"${DELETE}" "${CHAT}" "$2"
[ "${BOTSENT[OK]}" = "true" ] && BOTSENT[ID]="$2"
# output send message result
jssh_printDB "BOTSENT" | sort -r

View File

@ -1,15 +1,18 @@
#!/bin/bash #!/bin/bash
#=============================================================================== #===============================================================================
# shellcheck disable=SC2059
# #
# FILE: bin/broadcast_message.sh # FILE: bin/broadcast_message.sh
# #
# USAGE: broadcast_message.sh [-h|--help] [--doit] [--groups|--both] [format] "message ...." [debug] USAGE='broadcast_message.sh [-h|--help] [--doit] [--groups|--both|--db=file] [format] "message ...." [debug]'
# #
# DESCRIPTION: send a message to all users the bot have seen (listet in count.jssh) # DESCRIPTION: send a message to all users listed in a jsonDB (default count db)
# #
# OPTIONS: --doit - broadcast is dangerous, simulate run without --doit # OPTIONS: --doit - broadcast is dangerous, simulate run without --doit
# --groups - send to groups instead of users # --groups - send to groups instead of users
# --both - send to users and groups # --both - send to users and groups (default with --db)
# --db name - send to all user/groups in jsonDB database (e.g. blocked)
# db file: name.jssh, db keys are user/chat id, values are ignored
# #
# format - normal, markdown, html (optional) # format - normal, markdown, html (optional)
# message - message to send in specified format # message - message to send in specified format
@ -24,13 +27,13 @@
# AUTHOR: KayM (gnadelwartz), kay@rrr.de # AUTHOR: KayM (gnadelwartz), kay@rrr.de
# CREATED: 16.12.2020 16:14 # CREATED: 16.12.2020 16:14
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
#=============================================================================== #===============================================================================
# shellcheck disable=SC2059
#### ####
# minimum messages seen in a chat before send a broadcast to it # minimum messages seen in a chat before send a broadcast to it
MINCOUNT=2 MINCOUNT=2
USERDB=""
#### ####
# broadcast is dangerous, without --doit we do a dry run ... # broadcast is dangerous, without --doit we do a dry run ...
@ -49,13 +52,18 @@ elif [ "$1" = "--groups" ]; then
SENDTO="groups" SENDTO="groups"
GROUPSALSO=" only" GROUPSALSO=" only"
shift shift
elif [ "$1" = "--db" ]; then
USERDB="${2%.jssh}"
MINCOUNT=""
GROUPSALSO=" and groups"
shift 2
fi fi
#### ####
# parse args ----------------- # parse args -----------------
SEND="send_message" SEND="send_message"
case "$1" in case "$1" in
"nor*"|"tex*") "nor"*|"tex"*)
SEND="send_normal_message" SEND="send_normal_message"
shift shift
;; ;;
@ -71,11 +79,11 @@ case "$1" in
printf "missing missing arguments\n" printf "missing missing arguments\n"
;& ;&
"-h"*) "-h"*)
printf 'usage: send_message [-h|--help] [--groups|--both] [format] "message ...." [debug]\n' printf 'usage: %s\n' "${USAGE}"
exit 1 exit 1
;; ;;
'--h'*) '--h'*)
sed -n '3,/###/p' <"$0" sed -n -e '/# shellcheck /d' -e '3,/###/p' <"$0"
exit 1 exit 1
;; ;;
esac esac
@ -85,15 +93,16 @@ esac
source "${0%/*}/bashbot_env.inc.sh" "$2" # $3 debug source "${0%/*}/bashbot_env.inc.sh" "$2" # $3 debug
# read in users # read in users from given DB or count.jssh
database="${USERDB:-${COUNTFILE}}"
declare -A SENDALL declare -A SENDALL
jssh_readDB_async "SENDALL" "${COUNTFILE}" jssh_readDB_async "SENDALL" "${database}"
if [ -z "${SENDALL[*]}" ]; then if [ -z "${SENDALL[*]}" ]; then
printf "${ORANGE}Countfile not found or empty,${NC}\n" printf "${ORANGE}User database not found or empty: ${NC}${database}\n"
fi fi
# loop over users # loop over users
printf "${GREEN}Sending broadcast message to all users of ${BOT_NAME}${NC}${GREY}" printf "${GREEN}Sending broadcast message to ${SENDTO}${GROUPSALSO} of ${BOT_NAME} using database:${NC}${GREY} ${database##*/}"
{ # dry run { # dry run
[ -z "${DOIT}" ] && printf "${NC}\n${ORANGE}DRY RUN! use --doit as first argument to execute broadcast...${NC}\n" [ -z "${DOIT}" ] && printf "${NC}\n${ORANGE}DRY RUN! use --doit as first argument to execute broadcast...${NC}\n"
@ -106,7 +115,7 @@ fi
# ignore everything not a user or group # ignore everything not a user or group
[[ ! "${USER}" =~ ^[0-9-]*$ ]] && continue [[ ! "${USER}" =~ ^[0-9-]*$ ]] && continue
# ignore chats with no count or lower MINCOUNT # ignore chats with no count or lower MINCOUNT
[[ ! "${SENDALL[${USER}]}" =~ ^[0-9]*$ || "${SENDALL[${USER}]}" -lt "${MINCOUNT}" ]] && continue [[ -n "${MINCOUNT}" && ( ! "${SENDALL[${USER}]}" =~ ^[0-9]*$ || "${SENDALL[${USER}]}" -lt "${MINCOUNT}" ) ]] && continue
(( COUNT++ )) (( COUNT++ ))
if [ -z "${DOIT}" ]; then if [ -z "${DOIT}" ]; then
printf "${SEND} ${USER} $1 $2\n" printf "${SEND} ${USER} $1 $2\n"

View File

@ -3,11 +3,11 @@
# #
# FILE: bin/send_message.sh # FILE: bin/send_message.sh
# #
# USAGE: send_edit_message.sh [-h|--help] [format] "CHAT[ID]" "MESSAGE[ID]" "message ...." [debug] USAGE='send_edit_message.sh [-h|--help] [format|caption] "CHAT[ID]" "MESSAGE[ID]" "message ...." [debug]'
# #
# DESCRIPTION: replace a message in the given user/group # DESCRIPTION: replace a message in the given user/group
# #
# OPTIONS: format - normal, markdown, html (optional) # OPTIONS: format - normal, markdown, html or caption for file caption (optional)
# CHAT[ID] - ID number of CHAT or BOTADMIN to send to yourself # CHAT[ID] - ID number of CHAT or BOTADMIN to send to yourself
# MESSAGE[ID] - message to replace # MESSAGE[ID] - message to replace
# message - message to send in specified format # message - message to send in specified format
@ -22,14 +22,14 @@
# AUTHOR: KayM (gnadelwartz), kay@rrr.de # AUTHOR: KayM (gnadelwartz), kay@rrr.de
# CREATED: 23.12.2020 16:52 # CREATED: 23.12.2020 16:52
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
#=============================================================================== #===============================================================================
#### ####
# parse args # parse args
SEND="edit_normal_message" SEND="edit_normal_message"
case "$1" in case "$1" in
"nor*"|"tex*") "nor"*|"tex"*)
SEND="edit_normal_message" SEND="edit_normal_message"
shift shift
;; ;;
@ -37,15 +37,19 @@ case "$1" in
SEND="edit_markdownv2_message" SEND="edit_markdownv2_message"
shift shift
;; ;;
"html") "htm"*)
SEND="edit_html_message" SEND="edit_html_message"
shift shift
;; ;;
"cap"*)
SEND="edit_message_caption"
shift
;;
'') '')
printf "missing arguments\n" printf "missing arguments\n"
;& ;&
"-h"*) "-h"*)
printf 'usage: send_edit_message [-h|--help] [format] "CHAT[ID]" "MESSAGE[ID]" "message ..." [debug]\n' printf 'usage: %s\n' "${USAGE}"
exit 1 exit 1
;; ;;
'--h'*) '--h'*)
@ -54,10 +58,9 @@ case "$1" in
;; ;;
esac esac
# set bashbot environment # set bashbot environment
# shellcheck disable=SC1090 # shellcheck disable=SC1090
source "${0%/*}/bashbot_env.inc.sh" "$4" # $4 debug source "${0%/*}/bashbot_env.inc.sh" "${4:-debug}" # $4 debug
#### ####
#### ####

View File

@ -2,15 +2,18 @@
#=============================================================================== #===============================================================================
# #
# FILE: bin/send_file.sh # FILE: bin/send_file.sh
# #
# USAGE: send_file.sh [-h|--help] "CHAT[ID]" "file" "caption ...." [debug] USAGE='send_file.sh [-h|--help] "CHAT[ID]" "file|URL" "caption ...." [type] [debug]'
# #
# DESCRIPTION: send a file to the given user/group # DESCRIPTION: send a file to the given user/group
# #
# OPTIONS: CHAT[ID] - ID number of CHAT or BOTADMIN to send to yourself # OPTIONS: CHAT[ID] - ID number of CHAT or BOTADMIN to send to yourself
# file - file to send, must be an absolute path or relative to pwd # file - local file to send, must be an absolute path or relative to pwd
# Note: must not contain .. or . and located below BASHBOT_ETC # Note: must not contain .. or . and located below BASHBOT_ETC
# URL - send an URL instead local file
#
# caption - message to send with file # caption - message to send with file
# type - photo, video, sticker, voice, document (optional)
# #
# -h - display short help # -h - display short help
# --help - this help # --help - this help
@ -21,18 +24,18 @@
# AUTHOR: KayM (gnadelwartz), kay@rrr.de # AUTHOR: KayM (gnadelwartz), kay@rrr.de
# CREATED: 25.12.2020 20:24 # CREATED: 25.12.2020 20:24
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
#=============================================================================== #===============================================================================
#### ####
# parse args # parse args
SEND="upload_file" SEND="send_file"
case "$1" in case "$1" in
'') '')
printf "missing arguments\n" printf "missing arguments\n"
;& ;&
"-h"*) "-h"*)
printf 'usage: send_file [-h|--help] "CHAT[ID]" "file" "caption ...." [debug]\n' printf 'usage: %s\n' "${USAGE}"
exit 1 exit 1
;; ;;
'--h'*) '--h'*)
@ -43,7 +46,7 @@ esac
# set bashbot environment # set bashbot environment
# shellcheck disable=SC1090 # shellcheck disable=SC1090
source "${0%/*}/bashbot_env.inc.sh" "$4" # $4 debug source "${0%/*}/bashbot_env.inc.sh" "${5:-debug}" # $5 debug
#### ####
# ready, do stuff here ----- # ready, do stuff here -----
@ -54,10 +57,11 @@ else
fi fi
FILE="$2" FILE="$2"
[[ "$2" != "/"* ]] && FILE="${PWD}/$2" # convert to absolute path if not start with / or http://
[[ ! ( "$2" == "/"* || "$2" =~ ^https*:// || "$2" == "file_id://"*) ]] && FILE="${PWD}/$2"
# send message in selected format # send message in selected format
"${SEND}" "${CHAT}" "${FILE}" "$3" "${SEND}" "${CHAT}" "${FILE}" "$3" "$4"
# output send message result # output send message result
jssh_printDB "BOTSENT" | sort -r jssh_printDB "BOTSENT" | sort -r

View File

@ -3,7 +3,7 @@
# #
# FILE: bin/send_message.sh # FILE: bin/send_message.sh
# #
# USAGE: send_message.sh [-h|--help] [format] "CHAT[ID]" "message ...." [debug] USAGE='send_message.sh [-h|--help] [format] "CHAT[ID]" "message ...." [debug]'
# #
# DESCRIPTION: send a message to the given user/group # DESCRIPTION: send a message to the given user/group
# #
@ -21,14 +21,14 @@
# AUTHOR: KayM (gnadelwartz), kay@rrr.de # AUTHOR: KayM (gnadelwartz), kay@rrr.de
# CREATED: 16.12.2020 11:34 # CREATED: 16.12.2020 11:34
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
#=============================================================================== #===============================================================================
#### ####
# parse args # parse args
SEND="send_message" SEND="send_message"
case "$1" in case "$1" in
"nor*"|"tex*") "nor"*|"tex"*)
SEND="send_normal_message" SEND="send_normal_message"
shift shift
;; ;;
@ -44,7 +44,7 @@ case "$1" in
printf "missing arguments\n" printf "missing arguments\n"
;& ;&
"-h"*) "-h"*)
printf 'usage: send_message [-h|--help] [format] "CHAT[ID]" "message ...." [debug]\n' printf 'usage: %s\n' "${USAGE}"
exit 1 exit 1
;; ;;
'--h'*) '--h'*)
@ -55,7 +55,7 @@ esac
# set bashbot environment # set bashbot environment
# shellcheck disable=SC1090 # shellcheck disable=SC1090
source "${0%/*}/bashbot_env.inc.sh" "$3" # $3 debug source "${0%/*}/bashbot_env.inc.sh" "${3:-debug}" # $3 debug
#### ####
# ready, do stuff here ----- # ready, do stuff here -----

View File

@ -15,11 +15,10 @@
# This file is public domain in the USA and all free countries. # This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
# #
# adjust your language setting here, e.g. when run from other user or cron. # bashbot locale defaults to c.UTF-8, adjust locale in mycommands.sh if needed
# https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment
export 'LC_ALL=C.UTF-8' export 'LC_ALL=C.UTF-8'
export 'LANG=C.UTF-8' export 'LANG=C.UTF-8'
export 'LANGUAGE=C.UTF-8' export 'LANGUAGE=C.UTF-8'
@ -52,12 +51,12 @@ Get the code in my [GitHub](http://github.com/topkecleon/telegram-bot-bash)
' '
# load modules on startup and always on on debug # load modules on startup and always on on debug
if [ -n "${1}" ]; then if [ -n "$1" ]; then
# load all readable modules # load all readable modules
for modules in "${MODULEDIR:-.}"/*.sh ; do for modules in "${MODULEDIR:-.}"/*.sh ; do
if [[ "${1}" == *"debug"* ]] || ! _is_function "$(basename "${modules}")"; then if [[ "$1" == *"debug"* ]] || ! _is_function "$(basename "${modules}")"; then
# shellcheck source=./modules/aliases.sh # shellcheck source=./modules/aliases.sh
[ -r "${modules}" ] && source "${modules}" "${1}" [ -r "${modules}" ] && source "${modules}" "$1"
fi fi
done done
fi fi
@ -73,13 +72,13 @@ export FILE_REGEX="${BASHBOT_ETC}/.*"
# load mycommands # load mycommands
# shellcheck source=./commands.sh # shellcheck source=./commands.sh
[ -r "${BASHBOT_ETC:-.}/mycommands.sh" ] && source "${BASHBOT_ETC:-.}/mycommands.sh" "${1}" [ -r "${BASHBOT_ETC:-.}/mycommands.sh" ] && source "${BASHBOT_ETC:-.}/mycommands.sh" "$1"
if [ -z "${1}" ] || [[ "${1}" == *"debug"* ]];then if [ -z "$1" ] || [[ "$1" == *"debug"* ]];then
# detect inline commands.... # detect inline commands....
# no default commands, all processing is done in myinlines() # no default commands, all processing is done in myinlines()
if [ "$INLINE" != "0" ] && [ -n "${iQUERY[ID]}" ]; then if [ "${INLINE}" != "0" ] && [ -n "${iQUERY[ID]}" ]; then
# forward iinline query to optional dispatcher # forward iinline query to optional dispatcher
_exec_if_function myinlines _exec_if_function myinlines

View File

@ -5,17 +5,11 @@
# #
# Description: run all tests, exit after failed test # Description: run all tests, exit after failed test
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
############################################################# #############################################################
# magic to ensure that we're always inside the root of our application, #shellcheck disable=SC1090
# no matter from which directory we'll run script source "${0%/*}/dev.inc.sh"
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
if [ "$GIT_DIR" != "" ] ; then
cd "$GIT_DIR/.." || exit 1
else
printf "Sorry, no git repository %s\n" "$(pwd)" && exit 1
fi
########################## ##########################
# create test environment # create test environment
@ -52,7 +46,7 @@ do
"${test}" "${TESTENV}" "${test}" "${TESTENV}"
ret=$? ret=$?
set +e set +e
if [ "$ret" -eq 0 ] ; then if [ "${ret}" -eq 0 ] ; then
printf "OK: ---- %s\n" "${test}" printf "OK: ---- %s\n" "${test}"
passed=$((passed+1)) passed=$((passed+1))
else else
@ -64,7 +58,7 @@ done
########################### ###########################
# cleanup depending on test state # cleanup depending on test state
if [ "$fail" -eq 0 ]; then if [ "${fail}" -eq 0 ]; then
printf 'SUCCESS ' printf 'SUCCESS '
exitcode=0 exitcode=0
rm -rf "${TESTENV}" rm -rf "${TESTENV}"
@ -82,4 +76,4 @@ printf "%s\n\n" "${passed} / ${tests}"
ls -ld /tmp/bashbot.test* 2>/dev/null && printf "Do not forget to delete bashbot test files in /tmp!!\n" ls -ld /tmp/bashbot.test* 2>/dev/null && printf "Do not forget to delete bashbot test files in /tmp!!\n"
exit ${exitcode} exit "${exitcode}"

22
dev/dev.inc.sh Normal file
View File

@ -0,0 +1,22 @@
#!/usr/bin/env bash
#############################################################
#
# File: dev/dev.inc.sh
#
# Description: common stuff for all dev scripts
#
#### $$VERSION$$ v1.30-0-g3266427
#############################################################
# magic to ensure that we're always inside the root of our application,
# no matter from which directory we'll run script
# shellcheck disable=SC2034
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
BASE_DIR=$(git rev-parse --show-toplevel 2>/dev/null)
if [ "${BASE_DIR}" != "" ] ; then
cd "${BASE_DIR}" || exit 1
else
printf "Sorry, no git repository %s\n" "$(pwd)" && exit 1
fi

View File

@ -3,16 +3,10 @@
# #
# works together with git pre-push.sh and ADD all changed files since last push # works together with git pre-push.sh and ADD all changed files since last push
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
# magic to ensure that we're always inside the root of our application, #shellcheck disable=SC1090
# no matter from which directory we'll run script source "${0%/*}/dev.inc.sh"
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
if [ "$GIT_DIR" != "" ] ; then
cd "$GIT_DIR/.." || exit 1
else
printf "Sorry, no git repository %s\n" "$(pwd)" && exit 1
fi
[ ! -f .git/.lastcommit ] && printf "No previous commit or hooks not installed, use \"git add\" instead ... Abort\n" && exit [ ! -f .git/.lastcommit ] && printf "No previous commit or hooks not installed, use \"git add\" instead ... Abort\n" && exit
@ -31,7 +25,9 @@ for file in ${FILES}
do do
[ -d "${file}" ] && continue [ -d "${file}" ] && continue
printf "%s" "${file} " printf "%s" "${file} "
git add "$file"
done done
printf " - Done.\n" printf " - Done.\n"
# stay with "." for (re)moved files!
git add .

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
############ ############
# NOTE: you MUST run install-hooks.sh again when updating this file! # NOTE: you MUST run install-hooks.sh again when updating this file!
@ -7,7 +7,7 @@
# magic to ensure that we're always inside the root of our application, # magic to ensure that we're always inside the root of our application,
# no matter from which directory we'll run script # no matter from which directory we'll run script
GIT_DIR=$(git rev-parse --git-dir) GIT_DIR=$(git rev-parse --git-dir)
cd "$GIT_DIR/.." || exit 1 cd "${GIT_DIR}/.." || exit 1
export HOOKDIR="dev/hooks" export HOOKDIR="dev/hooks"
LASTPUSH='.git/.lastcommit' LASTPUSH='.git/.lastcommit'

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
############ ############
# NOTE: you MUST run install-hooks.sh again when updating this file! # NOTE: you MUST run install-hooks.sh again when updating this file!
@ -7,7 +7,7 @@
# magic to ensure that we're always inside the root of our application, # magic to ensure that we're always inside the root of our application,
# no matter from which directory we'll run script # no matter from which directory we'll run script
GIT_DIR=$(git rev-parse --git-dir) GIT_DIR=$(git rev-parse --git-dir)
cd "$GIT_DIR/.." || exit 1 cd "${GIT_DIR}/.." || exit 1
export HOOKDIR="dev/hooks" export HOOKDIR="dev/hooks"
LASTPUSH='.git/.lastpush' LASTPUSH='.git/.lastpush'
@ -32,9 +32,9 @@ set +f
FILES="$(find ./* -name '*.sh' | grep -v -e 'DIST\/' -e 'STANDALONE\/' -e 'JSON.sh')" FILES="$(find ./* -name '*.sh' | grep -v -e 'DIST\/' -e 'STANDALONE\/' -e 'JSON.sh')"
set -f set -f
FILES="${FILES} $(sed '/^#/d' <"dev/shellcheck.files")" FILES="${FILES} $(sed '/^#/d' <"dev/shellcheck.files")"
if [ "$FILES" != "" ]; then if [ "${FILES}" != "" ]; then
# shellcheck disable=SC2086 # shellcheck disable=SC2086
shellcheck -x ${FILES} || exit 1 shellcheck -o all -e SC2249,SC2154 -x ${FILES} || exit 1
printf " OK\n............................\n" printf " OK\n............................\n"
else else
# something went wrong # something went wrong

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
############ ############
# NOTE: you MUST run install-hooks.sh again when updating this file! # NOTE: you MUST run install-hooks.sh again when updating this file!
@ -7,7 +7,7 @@
# magic to ensure that we're always inside the root of our application, # magic to ensure that we're always inside the root of our application,
# no matter from which directory we'll run script # no matter from which directory we'll run script
GIT_DIR=$(git rev-parse --git-dir) GIT_DIR=$(git rev-parse --git-dir)
cd "$GIT_DIR/.." || exit 1 cd "${GIT_DIR}/.." || exit 1
export HOOKDIR="dev/hooks" export HOOKDIR="dev/hooks"
LASTPUSH='.git/.lastpush' LASTPUSH='.git/.lastpush'

View File

@ -7,7 +7,7 @@
# #
# Usage: source inject-json.sh # Usage: source inject-json.sh
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
############################################################## ##############################################################
# download JSON.sh # download JSON.sh

View File

@ -1,16 +1,10 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# this has to run once atfer git clone # this has to run once atfer git clone
# and every time we create new hooks # and every time we create new hooks
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
# magic to ensure that we're always inside the root of our application, #shellcheck disable=SC1090
# no matter from which directory we'll run script source "${0%/*}/dev.inc.sh"
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
if [ "$GIT_DIR" != "" ] ; then
cd "$GIT_DIR/.." || exit 1
else
printf "Sorry, no git repository %s\n" "$(pwd)" && exit 1
fi
HOOKDIR="dev/hooks" HOOKDIR="dev/hooks"
@ -19,7 +13,7 @@ for hook in pre-commit post-commit pre-push
do do
rm -f "${GIT_DIR}/hooks/${hook}" rm -f "${GIT_DIR}/hooks/${hook}"
if [ -f "${HOOKDIR}/${hook}.sh" ]; then if [ -f "${HOOKDIR}/${hook}.sh" ]; then
printf "%s"" $hook" printf "%s"" ${hook}"
ln -s "../../${HOOKDIR}/${hook}.sh" "${GIT_DIR}/hooks/${hook}" ln -s "../../${HOOKDIR}/${hook}.sh" "${GIT_DIR}/hooks/${hook}"
fi fi
done done

View File

@ -7,25 +7,20 @@
# #
# Options: --notest - skip tests # Options: --notest - skip tests
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
############################################################## ##############################################################
# magic to ensure that we're always inside the root of our application, #shellcheck disable=SC1090
# no matter from which directory we'll run script source "${0%/*}/dev.inc.sh"
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
if [ "$GIT_DIR" != "" ] ; then
[[ "$GIT_DIR" != "/"* ]] && GIT_DIR="${PWD}/${GIT_DIR}"
cd "$GIT_DIR/.." || exit 1
else
printf "Sorry, no git repository %s\n" "$(pwd)" && exit 1
fi
VERSION="$(git describe --tags | sed -e 's/-[0-9].*//' -e 's/v//')" VERSION="$(git describe --tags | sed -e 's/-[0-9].*//' -e 's/v//')"
DISTNAME="telegram-bot-bash" DISTNAME="telegram-bot-bash"
DISTDIR="./DIST/${DISTNAME}" DISTDIR="./DIST/${DISTNAME}"
DISTFILES="bashbot.rc bashbot.sh commands.sh mycommands.sh mycommands.sh.clean bin doc examples scripts modules addons LICENSE README.md README.txt README.html" DISTMKDIR="data-bot-bash logs bin bin/logs addons"
DISTMKDIR="data-bot-bash logs bin bin/logs"
DISTFILES="bashbot.sh commands.sh mycommands.sh.clean bin doc examples scripts modules LICENSE README.md README.txt README.html"
DISTFILESDIST="mycommands.sh mycommands.conf bashbot.rc $(echo "addons/"*.sh)"
# run tests first! # run tests first!
for test in $1 dev/all-test*.sh for test in $1 dev/all-test*.sh
@ -47,6 +42,7 @@ cp -r ${DISTFILES} "${DISTDIR}"
cd "${DISTDIR}" || exit 1 cd "${DISTDIR}" || exit 1
printf "Create directories\n" printf "Create directories\n"
# shellcheck disable=SC2250
for dir in $DISTMKDIR for dir in $DISTMKDIR
do do
[ ! -d "${dir}" ] && mkdir "${dir}" [ ! -d "${dir}" ] && mkdir "${dir}"
@ -54,15 +50,15 @@ done
# do not overwrite on update # do not overwrite on update
printf "Create .dist files\n" printf "Create .dist files\n"
for file in mycommands.sh bashbot.rc addons/*.sh for file in ${DISTFILESDIST}
do do
[ "${file}" = "addons/*.sh" ] && continue [ "${file}" = "addons/*.sh" ] && continue
mv "${file}" "${file}.dist" cp "${BASE_DIR}/${file}" "${file}.dist"
done done
# inject JSON.sh into distribution # inject JSON.sh into distribution
# shellcheck disable=SC1090 # shellcheck disable=SC1090
source "$GIT_DIR/../dev/inject-json.sh" source "${BASE_DIR}/dev/inject-json.sh"
# make html doc # make html doc
printf "Create html doc\n" printf "Create html doc\n"
@ -73,13 +69,13 @@ source "../../dev/make-html.sh"
cd .. || exit 1 cd .. || exit 1
printf "Create dist archives\n" printf "Create dist archives\n"
# shellcheck disable=SC2046 # shellcheck disable=SC2046
zip -rq - "${DISTNAME}" --exclude $(cat "$GIT_DIR/../dev/${0##*/}.exclude") >"${DISTNAME}-${VERSION}.zip" zip -rq - "${DISTNAME}" --exclude $(cat "${BASE_DIR}/dev/${0##*/}.exclude") >"${DISTNAME}-${VERSION}.zip"
tar --exclude-ignore="$GIT_DIR/../dev/${0##*/}.exclude" -czf "${DISTNAME}-${VERSION}.tar.gz" "${DISTNAME}" tar --exclude-ignore="${BASE_DIR}/dev/${0##*/}.exclude" -czf "${DISTNAME}-${VERSION}.tar.gz" "${DISTNAME}"
printf "%s Done!\n" "$0" printf "%s Done!\n" "$0"
# shellcheck disable=SC2086 # shellcheck disable=SC2086
ls -ld ${DISTNAME}-${VERSION}.* ls -ld "${DISTNAME}-${VERSION}".*
# an empty DEBUG.log is created ... :-( # an empty DEBUG.log is created ... :-(
rm -f "$GIT_DIR/../test/"*.log rm -f "${BASE_DIR}/test/"*.log

View File

@ -1,5 +1,7 @@
data-bot-bash/* data-bot-bash/*
JSON.awk JSON.awk
bashbot.rc
mycommands.sh
awk-patch.sh awk-patch.sh
*.jssh* *.jssh*
botacl botacl

View File

@ -7,7 +7,7 @@
# #
# Usage: source make-hmtl # Usage: source make-hmtl
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
############################################################## ##############################################################
# check for correct dir # check for correct dir
@ -28,16 +28,17 @@ else
cp README.html html/index.html cp README.html html/index.html
# convert *.md files in doc to *.hmtl in html # convert *.md files in doc to *.hmtl in html
find doc -iname "*.md" -type f -exec sh -c\ find doc -iname "*.md" -type f -exec sh -c\
'printf "."; pandoc -s -f commonmark -M "title=Bashobot Documentation - ${0%.md}.html" "${0}" -o "./html/$(basename ${0%.md}.html)"' {} \; 'printf "."; pandoc -s -f commonmark -M "title=Bashobot Documentation - ${0%.md}.html" "$0" -o "./html/$(basename ${0%.md}.html)"' {} \;
# html for examples dir # html for examples dir
if [ -d "examples" ]; then if [ -d "examples" ]; then
EXAMPLES="examples" # add to final conversion job EXAMPLES="examples" # add to final conversion job
find examples -iname "*.md" -type f -exec sh -c\ find examples -iname "*.md" -type f -exec sh -c\
'printf "."; pandoc -s -f commonmark -M "title=Bashobot Documentation - ${0%.md}.html" "${0}" -o "${0%.md}.html"' {} \; 'printf "."; pandoc -s -f commonmark -M "title=Bashobot Documentation - ${0%.md}.html" "$0" -o "${0%.md}.html"' {} \;
fi fi
# final: convert links from *.md to *.html # final: convert links from *.md to *.html
# shellcheck disable=SC2248
find README.html html ${EXAMPLES} -iname "*.html" -type f -exec sh -c\ 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}' {} \; 'sed -i -E "s/href=\"(\.\.\/)*doc\//href=\"\1html\//g;s/href=\"(.*).md(#.*)*\"/href=\"\1.html\"/g" $0' {} \;
printf " Done!\n" printf " Done!\n"
fi fi
fi fi

View File

@ -6,38 +6,43 @@
# Description: # Description:
# even after make-distribution.sh bashbot is not self contained as it was in the past. # even after make-distribution.sh bashbot is not self contained as it was in the past.
# #
# Options: --notest
#
# If you your bot is finished you can use make-standalone.sh to create the # 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! # the old all-in-one bashbot: bashbot.sh and commands.sh only!
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
################################################################### ###################################################################
# magic to ensure that we're always inside the root of our application, #shellcheck disable=SC1090
# no matter from which directory we'll run script source "${0%/*}/dev.inc.sh"
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null) [ ! -f "bashbot.sh" ] && printf "bashbot.sh not found in %s\n" " $(pwd)" && exit 1
if [ "$GIT_DIR" != "" ] ; then
[[ "$GIT_DIR" != "/"* ]] && GIT_DIR="${PWD}/${GIT_DIR}"
cd "$GIT_DIR/.." || exit 1
else
[ ! -f "bashbot.sh" ] && printf "bashbot.sh not found in %s\n" " $(pwd)" && exit 1
fi
#DISTNAME="telegram-bot-bash" #DISTNAME="telegram-bot-bash"
DISTDIR="./STANDALONE/${DISTNAME}" DISTDIR="./STANDALONE"
DISTFILES="bashbot.sh bashbot.rc commands.sh mycommands.sh dev/obfuscate.sh modules scripts logs LICENSE README.* doc botacl botconfig.jssh" DISTMKDIR="data-bot-bash logs bin bin/logs addons"
DISTFILES="bashbot.sh bashbot.rc commands.sh mycommands.sh dev/obfuscate.sh modules bin scripts LICENSE README.* doc botacl botconfig.jssh $(echo "addons/"*.sh)"
# run pre_commit on files # run pre_commit on files
dev/hooks/pre-commit.sh [ "$1" != "--notest" ] && dev/hooks/pre-commit.sh
# create dir for distribution and copy files # create dir for distribution and copy files
printf "Create directories and copy files\n"
mkdir -p "${DISTDIR}" 2>/dev/null mkdir -p "${DISTDIR}" 2>/dev/null
# shellcheck disable=SC2086 # shellcheck disable=SC2086
cp -r ${DISTFILES} "${DISTDIR}" 2>/dev/null cp -r ${DISTFILES} "${DISTDIR}" 2>/dev/null
cd "${DISTDIR}" || exit 1 cd "${DISTDIR}" || exit 1
# shellcheck disable=SC2250
for dir in $DISTMKDIR
do
[ ! -d "${dir}" ] && mkdir "${dir}"
done
# inject JSON.sh into distribution # inject JSON.sh into distribution
# shellcheck disable=SC1090 # shellcheck disable=SC1090
source "$GIT_DIR/../dev/inject-json.sh" source "${BASE_DIR}/dev/inject-json.sh"
####################### #######################
# here the magic starts # here the magic starts
@ -66,7 +71,7 @@ printf "\n... create unified bashbot.sh\n"
{ {
# first head of bashbot.sh # first head of bashbot.sh
sed -n '0,/for modules in/ p' bashbot.sh | head -n -3 sed -n '0,/for module in/ p' bashbot.sh | head -n -3
# then mycommands from first non comment line on # then mycommands from first non comment line on
printf '\n##############################\n# bashbot modules starts here ...\n' printf '\n##############################\n# bashbot modules starts here ...\n'
@ -95,7 +100,7 @@ chmod +x bashbot.sh.min
# make html doc # make html doc
printf "Create html doc\n" printf "Create html doc\n"
#shellcheck disable=SC1090 #shellcheck disable=SC1090
source "$GIT_DIR/../dev/make-html.sh" source "${BASE_DIR}/dev/make-html.sh"
printf "%s Done!\n" "$0" printf "%s Done!\n" "$0"

View File

@ -2,7 +2,7 @@
# #
# joke hack to obfuscate bashbot.min.sh # joke hack to obfuscate bashbot.min.sh
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
# shellcheck disable=SC2028,SC2016,SC1117 # shellcheck disable=SC2028,SC2016,SC1117
infile="bashbot.sh" infile="bashbot.sh"

View File

@ -1,4 +1,4 @@
# list of additional files to check from shellcheck # list of additional files to check from shellcheck
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
bashbot.rc bashbot.rc
mycommands.sh.clean mycommands.sh.clean

View File

@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
# shellcheck disable=SC2016 # shellcheck disable=SC2016
# #
# Easy Versioning in git: # Easy Versioning in git:
@ -34,14 +34,8 @@
# run this script to (re)place Version number in files # run this script to (re)place Version number in files
# #
# magic to ensure that we're always inside the root of our application, #shellcheck disable=SC1090
# no matter from which directory we'll run script source "${0%/*}/dev.inc.sh"
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
if [ "$GIT_DIR" != "" ] ; then
cd "$GIT_DIR/.." || exit 1
else
printf "Sorry, no git repository %s\n" "$(pwd)" && exit 1
fi
unset IFS unset IFS
# set -f # if you are paranoid use set -f to disable globbing # set -f # if you are paranoid use set -f to disable globbing
@ -52,16 +46,28 @@ printf "Update to version %s ...\n" "${VERSION}"
FILES="$(find ./*)" FILES="$(find ./*)"
[ "$1" != "" ] && FILES="$*" [ "$1" != "" ] && FILES="$*"
for file in $FILES # autogenerate REMADME.html REMADE.txt
if [[ "${FILES}" == *"README.md"* ]]; then
FILES+=" README.html README.txt"
type -f pandoc >/dev/null && pandoc -s -f commonmark -M "title=Bashbot README" README.md >README.html
cat "doc/bashbot.ascii" >"README.txt"
if [ -r "README.html" ] && type -f html2text >/dev/null; then
# convert html links to text [link]
sed -E 's/<a href="([^>]+)">([^<#]+)<\/a>/\2 [\1]/' <README.html |\
html2text -style pretty -width 90 - >>README.txt
else
type -f fold >/dev/null && fold -s -w 90 README.md >>README.txt
fi
fi
# change version string in given files
for file in ${FILES}
do do
[ ! -f "${file}" ] && continue [ ! -f "${file}" ] && continue
#[ "${file}" == "version" ] && continue #[ "${file}" == "version" ] && continue
printf "%s" " ${file}" >&2 printf "%s" " ${file}" >&2
sed -i 's/^#### $$VERSION$$.*/#### \$\$VERSION\$\$ '"${VERSION}"'/' "${file}" sed -i 's/^#### $$VERSION$$.*/#### \$\$VERSION\$\$ '"${VERSION}"'/' "${file}"
done done
# try to compile README.txt
printf " README.txt" >&2
type -f pandoc >/dev/null && pandoc -s -f commonmark -M "title=Bashbot README" README.md >README.html
fold -s README.md >README.txt
printf " done.\n" printf " done.\n"

View File

@ -2,7 +2,7 @@
## Check bash installation ## Check bash installation
There may systems where bash seems to be installed but it is not, e.g. embedded systems, or where bash is to old. There may systems where bash seems to be installed but it is not (_e.g. embedded systems_) or where bash is to old.
Bashbot has some builtin checks but it may better to check before installing bashbot. Bashbot has some builtin checks but it may better to check before installing bashbot.
Run the following commands to see if your bash looks ok ... Run the following commands to see if your bash looks ok ...
@ -15,7 +15,7 @@ if which bash; then echo "bash seems available..."; else echo "NO bash"; fi
bash -c 'if eval "a[1]=1"; then echo "Shell support arrays..."; else echo "Shell has NO arrays"; fi' bash -c 'if eval "a[1]=1"; then echo "Shell support arrays..."; else echo "Shell has NO arrays"; fi'
# check for bash version by feature # check for bash version by feature
bash -c 'if [ "$(echo -e "\u1111")" != "\u1111" ]; then echo "Bash version ok ..."; else echo "Bash version may to old ..."; fi' bash -c 'if [ "$(LANG=C.UTF-8 echo -e "\u1111")" != "\u1111" ]; then echo "Bash version ok ..."; else echo "Bash version may to old ..."; fi'
# display bash version, must be greater than 4.3 # display bash version, must be greater than 4.3
bash --version | grep "bash" bash --version | grep "bash"
@ -23,58 +23,60 @@ bash --version | grep "bash"
## Install bashbot ## Install bashbot
1. Go to the directory you want to install bashbot, e.g. Installing bashbot is very simple: Download and extract the installation archive.
* your $HOME directory (install and run with your user-ID)
* /usr/local if you want to run as service
2. [Download latest release zip / tar archive from github](https://github.com/topkecleon/telegram-bot-bash/releases/latest) and extract all files.
3. Change into the directory `telegram-bot-bash`
4. Copy `mycommands.sh.dist` or `mycommands.sh.clean` to `mycommands.sh`
5. Run `./bashbot.sh init` to setup the environment and enter your Bots token given by botfather.
Edit `mycommands.sh` to fit your needs. 1. Choose a directory to install bashbot (_e.g.your HOME or /usr/local_)
2. Download [latest release zip / tar archive](https://github.com/topkecleon/telegram-bot-bash/releases/latest) and extract all files.
3. Change into the directory `telegram-bot-bash`
4. Copy `mycommands.conf.dist` `mycommands.conf`
4. Copy `mycommands.sh.dist` or `mycommands.sh.clean` to `mycommands.sh`
5. Run `./bashbot.sh init`\* to setup the environment and enter your Bots token given by botfather.
Edit config in `mycommands.conf` and commands in `mycommands.sh` to fit your need.
Now your Bot is ready to start ... Now your Bot is ready to start ...
**If you are new to Bot development read [Bots: An introduction for developers](https://core.telegram.org/bots)** *If you are new to Bot development read [Bots: An introduction for developers](https://core.telegram.org/bots)*
\* _Run with sudo if you want to run bashbot from different user, e.g. from `bashbot.rc`._
### Update bashbot ### Update bashbot
**Important: all files including `mycommands.sh` may overwritten, make a backup!** Update bashbot is almost identical to installing bashbot: Download and extract the installation archive.
1. Go to the directory where you have installed bashbot, e.g. **Important: All files may overwritten, make a backup!**
* your $HOME directory
* /usr/local 1. Go to the directory where bashbot is installed (_e.g.$HOME/telegram-bot-bash or /usr/local/telegram-bot-bash_)
2. [Download latest release zip / tar archive from github](https://github.com/topkecleon/telegram-bot-bash/releases/latest) 2. Download [latest release zip / tar archive](https://github.com/topkecleon/telegram-bot-bash/releases/latest)
3. Stop all running instances of bashbot `./bashbot.sh stop` 3. Stop all running instances of bashbot `./bashbot.sh stop`
4. Extract all files to your existing bashbot dir 4. Change to parent directory of bashbot installation and extract all files from archive.
5. Run `sudo ./bashbot.sh init` to setup your environment after the update 5. Run `./bashbot.sh init`\* to setup your environment after the update
6. Restart your bot `./bashbot.sh start`
If you modified `commands.sh` move your changes to `mycommands.sh`, this avoids overwriting your commands on every update. `mycommands.conf` and `mycommands.sh` will not overwritten, this avoids losing your bot config and commands on updates.
Now you can restart your bashbot instances.
*Note*: If you are updating from a pre-1.0 version, update to [Version 1.20](https://github.com/topkecleon/telegram-bot-bash/releases/tags/v1.20) first! *Note*: If you are updating from a pre-1.0 version, update to [Version 1.20](https://github.com/topkecleon/telegram-bot-bash/releases/tags/v1.20) first!
### Use JSON.awk (beta) ### Use JSON.awk
[JSON.awk](https://github.com/step-/JSON.awk) is an awk port of `JSON.sh`, it provides the same functionality but is 5 times faster. [JSON.awk](https://github.com/step-/JSON.awk) is an awk port of `JSON.sh`, it provides the same functionality but is 5 times faster.
Most systems with awk can use `JSON.awk` as drop in replacement On most systems you can use `JSON.awk` with system default awk installation.
( [gnu awk, posix awk, mawk, busybox akw](https://github.com/step-/JSON.awk#compatibility-with-awk-implementations) ). ( [gnu awk, posix awk, mawk, busybox akw](https://github.com/step-/JSON.awk#compatibility-with-awk-implementations) ).
After you have checked that `JSON.awk.dist` is working on your system copy it to `JSON.awk` and (re)start bashbot.
BSD and MacOS users must install `gnu awk` and adjust the shebang, see below BSD and MacOS users must install `gnu awk` and adjust the shebang, see below
After you have checked that 'JSON.awk.dist' is working correct on your system copy it to `JSON.awk` and (re)start bashbot. *Note*: To install or update `JSON.awk` manually execute the following commands in the directory `JSON.sh/`:
Note: If you are not using the zip / tar archive, you must install `JSON.awk` manually into the same directory as 'JSON.sh`:
wget https://cdn.jsdelivr.net/gh/step-/JSON.awk/JSON.awk wget https://cdn.jsdelivr.net/gh/step-/JSON.awk/JSON.awk
wget https://cdn.jsdelivr.net/gh/step-/JSON.awk/tool/patch-for-busybox-awk.sh wget https://cdn.jsdelivr.net/gh/step-/JSON.awk/tool/patch-for-busybox-awk.sh
bash patch-for-busybox-awk.sh bash patch-for-busybox-awk.sh
chmod +x JSON.awk
### Install bashbot from git repo ### Install bashbot from git repo
Installation and Updates should be done using the zip / tar archives provided on github to avoid Installation and updates should be done using the zip / tar archives provided on github to avoid
problems and not overwriting your bot config and `mycommands.sh`. problems and not overwriting your bot config and `mycommands.sh`.
Nevertheless you can install or update bashbot from a git repo, see next chapter ... Nevertheless you can install or update bashbot from a git repo, see next chapter ...
@ -82,7 +84,8 @@ Nevertheless you can install or update bashbot from a git repo, see next chapter
### Create Installation / Update archives ### Create Installation / Update archives
To install or update bashbot from git repo execute `dev/make-distribution.sh`, this creates the archives and set up bashbot to run in `DIST/telegram.bot-bash`. To install or update bashbot from git repo execute `dev/make-distribution.sh`.
This creates the installation archives in `DIST/` and a ready to run test installation in `DIST/telegram.bot-bash`.
*Note:* You should be familiar with `git`. *Note:* You should be familiar with `git`.
@ -92,10 +95,10 @@ To install or update bashbot from git repo execute `dev/make-distribution.sh`, t
4. Run ` dev/make-distribution.sh` (_add --notest to skip tests_) 4. Run ` dev/make-distribution.sh` (_add --notest to skip tests_)
5. Change to dir `DIST/` 5. Change to dir `DIST/`
Use the archives created in `DIST/` to install or update bashbot as described above. Use the installation archives to install or update bashbot as described above.
To run a test bot, e.g. while development or testing latest changes, you can use the bashbot installation provided in `DIST/telegram-bot-bash`. To run a test bot, e.g. while development or testing latest changes, you can use the bashbot installation provided in `DIST/telegram-bot-bash`.
To update the test installation, e.g. after git pull, local changes or switch master/develop, run `dev/make-distrubition.sh` again. To update the test installation (_after git pull, local changes or switch master/develop_) run `dev/make-distribution.sh` again.
### Note for BSD and MacOS ### Note for BSD and MacOS
@ -104,32 +107,30 @@ To update the test installation, e.g. after git pull, local changes or switch ma
see e.g. [Install Bash on Mac](http://macappstore.org/bash/) see e.g. [Install Bash on Mac](http://macappstore.org/bash/)
**On BSD and MacOS** I recommend to install gnu coreutils and include them in your PATH **On BSD and MacOS** I recommend to install gnu coreutils and include them in your PATH
environment variable before running bashbot, e.g. the gnu versions of sed, grep, find ... environment variable before running bashbot, e.g. the gnu versions of sed, grep, find, awk ...
On BSD and MacOS you must adjust the shebang line of the scripts ```bashbot.sh``` and ```json.sh``` to point to to the correct bash On BSD and MacOS you must adjust the shebang line of the scripts `bashbot.sh` and `json.sh` to point to to the correct bash
or use the script: ```examples/bash2env *.sh */*.sh``` to convert them for you. or use the script: `examples/bash2env *.sh */*.sh` to convert them for you.
Bashbot will stay with /bin/bash shebang, as using a fixed path is more secure than the portable /usr/bin/env variant, see Bashbot will stay with `#!/bin/bash` shebang, as using a fixed path is IMHO more secure than the portable '!/usr/bin/env bash` variant.
[Security Considerations](../README.md#Security-Considerations)
I considered to make bashbot BSD sed compatible, but much of the bashbot "magic" relies on Compatibility with BSD/MacOS will result in a rewrite of all grep/sed commands with an uncertain outcome,
(gnu) sed features, e.g. alternation ```|```, non printables ```\n\t\<``` or repeat ```?+``` pattern, not supported by BSD sed.
BSD/MacOS sed compatibility will result in a rewrite of all grep/sed commands with an uncertain outcome,
see [BSD/MacOS vs. GNU sed](https://riptutorial.com/sed/topic/9436/bsd-macos-sed-vs--gnu-sed-vs--the-posix-sed-specification) see [BSD/MacOS vs. GNU sed](https://riptutorial.com/sed/topic/9436/bsd-macos-sed-vs--gnu-sed-vs--the-posix-sed-specification)
to get an impression how different they are. to get an impression how different they are.
### Notes on Changes ### Notes on Changes
#### Config moved to mycommands.conf
From Version 1.30 on config for new bots is moved to `mycommands.conf`.
#### Support for update from pre-1.0 removed #### Support for update from pre-1.0 removed
From Version 1.21 on updating from a pre-1.0 version is no more supported! From Version 1.21 on updating from a pre-1.0 version (_no \*.jssh config_) is no more supported!
You must update to [Version 1.20](https://github.com/topkecleon/telegram-bot-bash/releases/tags/v1.20) first! You must update to [Version 1.20](https://github.com/topkecleon/telegram-bot-bash/releases/tags/v1.20) first!
#### [Next Create Bot](1_firstbot.md) #### [Next Create Bot](1_firstbot.md)
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427

View File

@ -65,5 +65,5 @@ group. This step is up to you actually.
#### [Prev Installation](0_install.md) #### [Prev Installation](0_install.md)
#### [Next Getting started](2_usage.md) #### [Next Getting started](2_usage.md)
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427

View File

@ -19,8 +19,10 @@ Have FUN!
``` ```
. .
├── mycommands.sh # THIS is your bot, place logic and commands here! ├── mycommands.sh # THIS is your bot, place logic and commands here!
├── mycommands.conf # place your bot config and bot messages here!
├── mycommands.sh.clean # copy to "mycommands.sh" if you start developing your bot ├── mycommands.conf.dist # copy to "mycommands.conf" if not exist
├── mycommands.sh.clean # copy to "mycommands.sh" to start developing a new bot
├── mycommands.sh.dist # example bot, also used for testing bashbot internally ├── mycommands.sh.dist # example bot, also used for testing bashbot internally
├── count.jssh # count bashbot usage in jssh key-value store ├── count.jssh # count bashbot usage in jssh key-value store
@ -33,6 +35,7 @@ Have FUN!
├── bin # ready to use scripts, use `scriptname --help` for help ├── bin # ready to use scripts, use `scriptname --help` for help
│   ├── send_message.sh # send message to given chat │   ├── send_message.sh # send message to given chat
│   ├── edit_message.sh # replace given message id in given chat │   ├── edit_message.sh # replace given message id in given chat
│   ├── delete_message.sh # delete given message id in given chat
│   ├── send_broadcast.sh # send message to all known chats │   ├── send_broadcast.sh # send message to all known chats
│   ├── send_file.sh # send file to given chat │   ├── send_file.sh # send file to given chat
│   ├── bashbot_stats.sh # does what it says ... │   ├── bashbot_stats.sh # does what it says ...
@ -138,7 +141,8 @@ Note: to get help about a script in bin/ run `scriptname.sh --help`
---- ----
## Receive data ## Receive data
Evertime a Message is received, you can read incoming data using the following variables: Evertime a Telegram update is received, you can read incoming data using the following variables:
In case you need other update values, the array `UPD` contains complete Telegram response.
### Regular Messages ### Regular Messages
@ -252,14 +256,19 @@ they contain the following variables only:
* `${iQUERY[LAST_NAME]}`: User's last name * `${iQUERY[LAST_NAME]}`: User's last name
### Send Message Results ## Send data / get response
BOTSENT is set on every send_xxx action and only valid until next send action. For more on message results see. After every `send_xxx` `get_xxx` call the array BOTSENT contains the most important values from Telegram response.
[Advanced Usage](3_advanced.md) In case you need other response values , the array `UPD` contains complete Telegram response.
### BOTSENT array
* `$BOTSENT`: This array contains the parsed results from the last transmission to telegram. * `$BOTSENT`: This array contains the parsed results from the last transmission to telegram.
* `${BOTSENT[OK]}`: contains the string `true`: after a successful transmission * `${BOTSENT[OK]}`: contains the string `true`: after a successful transmission
* `${BOTSENT[ID]}`: Message ID of sent message, image, file etc., if OK is true * `${BOTSENT[ID]}`: Message ID of sent message, image, file etc., if OK is true
* `${BOTSENT[FILE_ID]}`: unique identifier returned for an uploaded file or URL
* `${BOTSENT[FILE_TYPE]}`: file type: photo, audio, video, sticker, voice, document
## Usage of bashbot functions ## Usage of bashbot functions
@ -314,9 +323,10 @@ send_message "${CHAT[ID]}" "lol" "safe"
#### Send files, locations, keyboards. #### Send files, locations, keyboards.
To send images, videos, voice files, photos etc. use the `send_photo`function (remember to change the safety Regex @ line 14 of command.sh to allow sending files only from certain directories): To send local files or URL's (photo, video, voice, sticker, documents) use the `send_file` function.
```bash ```bash
send_file "${CHAT[ID]}" "/home/user/doge.jpg" "Lool" send_file "${CHAT[ID]}" "/home/user/dog.jpg" "Lool" "photo"
send_file "${CHAT[ID]}" "https://images-na.ssl-images-amazon.com/images/I/81DQ0FpoSNL._AC_SL1500_.jpg"
``` ```
To send custom keyboards use the `send_keyboard`function: To send custom keyboards use the `send_keyboard`function:
```bash ```bash
@ -341,5 +351,5 @@ send_action "${CHAT[ID]}" "action"
#### [Prev Create Bot](1_firstbot.md) #### [Prev Create Bot](1_firstbot.md)
#### [Next Advanced Usage](3_advanced.md) #### [Next Advanced Usage](3_advanced.md)
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427

View File

@ -62,6 +62,7 @@ You must use the function `user_is_allowed` to check if a user has the capabilit
# GLOBAL commands start here, only edit messages # GLOBAL commands start here, only edit messages
'/start'*) '/start'*)
user_is_botadmin "${USER[ID]}" && send_markdown_message "${CHAT[ID]}" "You are *BOTADMIN*." user_is_botadmin "${USER[ID]}" && send_markdown_message "${CHAT[ID]}" "You are *BOTADMIN*."
# true if: user is botadmin, user is group admin, user is allowed
if user_is_allowed "${USER[ID]}" "start" "${CHAT[ID]}" ; then if user_is_allowed "${USER[ID]}" "start" "${CHAT[ID]}" ; then
bot_help "${CHAT[ID]}" bot_help "${CHAT[ID]}"
else else
@ -171,7 +172,7 @@ All output of the script will be sent to the user, to stop a background job use:
```bash ```bash
kill_back "${CHAT[ID]}" "jobname" kill_back "${CHAT[ID]}" "jobname"
``` ```
You can also suspend and resume currently running background jobs from outside bashbot, e.g. in your startup schripts: You can also suspend and resume currently running background jobs from outside bashbot, e.g. in your startup scripts:
```bash ```bash
./bashbot.sh suspendback ./bashbot.sh suspendback
./bashbot.sh resumeback ./bashbot.sh resumeback
@ -301,5 +302,5 @@ Note: If you disable automatic retry, se above, you disable also connection prob
#### [Prev Getting started](2_usage.md) #### [Prev Getting started](2_usage.md)
#### [Next Expert Use](4_expert.md) #### [Next Expert Use](4_expert.md)
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427

View File

@ -10,12 +10,12 @@ two bytes for encoding and covers almost all `Latin` alphabets, also `Greek`, `C
#### Setting up your Environment #### Setting up your Environment
In general `bash` and `GNU` utitities are UTF-8 aware if you to setup your environment In general `bash` and `GNU` utitities are UTF-8 aware if you to setup your environment
and your scripts accordingly: and your scripts accordingly (_locale setting_):
1. Your Terminal and Editor must support UTF-8: 1. Your Terminal and Editor must support UTF-8:
Set Terminal and Editor locale to UTF-8, eg. in `Settings/Configuration` select UTF-8 (Unicode) as Charset. Set Terminal and Editor locale to UTF-8, eg. in `Settings/Configuration` select UTF-8 (Unicode) as Charset.
2. Set `Shell` environment to UTF-8 in your `.profile` and your scripts. The usual settings are: 2. Set `Shell` locale environment to UTF-8 in your `.profile` and your scripts. The usual settings are:
```bash ```bash
export 'LC_ALL=C.UTF-8' export 'LC_ALL=C.UTF-8'
@ -31,11 +31,67 @@ export 'LANGUAGE=de_DE.UTF-8'
```bash ```bash
export 'LC_ALL=en_US.UTF-8' export 'LC_ALL=en_US.UTF-8'
export 'LANG=de_en_US.UTF-8' export 'LANG=de_en_US.UTF-8'
export 'LANGUAGE=den_US.UTF-8' export 'LANGUAGE=en_US.UTF-8'
``` ```
3. make sure your bot scripts use the correct settings, eg. include the lines above at the beginning of your scripts 3. make sure your bot scripts use the correct settings, eg. include the lines above at the beginning of your scripts
To display all available locales on your system run `locale -a | more`. [Gentoo Wiki](https://wiki.gentoo.org/wiki/UTF-8)
#### Known locale pitfalls
##### Missing C locale
Even required by POSIX standard some systems (e.g. Manjaro Linux) has `C` and `C.UTF-8` locale not installed.
If bashbot display a warning about missing locale you must install `C` and `C.UTF-8` locale.
If you don't know what locales are installed on your sytsem use `locale -a` to display them.
[Gentoo Wiki](https://wiki.gentoo.org/wiki/UTF-8).
##### Character classes
In ASCII times it was clear `[:lower:]` and `[a-z]` means ONLY the lowercase letters `[abcd...xyz]`.
With the introduction of locales, character classes and ranges now contain all characters fitting the class definition.
This means with a Latin UTF-8 locale `[:lower:]` and `[a-z]` contains also e.g. `á ø ü` etc,
see [Unicode Latin lowercase letters](https://www.fileformat.info/info/unicode/category/Ll/list.htm)
If that's ok for your script you're fine, but many scripts rely on the idea of ASCII ranges and may produce undesired results.
```bash
# try with different locales ...
# new bash to not change your current locale!
bash
lower="abcö"
echo "$LC_ALL $LC_COLLATE"
[[ "$lower" =~ ^[a-z]+$ ]] && echo "Ups, $lower is all lower case!" || echo "OK, not lower case"
LC_ALL="en_US.UTF-8"
[[ "$lower" =~ ^[a-z]+$ ]] && echo "Ups, $lower is all lower case!" || echo "OK, not lower case"
LC_ALL="C"
[[ "$lower" =~ ^[a-z]+$ ]] && echo "Ups, $lower is all lower case!" || echo "OK, not lower case"
```
There are three solutions:
1. list exactly the characters you want: `[abcd...]`
2. instruct bash to use `C` locale for ranges: `shopt -s "globasciiranges"`
3. use `LC_COLLATE` to change behavior of all programs: `export LC_COLLATE=C`
To work independent of language and bash settings bashbot uses solution 1.: Own "ranges" if an exact match is mandatory:
```bash
azazaz='abcdefghijklmnopqrstuvwxyz' # a-z :lower:
AZAZAZ='ABCDEFGHIJKLMNOPQRSTUVWXYZ' # A-Z :upper:
o9o9o9='0123456789' # 0-9 :digit:
azAZaz="${azazaz}${AZAZAZ}" # a-zA-Z :alpha:
azAZo9="${azAZaz}${o9o9o9}" # a-zA-z0-9 :alnum:
# e.g. characters allowed for key in key/value pairs
JSSH_KEYOK="[-${azAZo9},._]"
```
#### Bashbot UTF-8 Support #### Bashbot UTF-8 Support
Bashbot handles all messages transparently, regardless of the charset in use. The only exception is when converting from JSON data to strings. Bashbot handles all messages transparently, regardless of the charset in use. The only exception is when converting from JSON data to strings.
@ -45,11 +101,11 @@ The Emoticons ` 😁 😘 ❤️ 😊 👍 ` are encoded as: ` \uD83D\uDE01 \uD8
**This "mixed" JSON encoding needs special handling and can not decoded from** `echo -e` or `printf '%s\\n'` **This "mixed" JSON encoding needs special handling and can not decoded from** `echo -e` or `printf '%s\\n'`
Bbashbot uses an internal, pure bash implementation which is well tested now, even there may some corner cases*. Bashbot uses an internal, pure bash implementation which is well tested now, even there may some corner cases*.
### Run as other user or system service ### Run as other user or system service
Bashbot is desingned to run manually by the user who installed it. Nevertheless it's possible to run it by an other user-ID, as a system service or scheduled from cron. This is recommended if you want to bashbot run as a service. Bashbot is designed to run manually by the user who installed it. Nevertheless it's possible to run it by an other user-ID, as a system service or scheduled from cron. This is recommended if you want to bashbot run as a service.
Setup the environment for the user you want to run bashbot and enter desired username, e.g. nobody : Setup the environment for the user you want to run bashbot and enter desired username, e.g. nobody :
```bash ```bash
@ -98,7 +154,7 @@ To use bashbot as a system service include a working `bashbot.rc` in your init s
An example crontab is provided in `examples/bashbot.cron`. An example crontab is provided in `examples/bashbot.cron`.
- If you are running bashbot with your user-ID, copy the examples lines to your crontab and remove username `nobody`. - If you are running bashbot with your user-ID, copy the examples lines to your crontab and remove username `nobody`.
- if you run bashbot as an other user or a system service edit `examples/bashbot.cron` to fit your needs and replace username `nobody` with the username you want to run bashbot. copy the modified file to `/etc/cron.d/bashbot` - if you run bashbot as an other user or a system service edit `examples/bashbot.cron` to fit your needs and replace username `nobody` with the username you want to run bashbot. Copy the modified file to `/etc/cron.d/bashbot`
### Use bashbot from CLI and scripts ### Use bashbot from CLI and scripts
@ -175,10 +231,10 @@ User or Chat you are in. See [Send Messages](2_usage.md#sending-messages).
*Examples:* You can test this by sending messages to yourself: *Examples:* You can test this by sending messages to yourself:
```bash ```bash
# fist Hello World # first Hello World
send_normal_message "$(getConfigKey "botadmin")" "Hello World! This is my first message" send_normal_message "$(getConfigKey "botadmin")" "Hello World! This is my first message"
# now with some markdown and HTML # now with some markdown and HTML
send_markdown_message "$(getConfigKey "botadmin")" '*Hello World!* _This is my first markdown message_' send_markdown_message "$(getConfigKey "botadmin")" '*Hello World!* _This is my first markdown message_'
send_html_message "$(getConfigKey "botadmin")" '<b>Hello World!</b> <em>This is my first HTML message</em>' send_html_message "$(getConfigKey "botadmin")" '<b>Hello World!</b> <em>This is my first HTML message</em>'
send_keyboard "$(getConfigKey "botadmin")" 'Do you like it?' '[ "Yep" , "No" ]' send_keyboard "$(getConfigKey "botadmin")" 'Do you like it?' '[ "Yep" , "No" ]'
@ -202,10 +258,10 @@ This section describe how you can customize bashbot to your needs by setting env
#### Change file locations #### Change file locations
In standard setup bashbot is self containing, this means you can place 'telegram-bot-bash' any location In standard setup bashbot is self containing, this means you can place 'telegram-bot-bash' any location
and run it from there. All files - program, config, data etc - will reside in 'telegram-bot-bash'. and run it from there. All files - program, config, data etc - will reside in 'telegram-bot-bash'.
If you want to have other locations for config, data etc, define and export the following environment variables. If you want to have other locations for config, data etc, define and export the following environment variables.
**Note: all specified directories and files must exist or running 'bashbot.sh' will fail.** **Note: all specified directories and files must exist or running 'bashbot.sh' will fail.**
##### BASHBOT_ETC ##### BASHBOT_ETC
@ -323,7 +379,7 @@ BASHBOT_TIMEOUT to a numeric value between 1 and 999. Any non numeric or negativ
##### BASHBOT_SLEEP ##### BASHBOT_SLEEP
Instead of polling permanently or with a fixed delay, bashbot offers a simple adaptive polling. Instead of polling permanently or with a fixed delay, bashbot offers a simple adaptive polling.
If messages are received bashbot polls with no dealy. If no messages are available bashbot add 100ms delay If messages are received bashbot polls with no delay. If no messages are available bashbot add 100ms delay
for every poll until the maximum of BASHBOT_SLEEP ms. for every poll until the maximum of BASHBOT_SLEEP ms.
```bash ```bash
unset BASHBOT_SLEEP # 5000ms (default) unset BASHBOT_SLEEP # 5000ms (default)
@ -378,5 +434,5 @@ for every poll until the maximum of BASHBOT_SLEEP ms.
#### [Prev Advanced Use](3_advanced.md) #### [Prev Advanced Use](3_advanced.md)
#### [Next Best Practice](5_practice.md) #### [Next Best Practice](5_practice.md)
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427

View File

@ -160,5 +160,5 @@ The second warning is about an unused variable, this is true because in our exam
#### [Prev Best Practice](5_practice.md) #### [Prev Best Practice](5_practice.md)
#### [Next Functions Reference](6_reference.md) #### [Next Functions Reference](6_reference.md)
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427

View File

@ -115,23 +115,36 @@ The main use case for send_message is to process the output of interactive chats
### File, Album, Location, Venue, Keyboard ### File, Album, Location, Venue, Keyboard
##### send_file ##### send_file
send_file can send different type's of files, e.g. photos, stickers, audio, media, etc. send_file can send local files, URL's or file_id's as different filex types (_e.g. photo video sticker_)
[see Telegram API documentation](https://core.telegram.org/bots/api#sending-files).
It's recommended to use __absolute path names__ (_starting with `/`_), as relative path names are threated as __relative to UPLOADDIR__ `data-bot-bash/upload`! *usage:* send_file "${CHAT[ID]}" "file/URL/file_id" "caption" ["type"]
For security reasons the following restrictions apply: URL's must start with `http://` or `https://` and remote server must send an appropriate media type.
A file_id must start with `file_id://`, all other file names are threated as local files.
If Telegram accepts the file `BOTSENT[FILE_ID]` and `BOTSENT[FILE_TYPE]` are set.
- absolute path name must match the __shell regex__ `FILE_REGEX` (_not file glob_) Argument "type" is optional, if not given `send_file` detects file type by the file extension.
if file/URL has no extension `photo` is assumed. Unknown types and extensions are send as type `document`
Supported file types are: photo (_png jpg jpeg gif pic_) audio (_mp3 flac_) sticker (_webp_) video (_mp4_) voice (_ogg_) or document.
It's recommended to use __absolute path names__ for local files (_starting with `/`_), as relative path names are threated as __relative to UPLOADDIR__ `data-bot-bash/upload`!
For security reasons the following restrictions apply to local files:
- absolute path name must match the __shell regex__ `FILE_REGEX`
- relative path name is threated as relative to `UPLOADDIR` (_default: data-bot-bash/upload_)
- path must not start with `./` and not contain `../` - path must not start with `./` and not contain `../`
*usage:* send_file "${CHAT[ID]}" "file" "caption"
*example:* *example:*
```bash ```bash
# recommended: absolute path # send picture from web
send_file "${CHAT[ID]}" "https://dealz.rrr.de/assets/images/rbofd-1.gif" "My Bot" "photo"
send_file "${CHAT[ID]}" "https://images-na.ssl-images-amazon.com/images/I/81DQ0FpoSNL._AC_SL1500_.jpg"
# local file recommended: absolute path
send_file "${CHAT[ID]}" "/home/user/dog.jpg" "My Dog" send_file "${CHAT[ID]}" "/home/user/dog.jpg" "My Dog"
# relative to UPLOADDIR: data-bot-bash/upload/dog.jpg # relative to UPLOADDIR: data-bot-bash/upload/dog.jpg
@ -201,7 +214,7 @@ _keyboard_numpad
---- ----
##### send_button ##### send_button
*usage:* send_button "chat-id" "message" "text" "URL" *usage:* send_button "$CHAT[ID]" "message" "text" "URL"
*alias:* _button "text" "URL" *alias:* _button "text" "URL"
@ -210,6 +223,12 @@ _keyboard_numpad
send_button "${CHAT[ID]}" "MAKE MONEY FAST!!!" "Visit my Shop" "https://dealz.rrr.de" send_button "${CHAT[ID]}" "MAKE MONEY FAST!!!" "Visit my Shop" "https://dealz.rrr.de"
``` ```
##### send_sticker
`send_sticker` sends a sticker using a `file_id` to send a sticker that exists on the Telegram servers.
*usage:* send_sticker "$CHAT[ID]" "file_id"
##### send_inline_keyboard ##### send_inline_keyboard
Even its called keyboard, this function is different from send_keyboard. The main difference is that it's only possible to Even its called keyboard, this function is different from send_keyboard. The main difference is that it's only possible to
specify URL buttons, no Text Buttons and the Buttons must be an Array of Buttons as specified for specify URL buttons, no Text Buttons and the Buttons must be an Array of Buttons as specified for
@ -240,6 +259,7 @@ send_inline_keyboard "${CHAT[ID]}" "" '[{"text":"b 1", url"":"u 1"}, {"text":"b
Edit a message means replace the content of the message in place. The message stay on the same position in the chat and keep the same Edit a message means replace the content of the message in place. The message stay on the same position in the chat and keep the same
message id. message id.
If new message is the same than current message Telegram return error 400 with description "Bad Request: chat message is not modified"
There is no need to use the same format when replace a message, e.g. a message sent with `send_normal_message` can be replaced with There is no need to use the same format when replace a message, e.g. a message sent with `send_normal_message` can be replaced with
`edit_markdown_message` or `edit_html_message` and vice versa. `edit_markdown_message` or `edit_html_message` and vice versa.
@ -299,6 +319,67 @@ saved-id="${BOTSENT[ID]}"
edit_html_message "${CHAT[ID]}" "${saved-id}" "this is <b>html</b> text" edit_html_message "${CHAT[ID]}" "${saved-id}" "this is <b>html</b> text"
``` ```
##### edit_message_caption
`edit_message_caption` changes the caption of a message (photo, audio, video, document) in the given chat.
*usage:* edit_message_caption "${CHAT[ID]}" "MESSAGE-ID" "caption"
---
### Manage Group
To use the following functions the bot must have administrator status in the chat / group
##### set_chat_title
`set_chat_title` sets a new chat title. If new title is the same than current title Telegram return error 400
with description "Bad Request: chat title is not modified"
*usage:* set_chat_title "${CHAT[ID]}" "new chat title"
##### set_chat_description
`set_chat_description` sets a new description title. If new description is the same than current description Telegram return error 400
with description "Bad Request: chat description is not modified"
*usage:* set_chat_description "${CHAT[ID]}" "new chat description"
##### new_chat_invite
`new_chat_invite` generate a new invite link for a chat; any previously generated link is revoked.
Returns the new invite link as String on success.
*usage:* new_chat_invite "${CHAT[ID]}"
##### delete_chat_photo
*usage:* delete_chat_photo "${CHAT[ID]}"
##### pin_chat_message
# $1 chat, $2 message_id
`pin_chat_message` add a message to the list of pinned messages in a chat.
*usage:* pin_chat_message "${CHAT[ID]}" "message_id"
##### unpin_chat_message
`unpin_chat_message` remove a message from the list of pinned messages in a chat.
*usage:* unpin_chat_message "${CHAT[ID]}" "message_id"
##### unpinall_chat_message
`unpinall_chat_message` clear the list of pinned messages in a chat.
*usage:* unpinall_chat_message "${CHAT[ID]}"
##### delete_chat_stickers
`delete_chat_stickers` deletes a group sticker set from a supergroup.
*usage:* delete_chat_stickers "${CHAT[ID]}"
---- ----
@ -390,9 +471,10 @@ fi
*See also [Chat Member](https://core.telegram.org/bots/api/#chatmember)* *See also [Chat Member](https://core.telegram.org/bots/api/#chatmember)*
##### user_is_allowed ##### user_is_allowed
Bashbot supports User Access Control, see [Advanced Usage](3_advanced.md) `uers_is_allowed` checks if: user id botadmin, user is group admin or user is allowed to execute action..
Allowed actions are configured as User Access Control rules, see [Advanced Usage](3_advanced.md)
*usage:* user_is_allowed "${USER[ID]}" "what" "${CHAT[ID]}" *usage:* user_is_allowed "${USER[ID]}" "action" "${CHAT[ID]}"
*example:* *example:*
```bash ```bash
@ -1187,5 +1269,5 @@ The name of your bot is available as bash variable "$ME", there is no need to ca
#### [Prev Best Practice](5_practice.md) #### [Prev Best Practice](5_practice.md)
#### [Next Notes for Developers](7_develop.md) #### [Next Notes for Developers](7_develop.md)
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427

View File

@ -1,7 +1,7 @@
#### [Home](../README.md) #### [Home](../README.md)
## Notes for bashbot developers ## 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, modules and addons, not on develop your individual bot. Nevertheless the information provided here should help your bot development also. 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 developing your individual bot. Nevertheless the information provided here should also help you with your bot development.
If you want to provide fixes or new features [fork bashbot on github](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 github](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).
@ -11,21 +11,20 @@ If you want to get error messages (and more) start bashbot `./bashbot.sh startb
you can the change the level of verbosity of the debug argument: you can the change the level of verbosity of the debug argument:
``` ```
"debug" all output is redirected to "DEBUG.log", in addition every incoming message is logged in "MESSAGE.log" and "INLINE.log" "debug" all output is redirected to `DEBUG.log`, in addition every incoming 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" "xdebug" same as debug plus set bash option '-x' to log any executed command in `DEBUG.log`
use the command tail to watch your bot live, e.g. "tail -f DEBUG.log", to obtain more information place set -x; set +x in your code.
``` ```
``` Use the command `tail` to watch your bot live, e.g. `tail -f DEBUG.log`. To obtain more information place `set -x; ... set +x` around suspected code.
sometimes its useful to watch the bot live in the terminal:
Sometimes it's useful to watch the bot live in the terminal:
```
"debugx" debug 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 "xdebugx" same as debugx plus set bash option '-x' to show any executed command
``` ```
Logging of telegram update poll is disabled by default, also in `debug` mode. To enable it without using verbose `xdebug` mode Logging of Telegram update poll is disabled by default, also in `debug` mode. To enable it without using verbose `xdebug` mode
set `BASHBOT_UPDATELOG` to an empty value (not unset) `export BASHBOT_UPDATELOG=""` set `BASHBOT_UPDATELOG` to an empty value (not unset) `export BASHBOT_UPDATELOG=""`
### Modules and Addons ### Modules and Addons
@ -36,7 +35,7 @@ disable modules, e.g. by rename the respective module file to 'module.sh.off'.
Modules must use only functions provided by 'bashbot.sh' or the module itself and should not depend on other modules or addons. Modules must use only functions provided by 'bashbot.sh' or the module itself and should not depend on other modules or addons.
The only mandatory module is 'module/sendMessage.sh'. The only mandatory module is 'module/sendMessage.sh'.
If a not mandatory module is used in 'bashbot.sh' or 'commands.sh', the use of `_is_function` or If an optional module is used in 'bashbot.sh' or 'commands.sh', the use of `_is_function` or
`_execute_if_function` is mandatory to catch absence of the module. `_execute_if_function` is mandatory to catch absence of the module.
**Addons** resides in `addons/*.sh.dist` and are not enabled by default. To activate an addon rename it to end with '.sh', e.g. by **Addons** resides in `addons/*.sh.dist` and are not enabled by default. To activate an addon rename it to end with '.sh', e.g. by
@ -63,18 +62,17 @@ Note: For the same reason event function MUST return immediately! Time consuming
##### SEND RECEIVE events ##### SEND RECEIVE events
An RECEIVE event is executed when a Message is received, same iQuery / Message variables are available as in commands.sh A RECEIVE event is executed when a Message is received, same iQuery / Message variables are available as in commands.sh
* `BASHBOT_EVENT_INLINE` an inline query is received * `BASHBOT_EVENT_INLINE` an inline query is received
* `BASHBOT_EVENT_MESSAGE` any of the following message types is received
* BASHBOT_EVENT_MESSAGE` any of the following message types is received * `BASHBOT_EVENT_TEXT` a message containing text is received
* `BASHBOT_EVENT_TEXT` a message containing text is received * `BASHBOT_EVENT_CMD` a message containing a command is received (starts with /)
* `BASHBOT_EVENT_CMD` a message containing a command is received (starts with /) * `BASHBOT_EVENT_REPLYTO` a reply to a message is received
* `BASHBOT_EVENT_REPLYTO` a reply to a message is received * `BASHBOT_EVENT_FORWARD` a forwarded message is received
* `BASHBOT_EVENT_FORWARD` a forwarded message is received * `BASHBOT_EVENT_CONTACT` a contact is received
* `BASHBOT_EVENT_CONTACT` a contact is received * `BASHBOT_EVENT_LOCATION` a location or a venue is received
* `BASHBOT_EVENT_LOCATION` a location or a venue is received * `BASHBOT_EVENT_FILE` a file is received
* `BASHBOT_EVENT_FILE` a file is received
*usage*: BASHBOT_EVENT_xxx[ "unique-name" ]="callback" *usage*: BASHBOT_EVENT_xxx[ "unique-name" ]="callback"
@ -149,7 +147,7 @@ This means if you register an every 5 minutes callback first execution may < 5 M
* x execute every x minutes * x execute every x minutes
* -x execute once WITHIN the next x Minutes (next 10 Minutes since start "event") * -x execute once WITHIN the next x Minutes (next 10 Minutes since start "event")
Note: If you want exact "in x minutes" use "EVENT_TIMER plus x" as time: `-(EVENT_TIMER + x)` Note: If you want exact "in x minutes" use "EVENT_TIMER" as reference: `(EVENT_TIMER +x)`
*Example:* *Example:*
```bash ```bash
@ -168,8 +166,8 @@ BASHBOT_EVENT_TIMER["example_every5","5"]="example_every5min"
# execute once on the next 10 minutes since start "event" # execute once on the next 10 minutes since start "event"
BASHBOT_EVENT_TIMER["example_10min","-10"]="example_in10min" BASHBOT_EVENT_TIMER["example_10min","-10"]="example_in10min"
# once in exact 10 minutes # once in exact 10 minutes, note the -
BASHBOT_EVENT_TIMER["example_10min","$(( (EVENT_TIMER+10) * -1 ))"]="example_in10min" BASHBOT_EVENT_TIMER["example_10min","-$(( EVENT_TIMER+10 ))"]="example_in10min"
``` ```
@ -182,8 +180,8 @@ You don't need all these files after you're finished with your cool new bot.
Let's create a stripped down version: Let's create a stripped down version:
- delete all modules you do not need from `modules`, e.g. `modules/inline.sh` if you don't use inline queries - delete all modules you do not need from `modules`, e.g. `modules/inline.sh` if you don't use inline queries
- delete not needed standard commands and messages from `commands.sh` - delete unused standard commands and messages from `commands.sh`
- delete not needed commands and functions from `mycommands.sh` - delete unused commands and functions from `mycommands.sh`
- run `dev/make-standalone.sh` to create a a stripped down version of your bot - run `dev/make-standalone.sh` to create a a stripped down version of your bot
Now have a look at the directory `standalone`, here you find the files `bashbot.sh` and `commands.sh` containing everything to run your bot. Now have a look at the directory `standalone`, here you find the files `bashbot.sh` and `commands.sh` containing everything to run your bot.
@ -198,8 +196,8 @@ Now have a look at the directory `standalone`, here you find the files `bashbot.
5. give your (dev) fork a new version tag: `git tag v1.xx` 5. give your (dev) fork a new version tag: `git tag v1.xx`
6. setup github hooks by running `dev/install-hooks.sh` 6. setup github hooks by running `dev/install-hooks.sh`
Run `dev/make-distrubition.sh` to create installation archives and a test installation in `DIST/`. Run `dev/make-distribution.sh` to create installation archives and a test installation in `DIST/`.
To update the test installation, e.g. after git pull, local changes or switch master/develop, run `dev/make-distrubition.sh` again. To update the test installation, e.g. after git pull, local changes or switch master/develop, run `dev/make-distribution.sh` again.
Note for Debian: Debian Buster ships older versions of many utilities, pls try to install from [buster-backports](https://backports.debian.org/Instructions/) Note for Debian: Debian Buster ships older versions of many utilities, pls try to install from [buster-backports](https://backports.debian.org/Instructions/)
```bash ```bash
@ -210,7 +208,7 @@ sudo apt-get -t buster-backports install git shellcheck pandoc codespell curl
A typical bashbot develop loop looks as follow: A typical bashbot develop loop looks as follow:
1. start developing - *change, copy, edit bashbot files ...* 1. start developing - *change, copy, edit bashbot files ...*
2. after changing a bash sript: `shellcheck -x script.sh` 2. after changing a bash script: `shellcheck -x script.sh`
3. `dev/all-tests.sh` - *in case if errors back to 2.* 3. `dev/all-tests.sh` - *in case if errors back to 2.*
4. `dev/git-add.sh` - *check for changed files, update version string, run git add* 4. `dev/git-add.sh` - *check for changed files, update version string, run git add*
5. `git commit -m "COMMIT MESSAGE"; git push` 5. `git commit -m "COMMIT MESSAGE"; git push`
@ -254,6 +252,8 @@ data="$(cat file)" -> data="$(<"file")"
DIR="$(dirname $0) -> DIR="${0%/*}" DIR="$(dirname $0) -> DIR="${0%/*}"
date -> printf"%(%c)T\n" -1 # 100 times faster!
PROG="($basename $0)" -> PROG="${0##*/}* PROG="($basename $0)" -> PROG="${0##*/}*
ADDME="$ADDME something to add" -> ADDME+=" something to add"" ADDME="$ADDME something to add" -> ADDME+=" something to add""
@ -261,10 +261,38 @@ ADDME="$ADDME something to add" -> ADDME+=" something to add""
VAR="$(( 1 + 2 ))" -> (( var=1+2 )) VAR="$(( 1 + 2 ))" -> (( var=1+2 ))
INDEX="$(( ${INDEX} + 1 ))" -> (( INDEX++ )) INDEX="$(( ${INDEX} + 1 ))" -> (( INDEX++ ))
``` ```
For more examples see [Pure bash bible](https://github.com/dylanaraps/pure-bash-bible) For more examples see [Pure bash bible](https://github.com/dylanaraps/pure-bash-bible)
The special variable `$_` stores the expanded __last__ argument of the previous command.
This allows a nice optimisation in combination with the no-op command `:`, but be aware of `$_` pitfalls.
```bash
# $_ example: mkdir plus cd to it
mkdir "somedir-$$" && cd "$_" # somedir-1234 (process id)
# manipulate a variable multiple times without storing intermediate results
foo="1a23_b__x###"
...
: "${foo//[0-9]}" # a_b__x###
: "${_%%#*}" # a_b__x
bar="${_/__x/_c}" # a_b_c
# BE AWARE OF ...
# pitfall missing quotes: $_ is LAST arg
: ${SOMEVAR} # "String in var" $_ -> "var"
: $(<"file") # "Content of\n file" $_ -> "file"
# pitfall test command
[ -n "$MYVAR" ] && echo "$_" # outputs "]"
# pitfall command substitution: globbing and IFS is applied!
: "$(echo "a* is born")"# $_ -> a* is globbed even quoted!
: "$(echo "a b c")"# $_ -> "a b c"
: "$(<"file")" # "Content of\n file" $_ -> "Content of file"
```
#### Prepare a new version #### Prepare a new version
After some development it may time to create a new version for the users. a new version can be in sub version upgrade, e.g. for fixes and smaller additions or After some development it may time to create a new version for the users. a new version can be in sub version upgrade, e.g. for fixes and smaller additions or
a new release version for new features. To mark a new version use `git tag NEWVERSION` and run `dev/version.sh` to update all version strings. a new release version for new features. To mark a new version use `git tag NEWVERSION` and run `dev/version.sh` to update all version strings.
@ -291,15 +319,15 @@ To update version in all files run 'dev/version.sh' without parameter.
For a shell script running as a service it's important to be paranoid about quoting, globbing and other common problems. So it's a must to run shellchek on all shell scripts before you commit a change. this is automated by a git hook activated in Setup step 6. For a shell script running as a service it's important to be paranoid about quoting, globbing and other common problems. So it's a must to run shellchek on all shell scripts before you commit a change. this is automated by a git hook activated in Setup step 6.
To run shellcheck for a single script run `shellcheck -x script.sh`, to check all schripts run `dev/hooks/pre-commit.sh`. To run shellcheck for a single script run `shellcheck -x script.sh`, to check all scripts run `dev/hooks/pre-commit.sh`.
### bashbot test suite ### bashbot test suite
Starting with version 0.70 bashbot has a test suite. To start testsuite run `dev/all-tests.sh`. all-tests.sh will return 'SUCCESS' only if all tests pass. Starting with version 0.70 bashbot has a test suite. To start the test suite run `dev/all-tests.sh`. all-tests.sh will return 'SUCCESS' if ALL tests pass.
#### enabling / disabling tests #### enabling / disabling tests
All tests are placed in the directory `test`. To disable a test remove the execute flag from the '*-test.sh' script, to (re)enable a test make the script executable again. All tests are placed in the directory `test`. To disable a test remove the execute flag from the '*-test.sh' script, to (re)enable a test make the script executable again.
#### creating new tests #### creating new tests
@ -328,7 +356,7 @@ The file `ALL-tests.inc.sh` must be included from all tests and provide the test
ADMINFILE="botadmin" ADMINFILE="botadmin"
DATADIR="data-bot-bash" DATADIR="data-bot-bash"
# SUCCESS NOSUCCES -> echo "${SUCCESS}" or echo "${NOSUCCESS}" # SUCCESS NOSUCCESS -> echo "${SUCCESS}" or echo "${NOSUCCESS}"
SUCCESS=" OK" SUCCESS=" OK"
NOSUCCESS=" FAILED!" NOSUCCESS=" FAILED!"
@ -358,5 +386,5 @@ fi
#### [Prev Function Reference](6_reference.md) #### [Prev Function Reference](6_reference.md)
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427

22
doc/bashbot.ascii Normal file
View File

@ -0,0 +1,22 @@
..
****
****oooooo*****
*****ooooooooooooo*****
*****oooooooooooooooooooooo****
****oooooooooooooooooooooooooooooooo**
*.*oooooooooooooooooooooooooooooooooooo**
*.ooooooooooooooooooooooooooooooooo**....
*.oooooooooooooooooooooooooooo**.........
*.oooooooooooooooooooooooo**.............
*.ooooooooooooooooooo**.................. ____ _ _ _
*.ooooooooooooooooo*.......,............. | _ \ | | | | | |
*.ooooooooooooooooo*.....,***,........... | |_) | __ _ ___ | |__ | |__ ___ | |_
*.ooooooooooooooooo*....o*............... | _ < / _` |/ __|| '_ \ | '_ \ / _ \ | __|
*.ooooooooooooooooo*....*o***,........... | |_) || (_| |\__ \| | | || |_) || (_) || |_
*.*oooooooooooooooo*........o*.....oo.... |____/ \__,_||___/|_| |_||_.__/ \___/ \__|
****ooooooooooooo*....`***....oo.....*
*****oooooooo*......*..oo.....**
******ooo*.............*
***o*........**
**...**

View File

@ -56,6 +56,6 @@ convert existing bots.
**jsonDB-keybords** contains a stripped down real world example from my bot showing the usage of jsonDB to store and retrieve values **jsonDB-keybords** contains a stripped down real world example from my bot showing the usage of jsonDB to store and retrieve values
plus use of keyboards in private chats. It's an extended version of mycommands.sh.dist. Messages and help are in german. plus use of keyboards in private chats. It's an extended version of mycommands.sh.dist. Messages and help are in german.
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427

View File

@ -6,12 +6,12 @@ export res
# your additional bashbot commands ... # your additional bashbot commands ...
mycommands() { mycommands() {
case "$MESSAGE" in case "${MESSAGE}" in
'/run_'*) '/run_'*)
myback="run_${MESSAGE#*_}" myback="run_${MESSAGE#*_}"
if [ -x "./${myback}.sh" ]; then if [ -x "./${myback}.sh" ]; then
checkback "${myback}" checkback "${myback}"
if [ "$res" -gt 0 ] ; then if [ "${res}" -gt 0 ] ; then
send_normal_message "${CHAT[ID]}" "Start ${myback}, use /kill${myback} to stop it." send_normal_message "${CHAT[ID]}" "Start ${myback}, use /kill${myback} to stop it."
background "./${myback}.sh" "${myback}" background "./${myback}.sh" "${myback}"
else else
@ -23,7 +23,7 @@ mycommands() {
myback="run_${MESSAGE#*_}" myback="run_${MESSAGE#*_}"
if [ -x "./${myback}.sh" ]; then if [ -x "./${myback}.sh" ]; then
checkback "${myback}" checkback "${myback}"
if [ "$res" -eq 0 ] ; then if [ "${res}" -eq 0 ] ; then
killback "${myback}" killback "${myback}"
send_normal_message "${CHAT[ID]}" "Stopping ${myback}, use /run_${myback} to start again." send_normal_message "${CHAT[ID]}" "Stopping ${myback}, use /run_${myback} to start again."
else else
@ -56,7 +56,7 @@ watch_dir_loop() {
echo "$(date): new file: ${newfile}" >>"$0.log" echo "$(date): new file: ${newfile}" >>"$0.log"
# note: loop callback must a function in the calling script! # note: loop callback must a function in the calling script!
if _is_function loop_callback ; then if _is_function loop_callback ; then
loop_callback "$1/$newfile" loop_callback "$1/${newfile}"
else else
echo "ERROR: loop_callback not found!" >&2 echo "ERROR: loop_callback not found!" >&2
exit 1 exit 1
@ -94,8 +94,8 @@ output_file() {
sed <<< "${1}" ' sed <<< "${1}" '
s/ *mynewlinestartshere */\n/ s/ *mynewlinestartshere */\n/
s/ my[a-z]\{3,15}\(start\|ends\)here.*//g s/ my[a-z]\{3,15}\(start\|ends\)here.*//g
' >"$publish$$" ' >"${publish}$$"
cat "$publish" >>"$publish$$" cat "${publish}" >>"${publish}$$"
mv "${publish}$$" "${publish}" mv "${publish}$$" "${publish}"
} # >>"$0.log" 2>&1 } # >>"$0.log" 2>&1

View File

@ -4,7 +4,7 @@
# #
# This file is public domain in the USA and all free countries. # This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
###### ######
# parameters # parameters
@ -28,8 +28,8 @@ cat >/dev/null &
source "./mycommands.sh" source "./mycommands.sh"
# check if $1 is a number # check if $1 is a number
re='^[0-9]+$' regex='^[0-9]+$'
if [[ $1 =~ $re ]] ; then if [[ $1 =~ ${regex} ]] ; then
SLEEP="$1" SLEEP="$1"
else else
SLEEP=100 # time between time notifications SLEEP=100 # time between time notifications
@ -39,11 +39,11 @@ NEWLINE=$'\n'
# output disk usage every $1 seconds # output disk usage every $1 seconds
WAIT=0 WAIT=0
while sleep $WAIT while sleep "${WAIT}"
do do
output_telegram "Current Disk usage ${NEWLINE} $(df -h / /tmp /usr /var /home)" output_telegram "Current Disk usage ${NEWLINE} $(df -h / /tmp /usr /var /home)"
# only for testing, delete echo line for production ... # only for testing, delete echo line for production ...
echo "Current Disk usage ${NEWLINE} $(df -h / /tmp /usr /var /home)" echo "Current Disk usage ${NEWLINE} $(df -h / /tmp /usr /var /home)"
WAIT="$SLEEP" WAIT="${SLEEP}"
done done

View File

@ -2,7 +2,7 @@
# file: run_filename # file: run_filename
# background job to display content of all new files in WATCHDIR # background job to display content of all new files in WATCHDIR
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
###### ######
# parameters # parameters
@ -40,4 +40,4 @@ loop_callback() {
output_telegram "Contents of ${1}: ${NEWLINE} $(cat "${1}")" output_telegram "Contents of ${1}: ${NEWLINE} $(cat "${1}")"
} }
watch_dir_loop "$WATCHDIR" watch_dir_loop "${WATCHDIR}"

View File

@ -2,7 +2,7 @@
# file: run_filename # file: run_filename
# background job to display all new files in WATCHDIR # background job to display all new files in WATCHDIR
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
###### ######
# parameters # parameters
@ -38,5 +38,5 @@ loop_callback() {
echo "New file ${1} created in ${WATCHDIR}!" echo "New file ${1} created in ${WATCHDIR}!"
} }
watch_dir_loop "$WATCHDIR" watch_dir_loop "${WATCHDIR}"

View File

@ -4,7 +4,7 @@
# #
# This file is public domain in the USA and all free countries. # This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
###### ######
# parameters # parameters
@ -25,15 +25,15 @@ unset IFS
cat >/dev/null & cat >/dev/null &
# check if $1 is a number # check if $1 is a number
re='^[0-9]+$' regex='^[0-9]+$'
if [[ $1 =~ $re ]] ; then if [[ "$1" =~ ${regex} ]] ; then
SLEEP="$1" SLEEP="$1"
else else
SLEEP=10 # time between time notifications SLEEP=10 # time between time notifications
fi fi
# output current time every $1 seconds # output current time every $1 seconds
while sleep $SLEEP while sleep "${SLEEP}"
do do
date "+* It's %k:%M:%S o' clock ..." date "+* It's %k:%M:%S o' clock ..."
done done

View File

@ -6,7 +6,7 @@
# This file is public domain in the USA and all free countries. # This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
# shellcheck disable=SC1117 # shellcheck disable=SC1117
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
# adjust your language setting here # adjust your language setting here
# https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment # https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment

View File

@ -2,14 +2,14 @@
# file. multibot.sh # file. multibot.sh
# description: run multiple telegram bots from one installation # description: run multiple telegram bots from one installation
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
if [ "${2}" = "" ] || [ "${2}" = "-h" ]; then if [ "$2" = "" ] || [ "$2" = "-h" ]; then
echo "Usage: $0 botname command" echo "Usage: $0 botname command"
exit 1 exit 1
fi fi
BOT="${1}" BOT="$1"
[ "${#BOT}" -lt 5 ] && echo "Botname must have a minimum length of 5 characters" && exit 1 [ "${#BOT}" -lt 5 ] && echo "Botname must have a minimum length of 5 characters" && exit 1
# where should the bots live? # where should the bots live?

View File

@ -7,7 +7,7 @@
# This file is public domain in the USA and all free countries. # This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
SHELL=/bin/sh SHELL=/bin/sh

View File

@ -11,7 +11,7 @@
# This file is public domain in the USA and all free countries. # This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
######################################################################## ########################################################################
###### ######

View File

@ -10,7 +10,7 @@
# AUTHOR: KayM (), kay@rrr.de # AUTHOR: KayM (), kay@rrr.de
# DATE: 19.12.2020 19:03 # DATE: 19.12.2020 19:03
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
#=============================================================================== #===============================================================================
# shellcheck disable=SC2154 # shellcheck disable=SC2154
# shellcheck disable=SC2034 # shellcheck disable=SC2034
@ -326,8 +326,8 @@ fi
MYKEYF="$2" MYKEYF="$2"
MINLEN="4" MINLEN="4"
# check len of keys # check len of keys
for MYKEY in ${MYFIND}; do [ "${#MYKEY}" -lt ${MINLEN} ] && break; done for MYKEY in ${MYFIND}; do [ "${#MYKEY}" -lt "${MINLEN}" ] && break; done
if [ "${#MYKEY}" -lt ${MINLEN} ]; then if [ "${#MYKEY}" -lt "${MINLEN}" ]; then
send_markdownv2_message "${CHAT[ID]}" "*Ein Suchbegriff ist kürzer als ${MINLEN} Zeichen!*" send_markdownv2_message "${CHAT[ID]}" "*Ein Suchbegriff ist kürzer als ${MINLEN} Zeichen!*"
else else
MYFIND="$(create_pattern "${MYFIND}")" MYFIND="$(create_pattern "${MYFIND}")"

View File

@ -13,7 +13,7 @@
# This file is public domain in the USA and all free countries. # This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
######################################################################## ########################################################################
###### ######
@ -47,6 +47,6 @@ printf "Output time every %s seconds ...\n" "${SLEEP}"
while true while true
do do
date "+* It's %k:%M:%S o'clock ..." date "+* It's %k:%M:%S o'clock ..."
sleep $SLEEP sleep "${SLEEP}"
done done

View File

@ -10,7 +10,7 @@
# This file is public domain in the USA and all free countries. # This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
######################################################################## ########################################################################
###### ######
@ -39,7 +39,7 @@ else
fi fi
# question with Keyboard, repeating until correct answer given # question with Keyboard, repeating until correct answer given
until [ "$SUCCESS" = "y" ] ;do until [ "${SUCCESS}" = "y" ] ;do
printf 'Do you like Music? mykeyboardstartshere "Yass!" , "No"\n' printf 'Do you like Music? mykeyboardstartshere "Yass!" , "No"\n'
read -r answer <"${INPUT}" read -r answer <"${INPUT}"
case ${answer,,} in case ${answer,,} in

View File

@ -1,7 +1,7 @@
# file: botacl # file: botacl
# a user not listed here, will return false from 'user_is_allowed' # a user not listed here, will return false from 'user_is_allowed'
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
# Format: # Format:
# user:resource:chat # user:resource:chat

View File

@ -5,7 +5,7 @@
# to show how you can customize bashbot by only editing mycommands.sh # to show how you can customize bashbot by only editing mycommands.sh
# NOTE: this is not tested, simply copied from original source and reworked! # NOTE: this is not tested, simply copied from original source and reworked!
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
# #
# shellcheck disable=SC2154 # shellcheck disable=SC2154
# shellcheck disable=SC2034 # shellcheck disable=SC2034
@ -38,7 +38,7 @@ mycommands() {
local msg="" local msg=""
if user_is_botadmin "${USER[ID]}" || user_is_allowed "${USER[ID]}" "systemstatus"; then if user_is_botadmin "${USER[ID]}" || user_is_allowed "${USER[ID]}" "systemstatus"; then
case "$CMD" in case "${CMD}" in
'/md'*) msg="$(cat /proc/mdstat)";; '/md'*) msg="$(cat /proc/mdstat)";;
'/smb'*) msg="$(smbstatus)" ;; '/smb'*) msg="$(smbstatus)" ;;
'/se'*) msg="$(sensors | sed -r 's/\s|\)+//g' | sed -r 's/\(high=|\(min=/\//' | sed -r 's/\,crit=|\,max=/\//')";; '/se'*) msg="$(sensors | sed -r 's/\s|\)+//g' | sed -r 's/\(high=|\(min=/\//' | sed -r 's/\,crit=|\,max=/\//')";;
@ -51,14 +51,14 @@ mycommands() {
'/smart'*) '/smart'*)
[ "${CMD[1]}" == "" ] && msg="example \`/smart sda\`" && return [ "${CMD[1]}" == "" ] && msg="example \`/smart sda\`" && return
drive="$(echo "${CMD[1]}" | cut -c 1-3)" drive="$(echo "${CMD[1]}" | cut -c 1-3)"
echo "smartctl -a /dev/$drive" echo "smartctl -a /dev/${drive}"
msg="$(smartctl -a "/dev/$drive")" msg="$(smartctl -a "/dev/${drive}")"
;; ;;
'/df') msg="$(df -h | sed -r 's/^/\n/' | sed -r 's/\s+/\n/g')";; '/df') msg="$(df -h | sed -r 's/^/\n/' | sed -r 's/\s+/\n/g')";;
esac esac
if [ "$msg" != "" ]; then if [ "${msg}" != "" ]; then
send_normal_message "${CHAT[ID]}" "$msg" send_normal_message "${CHAT[ID]}" "${msg}"
fi fi
else else
send_normal_message "${USER[ID]}" "Sorry, you are not allowed to use this bot!" send_normal_message "${USER[ID]}" "Sorry, you are not allowed to use this bot!"

View File

@ -5,7 +5,7 @@
# This file is public domain in the USA and all free countries. # This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
# #
# will be automatically sourced from bashbot # will be automatically sourced from bashbot
@ -23,36 +23,36 @@ _is_creator() {
user_is_creator "${CHAT[ID]}" "${USER[ID]}" user_is_creator "${CHAT[ID]}" "${USER[ID]}"
} }
_is_allowed() { _is_allowed() {
user_is_allowed "${USER[ID]}" "${1}" "${CHAT[ID]}" user_is_allowed "${USER[ID]}" "$1" "${CHAT[ID]}"
} }
_leave() { _leave() {
leave_chat "${CHAT[ID]}" leave_chat "${CHAT[ID]}"
} }
_kick_user() { _kick_user() {
kick_chat_member "${CHAT[ID]}" "${1}" kick_chat_member "${CHAT[ID]}" "$1"
} }
_unban_user() { _unban_user() {
unban_chat_member "${CHAT[ID]}" "${1}" unban_chat_member "${CHAT[ID]}" "$1"
} }
# easy sending of messages of messages # easy sending of messages of messages
_message() { _message() {
send_normal_message "${CHAT[ID]}" "${1}" send_normal_message "${CHAT[ID]}" "$1"
} }
_normal_message() { _normal_message() {
send_normal_message "${CHAT[ID]}" "${1}" send_normal_message "${CHAT[ID]}" "$1"
} }
_html_message() { _html_message() {
send_html_message "${CHAT[ID]}" "${1}" send_html_message "${CHAT[ID]}" "$1"
} }
_markdown_message() { _markdown_message() {
send_markdown_message "${CHAT[ID]}" "${1}" send_markdown_message "${CHAT[ID]}" "$1"
} }
# easy handling of keyboards # easy handling of keyboards
_inline_button() { _inline_button() {
send_inline_button "${CHAT[ID]}" "" "${1}" "${2}" send_inline_button "${CHAT[ID]}" "" "$1" "$2"
} }
_inline_keyboard() { _inline_keyboard() {
send_inline_keyboard "${CHAT[ID]}" "" "${1}" send_inline_keyboard "${CHAT[ID]}" "" "$1"
} }
_keyboard_numpad() { _keyboard_numpad() {
send_keyboard "${CHAT[ID]}" "" '["1","2","3"],["4","5","6"],["7","8","9"],["-","0","."]' "yes" send_keyboard "${CHAT[ID]}" "" '["1","2","3"],["4","5","6"],["7","8","9"],["-","0","."]' "yes"

View File

@ -5,20 +5,19 @@
# This file is public domain in the USA and all free countries. # This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
# will be automatically sourced from bashbot # will be automatically sourced from bashbot
# source once magic, function named like file # source once magic, function named like file
eval "$(basename "${BASH_SOURCE[0]}")(){ :; }" eval "$(basename "${BASH_SOURCE[0]}")(){ :; }"
INLINE_QUERY=$URL'/answerInlineQuery'
answer_inline_query() { answer_inline_query() {
answer_inline_multi "${1}" "$(shift; inline_query_compose "$RANDOM" "$@")" answer_inline_multi "$1" "$(shift; inline_query_compose "${RANDOM}" "$@")"
} }
answer_inline_multi() { answer_inline_multi() {
sendJson "" '"inline_query_id": '"${1}"', "results": ['"${2}"']' "${INLINE_QUERY}" sendJson "" '"inline_query_id": '"$1"', "results": ['"$2"']' "${URL}/answerInlineQuery"
} }
# $1 unique ID for answer # $1 unique ID for answer
@ -27,76 +26,76 @@ answer_inline_multi() {
# followed by the optional arguments: https://core.telegram.org/bots/api#inlinequeryresult # followed by the optional arguments: https://core.telegram.org/bots/api#inlinequeryresult
inline_query_compose(){ inline_query_compose(){
local JSON="{}" local JSON="{}"
local ID="${1}" local ID="$1"
local fours last local fours last
# title2Json title caption description markup inlinekeyboard # title2Json title caption description markup inlinekeyboard
case "${2}" in case "$2" in
# user provided media # user provided media
"article"|"message") # article ID title message (markup description) "article"|"message") # article ID title message (markup description)
JSON='{"type":"article","id":"'$ID'","input_message_content": {"message_text":"'$4'"} '$(title2Json "$3" "" "$5" "$6" "$7")'}' JSON='{"type":"article","id":"'${ID}'","input_message_content": {"message_text":"'$4'"} '$(title2Json "$3" "" "$5" "$6" "$7")'}'
;; ;;
"photo") # photo ID photoURL (thumbURL title description caption) "photo") # photo ID photoURL (thumbURL title description caption)
[ -z "$4" ] && tumb="$3" [ -z "$4" ] && tumb="$3"
JSON='{"type":"photo","id":"'$ID'","photo_url":"'$3'","thumb_url":"'$4${tumb}'"'$(title2Json "$5" "$7" "$6" "$7" "$8")'}' JSON='{"type":"photo","id":"'${ID}'","photo_url":"'$3'","thumb_url":"'$4${tumb}'"'$(title2Json "$5" "$7" "$6" "$7" "$8")'}'
;; ;;
"gif") # gif ID photoURL (thumbURL title caption) "gif") # gif ID photoURL (thumbURL title caption)
[ -z "$4" ] && tumb="$3" [ -z "$4" ] && tumb="$3"
JSON='{"type":"gif","id":"'$ID'","gif_url":"'$3'", "thumb_url":"'$4${tumb}'"'$(title2Json "$5" "$6" "$7" "$8" "$9")'}' JSON='{"type":"gif","id":"'${ID}'","gif_url":"'$3'", "thumb_url":"'$4${tumb}'"'$(title2Json "$5" "$6" "$7" "$8" "$9")'}'
;; ;;
"mpeg4_gif") # mpeg4_gif ID mpegURL (thumbURL title caption) "mpeg4_gif") # mpeg4_gif ID mpegURL (thumbURL title caption)
[ -n "$4" ] && tumb='","thumb_url":"'$4'"' [ -n "$4" ] && tumb='","thumb_url":"'$4'"'
JSON='{"type":"mpeg4_gif","id":"'$ID'","mpeg4_url":"'$3'"'${tumb}$(title2Json "$5" "$6" "" "$7" "$8")'}' JSON='{"type":"mpeg4_gif","id":"'${ID}'","mpeg4_url":"'$3'"'${tumb}$(title2Json "$5" "$6" "" "$7" "$8")'}'
;; ;;
"video") # video ID videoURL mime thumbURL title (caption) "video") # video ID videoURL mime thumbURL title (caption)
JSON='{"type":"video","id":"'$ID'","video_url":"'$3'","mime_type":"'$4'","thumb_url":"'$5'"'$(title2Json "$6" "$7" "$8" "$9" "${10}")'}' JSON='{"type":"video","id":"'${ID}'","video_url":"'$3'","mime_type":"'$4'","thumb_url":"'$5'"'$(title2Json "$6" "$7" "$8" "$9" "${10}")'}'
;; ;;
"audio") # audio ID audioURL title (caption) "audio") # audio ID audioURL title (caption)
JSON='{"type":"audio","id":"'$ID'","audio_url":"'$3'"'$(title2Json "$4" "$5" "" "" "$6")'}' JSON='{"type":"audio","id":"'${ID}'","audio_url":"'$3'"'$(title2Json "$4" "$5" "" "" "$6")'}'
;; ;;
"voice") # voice ID voiceURL title (caption) "voice") # voice ID voiceURL title (caption)
JSON='{"type":"voice","id":"'$ID'","voice_url":"'$3'"'$(title2Json "$4" "$5" "" "" "$6")'}' JSON='{"type":"voice","id":"'${ID}'","voice_url":"'$3'"'$(title2Json "$4" "$5" "" "" "$6")'}'
;; ;;
"document") # document ID title documentURL mimetype (caption description) "document") # document ID title documentURL mimetype (caption description)
JSON='{"type":"document","id":"'$ID'","document_url":"'$4'","mime_type":"'$5'"'$(title2Json "$3" "$6" "$7" "$8" "$9")'}' JSON='{"type":"document","id":"'${ID}'","document_url":"'$4'","mime_type":"'$5'"'$(title2Json "$3" "$6" "$7" "$8" "$9")'}'
;; ;;
"location") # location ID lat long title "location") # location ID lat long title
JSON='{"type":"location","id":"'$ID'","latitude":"'$3'","longitude":"'$4'","title":"'$5'"}' JSON='{"type":"location","id":"'${ID}'","latitude":"'$3'","longitude":"'$4'","title":"'$5'"}'
;; ;;
"venue") # venue ID lat long title (address forsquare) "venue") # venue ID lat long title (address forsquare)
[ -z "$6" ] && addr="$5" [ -z "$6" ] && addr="$5"
[ -n "$7" ] && fours=',"foursquare_id":"'$7'"' [ -n "$7" ] && fours=',"foursquare_id":"'$7'"'
JSON='{"type":"venue","id":"'$ID'","latitude":"'$3'","longitude":"'$4'","title":"'$5'","address":"'$6${addr}'"'${fours}'}' JSON='{"type":"venue","id":"'${ID}'","latitude":"'$3'","longitude":"'$4'","title":"'$5'","address":"'$6${addr}'"'${fours}'}'
;; ;;
"contact") # contact ID phone first (last thumb) "contact") # contact ID phone first (last thumb)
[ -n "$5" ] && last=',"last_name":"'$5'"' [ -n "$5" ] && last=',"last_name":"'$5'"'
[ -n "$6" ] && tumb='","thumb_url":"'$6'"' [ -n "$6" ] && tumb='","thumb_url":"'$6'"'
JSON='{"type":"contact","id":"'$ID'","phone_number":"'$3'","first_name":"'$4'"'${last}'"}' JSON='{"type":"contact","id":"'${ID}'","phone_number":"'$3'","first_name":"'$4'"'${last}'"}'
;; ;;
# title2Json title caption description markup inlinekeyboard # title2Json title caption description markup inlinekeyboard
# Cached media stored in Telegram server # Cached media stored in Telegram server
"cached_photo") # photo ID file (title description caption) "cached_photo") # photo ID file (title description caption)
JSON='{"type":"photo","id":"'$ID'","photo_file_id":"'$3'"'$(title2Json "$4" "$6" "$5" "$7" "$8")'}' JSON='{"type":"photo","id":"'${ID}'","photo_file_id":"'$3'"'$(title2Json "$4" "$6" "$5" "$7" "$8")'}'
;; ;;
"cached_gif") # gif ID file (title caption) "cached_gif") # gif ID file (title caption)
JSON='{"type":"gif","id":"'$ID'","gif_file_id":"'$3'"'$(title2Json "$4" "$5" "$6" "$7" "$8" )'}' JSON='{"type":"gif","id":"'${ID}'","gif_file_id":"'$3'"'$(title2Json "$4" "$5" "$6" "$7" "$8" )'}'
;; ;;
"cached_mpeg4_gif") # mpeg ID file (title caption) "cached_mpeg4_gif") # mpeg ID file (title caption)
JSON='{"type":"mpeg4_gif","id":"'$ID'","mpeg4_file_id":"'$3'"'$(title2Json "$4" "$5" "" "$6" "$7")'}' JSON='{"type":"mpeg4_gif","id":"'${ID}'","mpeg4_file_id":"'$3'"'$(title2Json "$4" "$5" "" "$6" "$7")'}'
;; ;;
"cached_sticker") # sticker ID file "cached_sticker") # sticker ID file
JSON='{"type":"sticker","id":"'$ID'","sticker_file_id":"'$3'"}' JSON='{"type":"sticker","id":"'${ID}'","sticker_file_id":"'$3'"}'
;; ;;
"cached_document") # document ID title file (description caption) "cached_document") # document ID title file (description caption)
JSON='{"type":"document","id":"'$ID'","document_file_id":"'$4'"'$(title2Json "$3" "$6" "$5" "$6" "$7")'}' JSON='{"type":"document","id":"'${ID}'","document_file_id":"'$4'"'$(title2Json "$3" "$6" "$5" "$6" "$7")'}'
;; ;;
"cached_video") # video ID file title (description caption) "cached_video") # video ID file title (description caption)
JSON='{"type":"video","id":"'$ID'","video_file_id":"'$3'"'$(title2Json "$4" "$6" "$5" "$7" "$8")'}' JSON='{"type":"video","id":"'${ID}'","video_file_id":"'$3'"'$(title2Json "$4" "$6" "$5" "$7" "$8")'}'
;; ;;
"cached_voice") # voice ID file title (caption) "cached_voice") # voice ID file title (caption)
JSON='{"type":"voice","id":"'$ID'","voice_file_id":"'$3'"'$(title2Json "$4" "$5" "" "" "$6")'}' JSON='{"type":"voice","id":"'${ID}'","voice_file_id":"'$3'"'$(title2Json "$4" "$5" "" "" "$6")'}'
;; ;;
"cached_audio") # audio ID file title (caption) "cached_audio") # audio ID file title (caption)
JSON='{"type":"audio","id":"'$ID'","audio_file_id":"'$3'"'$(title2Json "$4" "$5" "" "" "$6")'}' JSON='{"type":"audio","id":"'${ID}'","audio_file_id":"'$3'"'$(title2Json "$4" "$5" "" "" "$6")'}'
;; ;;
esac esac

View File

@ -6,7 +6,7 @@
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
# #
# shellcheck disable=SC1117,SC2059 # shellcheck disable=SC1117,SC2059
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
# will be automatically sourced from bashbot # will be automatically sourced from bashbot
@ -48,9 +48,9 @@ start_back() {
} }
restart_back() { restart_back() {
local fifo; fifo="${DATADIR:-.}/$(procname "$1" "back-$3-")" local fifo; fifo="${DATADIR:-.}/$(procname "$1" "back-$3-")"
printf "%s: Start background job CHAT=%s JOB=%s CMD=%s\n" "$(date)" "${1}" "${fifo##*/}" "${2##*/} ${4} ${5}" >>"${UPDATELOG}" log_message "Start background job CHAT=$1 JOB=${fifo##*/} CMD=${2##*/} $4 $5"
check_back "$1" "$3" && kill_proc "$1" "back-$3-" check_back "$1" "$3" && kill_proc "$1" "back-$3-"
nohup bash -c "{ $2 \"$4\" \"$5\" \"${fifo}\" | \"${SCRIPT}\" outproc \"${1}\" \"${fifo}\"; }" &>>"${fifo}.log" & nohup bash -c "{ $2 \"$4\" \"$5\" \"${fifo}\" | \"${SCRIPT}\" outproc \"$1\" \"${fifo}\"; }" &>>"${fifo}.log" &
sleep 0.5 # give bg job some time to init sleep 0.5 # give bg job some time to init
} }
@ -62,10 +62,10 @@ start_proc() {
[ -z "$2" ] && return [ -z "$2" ] && return
[ -x "${2%% *}" ] || return 1 [ -x "${2%% *}" ] || return 1
local fifo; fifo="${DATADIR:-.}/$(procname "$1")" local fifo; fifo="${DATADIR:-.}/$(procname "$1")"
printf "%s: Start interacitve script CHAT=%s JOB=%s CMD=%s\n" "$(date)" "${1}" "${fifo##*/}" "${2} ${3} ${4}" >>"${UPDATELOG}" log_message "Start interactive script CHAT=$1 JOB=${fifo##*/} CMD=$2 $3 $4"
check_proc "$1" && kill_proc "$1" check_proc "$1" && kill_proc "$1"
mkfifo "${fifo}" mkfifo "${fifo}"
nohup bash -c "{ $2 \"$4\" \"$5\" \"$fifo\" | \"${SCRIPT}\" outproc \"${1}\" \"${fifo}\" nohup bash -c "{ $2 \"$4\" \"$5\" \"${fifo}\" | \"${SCRIPT}\" outproc \"$1\" \"${fifo}\"
rm \"${fifo}\"; [ -s \"${fifo}.log\" ] || rm -f \"${fifo}.log\"; }" &>>"${fifo}.log" & rm \"${fifo}\"; [ -s \"${fifo}.log\" ] || rm -f \"${fifo}.log\"; }" &>>"${fifo}.log" &
} }
@ -99,7 +99,7 @@ kill_proc() {
fifo="$(procname "$1" "$2")" fifo="$(procname "$1" "$2")"
prid="$(proclist "${fifo}")" prid="$(proclist "${fifo}")"
fifo="${DATADIR:-.}/${fifo}" fifo="${DATADIR:-.}/${fifo}"
printf "%s: Stop interacitve / background CHAT=%s JOB=%s\n" "$(date)" "${1}" "${fifo##*/}" >>"${UPDATELOG}" log_message "Stop interactive / background CHAT=$1 JOB=${fifo##*/}"
# shellcheck disable=SC2086 # shellcheck disable=SC2086
[ -n "${prid}" ] && kill ${prid} [ -n "${prid}" ] && kill ${prid}
[ -s "${fifo}.log" ] || rm -f "${fifo}.log" [ -s "${fifo}.log" ] || rm -f "${fifo}.log"
@ -127,7 +127,7 @@ job_control() {
local BOT ADM content proc CHAT job fifo killall="" local BOT ADM content proc CHAT job fifo killall=""
BOT="$(getConfigKey "botname")" BOT="$(getConfigKey "botname")"
ADM="$(getConfigKey "botadmin")" ADM="$(getConfigKey "botadmin")"
debug_checks "Enter job_control" "${1}" debug_checks "Enter job_control" "$1"
for FILE in "${DATADIR:-.}/"*-back.cmd; do for FILE in "${DATADIR:-.}/"*-back.cmd; do
[ "${FILE}" = "${DATADIR:-.}/*-back.cmd" ] && printf "${RED}No background processes.${NN}" && break [ "${FILE}" = "${DATADIR:-.}/*-back.cmd" ] && printf "${RED}No background processes.${NN}" && break
content="$(< "${FILE}")" content="$(< "${FILE}")"
@ -136,7 +136,7 @@ job_control() {
proc="${job#*:}" proc="${job#*:}"
job="${job%:*}" job="${job%:*}"
fifo="$(procname "${CHAT}" "${job}")" fifo="$(procname "${CHAT}" "${job}")"
debug_checks "Execute job_control" "${1}" "${FILE##*/}" debug_checks "Execute job_control" "$1" "${FILE##*/}"
case "$1" in case "$1" in
"resumeb"*|"backgr"*) "resumeb"*|"backgr"*)
printf "Restart Job: %s %s\n" "${proc}" " ${fifo##*/}" printf "Restart Job: %s %s\n" "${proc}" " ${fifo##*/}"
@ -163,7 +163,7 @@ job_control() {
# send message only onnfirst job # send message only onnfirst job
ADM="" ADM=""
done done
debug_checks "end job_control" "${1}" debug_checks "end job_control" "$1"
# kill all requestet. kill ALL background jobs, even not listed in data-bot-bash # kill all requestet. kill ALL background jobs, even not listed in data-bot-bash
[ "${killall}" = "y" ] && killallproc "back-" [ "${killall}" = "y" ] && killallproc "back-"
} }

View File

@ -5,36 +5,78 @@
# This file is public domain in the USA and all free countries. # This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
# will be automatically sourced from bashbot # will be automatically sourced from bashbot
# source once magic, function named like file # source once magic, function named like file
eval "$(basename "${BASH_SOURCE[0]}")(){ :; }" eval "$(basename "${BASH_SOURCE[0]}")(){ :; }"
LEAVE_URL=$URL'/leaveChat'
KICK_URL=$URL'/kickChatMember' # manage chat functions -------
UNBAN_URL=$URL'/unbanChatMember' # $1 chat
GETMEMBER_URL=$URL'/getChatMember' new_chat_invite() {
sendJson "$1" "" "${URL}/exportChatInviteLink"
[ "${BOTSENT[OK]}" = "true" ] && printf "%s\n" "${BOTSENT[RESULT]}"
}
# $1 chat, $2 title
set_chat_title() {
sendJson "$1" '"title": "'"$2"'"' "${URL}/setChatTitle"
}
# $1 chat, $2 title
set_chat_description() {
sendJson "$1" '"description": "'"$2"'"' "${URL}/setChatDescription"
}
# $1 chat
delete_chat_photo() {
sendJson "$1" "" "${URL}/deleteChatPhoto"
}
# $1 chat, $2 message_id
pin_chat_message() {
sendJson "$1" '"message_id": "'"$2"'"' "${URL}/pinChatMessage"
}
# $1 chat, $2 message_id
unpin_chat_message() {
sendJson "$1" '"message_id": "'"$2"'"' "${URL}/unpinChatMessage"
}
# $1 chat
unpinall_chat_message() {
sendJson "$1" "" "${URL}/unpinAllChatMessages"
}
# $1 chat
delete_chat_stickers() {
sendJson "$1" "" "${URL}/deleteChatStickerSet"
}
# manage chat member functions -------
kick_chat_member() {
sendJson "$1" 'user_id: '"$2"'' "${URL}/kickChatMember"
}
unban_chat_member() {
sendJson "$1" 'user_id: '"$2"'' "${URL}/unbanChatMember"
}
leave_chat() {
sendJson "$1" "" "${URL}/leaveChat"
}
# bashbot specific functions ---------
# usage: status="$(get_chat_member_status "chat" "user")" # usage: status="$(get_chat_member_status "chat" "user")"
# $1 chat # $2 user # $1 chat # $2 user
get_chat_member_status() { get_chat_member_status() {
sendJson "$1" '"user_id":'"$2"'' "$GETMEMBER_URL" sendJson "$1" '"user_id":'"$2"'' "${URL}/getChatMember"
# shellcheck disable=SC2154 # shellcheck disable=SC2154
JsonGetString '"result","status"' <<< "$res" JsonGetString '"result","status"' <<< "${res}"
}
kick_chat_member() {
sendJson "$1" 'user_id: '"$2"'' "$KICK_URL"
}
unban_chat_member() {
sendJson "$1" 'user_id: '"$2"'' "$UNBAN_URL"
}
leave_chat() {
sendJson "$1" "" "$LEAVE_URL"
} }
user_is_creator() { user_is_creator() {
@ -62,8 +104,8 @@ user_is_admin() {
user_is_botadmin() { user_is_botadmin() {
[ -z "$1" ] && return 1 [ -z "$1" ] && return 1
local admin; admin="$(getConfigKey "botadmin")"; [ -z "${admin}" ] && return 1 local admin; admin="$(getConfigKey "botadmin")"; [ -z "${admin}" ] && return 1
[[ "${admin}" == "${1}" || "${admin}" == "${2}" ]] && return 0 [[ "${admin}" == "$1" || "${admin}" == "$2" ]] && return 0
#[[ "${admin}" = "@*" ]] && [[ "${admin}" = "${2}" ]] && return 0 #[[ "${admin}" = "@*" ]] && [[ "${admin}" = "$2" ]] && return 0
if [ "${admin}" = "?" ]; then setConfigKey "botadmin" "${1:-?}"; return 0; fi if [ "${admin}" = "?" ]; then setConfigKey "botadmin" "${1:-?}"; return 0; fi
return 1 return 1
} }
@ -71,17 +113,18 @@ user_is_botadmin() {
# $1 user # $2 key # $3 chat # $1 user # $2 key # $3 chat
user_is_allowed() { user_is_allowed() {
[ -z "$1" ] && return 1 [ -z "$1" ] && return 1
user_is_admin "$1" && return 0
# user can do everything # user can do everything
grep -F -xq "$1:*:*" <"${BOTACL}" && return 0 grep -F -xq "$1:*:*" "${BOTACL}" && return 0
[ -z "$2" ] && return 1 [ -z "$2" ] && return 1
# user is allowed todo one action in every chat # user is allowed todo one action in every chat
grep -F -xq "$1:$2:*" <"${BOTACL}" && return 0 grep -F -xq "$1:$2:*" "${BOTACL}" && return 0
# all users are allowed to do one action in every chat # all users are allowed to do one action in every chat
grep -F -xq "ALL:$2:*" <"${BOTACL}" && return 0 grep -F -xq "ALL:$2:*" "${BOTACL}" && return 0
[ -z "$3" ] && return 1 [ -z "$3" ] && return 1
# user is allowed to do one action in one chat # user is allowed to do one action in one chat
grep -F -xq "$1:$2:$3" <"${BOTACL}" && return 0 grep -F -xq "$1:$2:$3" "${BOTACL}" && return 0
# all users are allowed to do one action in one chat # all users are allowed to do one action in one chat
grep -F -xq "ALL:$2:$3" <"${BOTACL}" && return 0 grep -F -xq "ALL:$2:$3" "${BOTACL}" && return 0
return 1 return 1
} }

View File

@ -5,7 +5,7 @@
# This file is public domain in the USA and all free countries. # This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
# #
# source from commands.sh to use jsonDB functions # source from commands.sh to use jsonDB functions
# #
@ -27,6 +27,28 @@ eval "$(basename "${BASH_SOURCE[0]}")(){ :; }"
# lockfile filename.flock is persistent and will be testet with flock for active lock (file open) # lockfile filename.flock is persistent and will be testet with flock for active lock (file open)
export JSSH_LOCKNAME=".flock" export JSSH_LOCKNAME=".flock"
# in UTF-8 äöü etc. are part of [:alnum:] and ranges (e.g. a-z), but we want ASCII a-z ranges!
# for more information see doc/4_expert.md#Character_classes
azazaz='abcdefghijklmnopqrstuvwxyz' # a-z :lower:
AZAZAZ='ABCDEFGHIJKLMNOPQRSTUVWXYZ' # A-Z :upper:
o9o9o9='0123456789' # 0-9 :digit:
azAZaz="${azazaz}${AZAZAZ}" # a-zA-Z :alpha:
azAZo9="${azAZaz}${o9o9o9}" # a-zA-z0-9 :alnum:
# characters allowed for key in key/value pairs
JSSH_KEYOK="[-${azAZo9},._]"
# read string from stdin and and strip invalid characters
# $1 - invalid charcaters are replaced with first character
# or deleted if $1 is empty
jssh_stripKey() { # tr: we must escape first - in [-a-z...]
if [[ "$1" =~ ^${JSSH_KEYOK} ]]; then # tr needs [\-...
tr -c "${JSSH_KEYOK/\[-/[\\-}\r\n" "${1:0:1}"
else
tr -dc "${JSSH_KEYOK/\[-/[\\-}\r\n"
fi
}
# use flock if command exist # use flock if command exist
if [ "$(LC_ALL=C type -t "flock")" = "file" ]; then if [ "$(LC_ALL=C type -t "flock")" = "file" ]; then
@ -63,8 +85,8 @@ if [ "$(LC_ALL=C type -t "flock")" = "file" ]; then
# complex slow, warpper async # complex slow, warpper async
jssh_updateDB() { jssh_updateDB() {
# for atomic update we can't use read/writeDB # for atomic update we can't use read/writeDB
[ -z "${2}" ] && return 1 [ -z "$2" ] && return 1
local DB="${2}.jssh" # check in async local DB="$2.jssh" # check in async
[ ! -f "${DB}" ] && return 2 [ ! -f "${DB}" ] && return 2
{ flock -e -w 10 200; jssh_updateDB_async "$@"; } 200>"${DB}${JSSH_LOCKNAME}" { flock -e -w 10 200; jssh_updateDB_async "$@"; } 200>"${DB}${JSSH_LOCKNAME}"
} }
@ -76,7 +98,7 @@ if [ "$(LC_ALL=C type -t "flock")" = "file" ]; then
alias jssh_insertDB=jssh_insertKeyDB # backward compatibility alias jssh_insertDB=jssh_insertKeyDB # backward compatibility
# renamed to be more consistent # renamed to be more consistent
jssh_insertKeyDB() { jssh_insertKeyDB() {
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3 [[ "$1" =~ ^${JSSH_KEYOK}+$ ]] || return 3
local DB; DB="$(jssh_checkDB "$3")" local DB; DB="$(jssh_checkDB "$3")"
[ -z "${DB}" ] && return 1 [ -z "${DB}" ] && return 1
[ ! -f "${DB}" ] && return 2 [ ! -f "${DB}" ] && return 2
@ -93,9 +115,9 @@ if [ "$(LC_ALL=C type -t "flock")" = "file" ]; then
# $2 filename (must exist!), must be relative to BASHBOT_ETC, and not contain '..' # $2 filename (must exist!), must be relative to BASHBOT_ETC, and not contain '..'
# medium complex slow, wrapper async # medium complex slow, wrapper async
jssh_deleteKeyDB() { jssh_deleteKeyDB() {
[ -z "${2}" ] && return 1 [ -z "$2" ] && return 1
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3 [[ "$1" =~ ^${JSSH_KEYOK}+$ ]] || return 3
local DB="${2}.jssh" local DB="$2.jssh"
# start atomic delete here, exclusive max wait 10s # start atomic delete here, exclusive max wait 10s
{ flock -e -w 10 200; jssh_deleteKeyDB_async "$@"; } 200>"${DB}${JSSH_LOCKNAME}" { flock -e -w 10 200; jssh_deleteKeyDB_async "$@"; } 200>"${DB}${JSSH_LOCKNAME}"
} }
@ -105,12 +127,12 @@ if [ "$(LC_ALL=C type -t "flock")" = "file" ]; then
# $2 filename (must exist!), must be relative to BASHBOT_ETC, and not contain '..' # $2 filename (must exist!), must be relative to BASHBOT_ETC, and not contain '..'
alias jssh_getDB=jssh_getKeyDB alias jssh_getDB=jssh_getKeyDB
jssh_getKeyDB() { jssh_getKeyDB() {
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3 [[ "$1" =~ ^${JSSH_KEYOK}+$ ]] || return 3
local DB; DB="$(jssh_checkDB "$2")" local DB; DB="$(jssh_checkDB "$2")"
[ -z "${DB}" ] && return 1 [ -z "${DB}" ] && return 1
# start atomic delete here, exclusive max wait 1s # start atomic delete here, exclusive max wait 1s
{ flock -s -w 1 200 { flock -s -w 1 200
[ -r "${DB}" ] && sed -n 's/\["'"$1"'"\]\t*"\(.*\)"/\1/p' <"${DB}" | tail -n 1 [ -r "${DB}" ] && sed -n 's/\["'"$1"'"\]\t*"\(.*\)"/\1/p' "${DB}" | tail -n 1
} 200>"${DB}${JSSH_LOCKNAME}" } 200>"${DB}${JSSH_LOCKNAME}"
} }
@ -122,9 +144,9 @@ if [ "$(LC_ALL=C type -t "flock")" = "file" ]; then
# side effect: if $3 is not given, we add to end of file to be as fast as possible # side effect: if $3 is not given, we add to end of file to be as fast as possible
# complex, wrapper to async # complex, wrapper to async
jssh_countKeyDB() { jssh_countKeyDB() {
[ -z "${2}" ] && return 1 [ -z "$2" ] && return 1
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3 [[ "$1" =~ ^${JSSH_KEYOK}+$ ]] || return 3
local DB="${2}.jssh" local DB="$2.jssh"
# start atomic delete here, exclusive max wait 5 # start atomic delete here, exclusive max wait 5
{ flock -e -w 5 200; jssh_countKeyDB_async "$@"; } 200>"${DB}${JSSH_LOCKNAME}" { flock -e -w 5 200; jssh_countKeyDB_async "$@"; } 200>"${DB}${JSSH_LOCKNAME}"
} }
@ -135,12 +157,12 @@ if [ "$(LC_ALL=C type -t "flock")" = "file" ]; then
# $3 filename (must exist!), must be relative to BASHBOT_ETC, and not contain '..' # $3 filename (must exist!), must be relative to BASHBOT_ETC, and not contain '..'
#no own locking, so async is the same as updatekeyDB #no own locking, so async is the same as updatekeyDB
jssh_updateKeyDB() { jssh_updateKeyDB() {
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3 [[ "$1" =~ ^${JSSH_KEYOK}+$ ]] || return 3
[ -z "${3}" ] && return 1 [ -z "$3" ] && return 1
declare -A updARR declare -A updARR
# shellcheck disable=SC2034 # shellcheck disable=SC2034
updARR["$1"]="$2" updARR["$1"]="$2"
jssh_updateDB "updARR" "${3}" || return 3 jssh_updateDB "updARR" "$3" || return 3
} }
# $1 filename (must exist!), must be relative to BASHBOT_ETC, and not contain '..' # $1 filename (must exist!), must be relative to BASHBOT_ETC, and not contain '..'
@ -156,11 +178,11 @@ if [ "$(LC_ALL=C type -t "flock")" = "file" ]; then
# $3 id used to identify caller # $3 id used to identify caller
# medium complex, wrapper async # medium complex, wrapper async
jssh_updateArray() { jssh_updateArray() {
[ -z "${2}" ] && return 1 [ -z "$2" ] && return 1
local DB="${2}.jssh" # name check in async local DB="$2.jssh" # name check in async
[ ! -f "${DB}" ] && return 2 [ ! -f "${DB}" ] && return 2
declare -n ARRAY="$1" declare -n ARRAY="$1"
[[ -z "${ARRAY[*]}" || "${DB}" -nt "${DB}.last${3}" ]] && touch "${DB}.last${3}" && jssh_readDB "${1}" "${2}" [[ -z "${ARRAY[*]}" || "${DB}" -nt "${DB}.last$3" ]] && touch "${DB}.last$3" && jssh_readDB "$1" "$2"
} }
else else
@ -206,9 +228,9 @@ jssh_checkDB(){
[ -z "$1" ] && return 1 [ -z "$1" ] && return 1
[[ "$1" = *'../.'* ]] && return 2 [[ "$1" = *'../.'* ]] && return 2
if [[ "$1" == "${BASHBOT_VAR:-.}"* ]] || [[ "$1" == "${BASHBOT_DATA:-.}"* ]]; then if [[ "$1" == "${BASHBOT_VAR:-.}"* ]] || [[ "$1" == "${BASHBOT_DATA:-.}"* ]]; then
DB="${1}.jssh" DB="$1.jssh"
else else
DB="${BASHBOT_VAR:-.}/${1}.jssh" DB="${BASHBOT_VAR:-.}/$1.jssh"
fi fi
[ "${DB}" != ".jssh" ] && printf '%s' "${DB}" [ "${DB}" != ".jssh" ] && printf '%s' "${DB}"
} }
@ -232,7 +254,7 @@ jssh_writeDB_async() {
} }
jssh_updateDB_async() { jssh_updateDB_async() {
[ -z "${2}" ] && return 1 [ -z "$2" ] && return 1
declare -n ARRAY="$1" declare -n ARRAY="$1"
[ -z "${ARRAY[*]}" ] && return 1 [ -z "${ARRAY[*]}" ] && return 1
declare -A oldARR declare -A oldARR
@ -253,7 +275,7 @@ jssh_updateDB_async() {
jssh_insertDB_async() { jssh_insertKeyDB "$@"; } jssh_insertDB_async() { jssh_insertKeyDB "$@"; }
jssh_insertKeyDB_async() { jssh_insertKeyDB_async() {
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3 [[ "$1" =~ ^${JSSH_KEYOK}+$ ]] || return 3
local DB; DB="$(jssh_checkDB "$3")" local DB; DB="$(jssh_checkDB "$3")"
[ -z "${DB}" ] && return 1 [ -z "${DB}" ] && return 1
[ ! -f "${DB}" ] && return 2 [ ! -f "${DB}" ] && return 2
@ -263,7 +285,7 @@ jssh_insertKeyDB_async() {
} }
jssh_deleteKeyDB_async() { jssh_deleteKeyDB_async() {
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3 [[ "$1" =~ ^${JSSH_KEYOK}+$ ]] || return 3
local DB; DB="$(jssh_checkDB "$2")" local DB; DB="$(jssh_checkDB "$2")"
[ -z "${DB}" ] && return 1 [ -z "${DB}" ] && return 1
declare -A oldARR declare -A oldARR
@ -273,14 +295,14 @@ jssh_deleteKeyDB_async() {
} }
jssh_getKeyDB_async() { jssh_getKeyDB_async() {
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3 [[ "$1" =~ ^${JSSH_KEYOK}+$ ]] || return 3
local DB; DB="$(jssh_checkDB "$2")" local DB; DB="$(jssh_checkDB "$2")"
[ -z "${DB}" ] && return 1 [ -z "${DB}" ] && return 1
[ -r "${DB}" ] && sed -n 's/\["'"$1"'"\]\t*"\(.*\)"/\1/p' <"${DB}" | tail -n 1 [ -r "${DB}" ] && sed -n 's/\["'"$1"'"\]\t*"\(.*\)"/\1/p' "${DB}" | tail -n 1
} }
jssh_countKeyDB_async() { jssh_countKeyDB_async() {
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3 [[ "$1" =~ ^${JSSH_KEYOK}+$ ]] || return 3
local VAL DB; DB="$(jssh_checkDB "$2")" local VAL DB; DB="$(jssh_checkDB "$2")"
[ -z "${DB}" ] && return 1 [ -z "${DB}" ] && return 1
# start atomic delete here, exclusive max wait 5 # start atomic delete here, exclusive max wait 5
@ -291,7 +313,7 @@ jssh_countKeyDB_async() {
Array2Json "oldARR" >"${DB}" Array2Json "oldARR" >"${DB}"
elif [ -r "${DB}" ]; then elif [ -r "${DB}" ]; then
# it's append, but last one counts, its a simple DB ... # it's append, but last one counts, its a simple DB ...
VAL="$(sed -n 's/\["'"$1"'"\]\t*"\(.*\)"/\1/p' <"${DB}" | tail -n 1)" VAL="$(sed -n 's/\["'"$1"'"\]\t*"\(.*\)"/\1/p' "${DB}" | tail -n 1)"
printf '["%s"]\t"%s"\n' "${1//,/\",\"}" "$((++VAL))" >>"${DB}" printf '["%s"]\t"%s"\n' "${1//,/\",\"}" "$((++VAL))" >>"${DB}"
fi fi
} }
@ -302,12 +324,12 @@ jssh_countKeyDB_async() {
# $3 filename (must exist!), must be relative to BASHBOT_ETC, and not contain '..' # $3 filename (must exist!), must be relative to BASHBOT_ETC, and not contain '..'
#no own locking, so async is the same as updatekeyDB #no own locking, so async is the same as updatekeyDB
jssh_updateKeyDB_async() { jssh_updateKeyDB_async() {
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3 [[ "$1" =~ ^${JSSH_KEYOK}+$ ]] || return 3
[ -z "${3}" ] && return 1 [ -z "$3" ] && return 1
declare -A updARR declare -A updARR
# shellcheck disable=SC2034 # shellcheck disable=SC2034
updARR["$1"]="$2" updARR["$1"]="$2"
jssh_updateDB_async "updARR" "${3}" || return 3 jssh_updateDB_async "updARR" "$3" || return 3
} }
jssh_clearDB_async() { jssh_clearDB_async() {
@ -321,7 +343,7 @@ function jssh_updateArray_async() {
[ -z "${DB}" ] && return 1 [ -z "${DB}" ] && return 1
[ ! -f "${DB}" ] && return 2 [ ! -f "${DB}" ] && return 2
declare -n ARRAY="$1" declare -n ARRAY="$1"
[[ -z "${ARRAY[*]}" || "${DB}" -nt "${DB}.last${3}" ]] && touch "${DB}.last${3}" && jssh_readDB_async "${1}" "${2}" [[ -z "${ARRAY[*]}" || "${DB}" -nt "${DB}.last$3" ]] && touch "${DB}.last$3" && jssh_readDB_async "$1" "$2"
} }
############## ##############
@ -340,13 +362,13 @@ Json2Array() {
# $1 ARRAY name, must be declared with "declare -A ARRAY" before calling # $1 ARRAY name, must be declared with "declare -A ARRAY" before calling
Array2Json() { Array2Json() {
[ -z "$1" ] && return 1 [ -z "$1" ] && return 1
local key val local key
declare -n ARRAY="$1" declare -n ARRAY="$1"
for key in "${!ARRAY[@]}" for key in "${!ARRAY[@]}"
do do
# in case val contains newline convert to \n [[ "${key}" =~ ^${JSSH_KEYOK}+$ ]] || continue
val="${ARRAY[${key}]//$'\n'/\\n}" # in case value contains newline convert to \n
printf '["%s"]\t"%s"\n' "${key//,/\",\"}" "${val//\"/\\\"}" : "${ARRAY[${key}]//$'\n'/\\n}"
printf '["%s"]\t"%s"\n' "${key//,/\",\"}" "${_//\"/\\\"}"
done done
} }

View File

@ -6,7 +6,7 @@
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
# #
# shellcheck disable=SC1117 # shellcheck disable=SC1117
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
# will be automatically sourced from bashbot # will be automatically sourced from bashbot
@ -15,19 +15,8 @@ eval "$(basename "${BASH_SOURCE[0]}")(){ :; }"
# source from commands.sh to use the sendMessage functions # source from commands.sh to use the sendMessage functions
MSG_URL=$URL'/sendMessage' MSG_URL=${URL}'/sendMessage'
EDIT_URL=$URL'/editMessageText' EDIT_URL=${URL}'/editMessageText'
PHO_URL=$URL'/sendPhoto'
AUDIO_URL=$URL'/sendAudio'
DOCUMENT_URL=$URL'/sendDocument'
STICKER_URL=$URL'/sendSticker'
VIDEO_URL=$URL'/sendVideo'
VOICE_URL=$URL'/sendVoice'
LOCATION_URL=$URL'/sendLocation'
VENUE_URL=$URL'/sendVenue'
ACTION_URL=$URL'/sendChatAction'
FORWARD_URL=$URL'/forwardMessage'
ALBUM_URL=$URL'/sendMediaGroup'
# #
# send/edit message variants ------------------ # send/edit message variants ------------------
@ -35,17 +24,17 @@ ALBUM_URL=$URL'/sendMediaGroup'
# $1 CHAT $2 message # $1 CHAT $2 message
send_normal_message() { send_normal_message() {
local len text; text="$(JsonEscape "${2}")" local len text; text="$(JsonEscape "$2")"
text="${text//$'\n'/\\n}" text="${text//$'\n'/\\n}"
until [ -z "${text}" ]; do until [ -z "${text}" ]; do
if [ "${#text}" -le 4096 ]; then if [ "${#text}" -le 4096 ]; then
sendJson "${1}" '"text":"'"${text}"'"' "${MSG_URL}" sendJson "$1" '"text":"'"${text}"'"' "${MSG_URL}"
break break
else else
len=4095 len=4095
[ "${text:4095:2}" != "\n" ] &&\ [ "${text:4095:2}" != "\n" ] &&\
len="${text:0:4096}" && len="${len%\\n*}" && len="${#len}" len="${text:0:4096}" && len="${len%\\n*}" && len="${#len}"
sendJson "${1}" '"text":"'"${text:0:${len}}"'"' "${MSG_URL}" sendJson "$1" '"text":"'"${text:0:${len}}"'"' "${MSG_URL}"
text="${text:$((len+2))}" text="${text:$((len+2))}"
fi fi
done done
@ -53,48 +42,53 @@ send_normal_message() {
# $1 CHAT $2 message # $1 CHAT $2 message
send_markdown_message() { send_markdown_message() {
_format_message_url "${1}" "${2}" ',"parse_mode":"markdown"' "${MSG_URL}" _format_message_url "$1" "$2" ',"parse_mode":"markdown"' "${MSG_URL}"
} }
# $1 CHAT $2 message # $1 CHAT $2 message
send_markdownv2_message() { send_markdownv2_message() {
_markdownv2_message_url "${1}" "${2}" ',"parse_mode":"markdownv2"' "${MSG_URL}" _markdownv2_message_url "$1" "$2" ',"parse_mode":"markdownv2"' "${MSG_URL}"
} }
# $1 CHAT $2 message # $1 CHAT $2 message
send_html_message() { send_html_message() {
_format_message_url "${1}" "${2}" ',"parse_mode":"html"' "${MSG_URL}" _format_message_url "$1" "$2" ',"parse_mode":"html"' "${MSG_URL}"
} }
# $1 CHAT $2 msg-id $3 message # $1 CHAT $2 msg-id $3 message
edit_normal_message() { edit_normal_message() {
_format_message_url "${1}" "${3}" ',"message_id":'"${2}"'' "${EDIT_URL}" _format_message_url "$1" "$3" ',"message_id":'"$2"'' "${EDIT_URL}"
} }
# $1 CHAT $2 msg-id $3 message # $1 CHAT $2 msg-id $3 message
edit_markdown_message() { edit_markdown_message() {
_format_message_url "${1}" "${3}" ',"message_id":'"${2}"',"parse_mode":"markdown"' "${EDIT_URL}" _format_message_url "$1" "$3" ',"message_id":'"$2"',"parse_mode":"markdown"' "${EDIT_URL}"
} }
# $1 CHAT $2 msg-id $3 message # $1 CHAT $2 msg-id $3 message
edit_markdownv2_message() { edit_markdownv2_message() {
_markdownv2_message_url "${1}" "${3}" ',"message_id":'"${2}"',"parse_mode":"markdownv2"' "${EDIT_URL}" _markdownv2_message_url "$1" "$3" ',"message_id":'"$2"',"parse_mode":"markdownv2"' "${EDIT_URL}"
} }
# $1 CHAT $2 msg-id $3 message # $1 CHAT $2 msg-id $3 message
edit_html_message() { edit_html_message() {
_format_message_url "${1}" "${3}" ',"message_id":'"${2}"',"parse_mode":"html"' "${EDIT_URL}" _format_message_url "$1" "$3" ',"message_id":'"$2"',"parse_mode":"html"' "${EDIT_URL}"
}
# $1 chat $2 mesage_id, $3 caption
edit_message_caption() {
sendJson "$1" '"message_id":'"$2"',"caption":"'"$3"'"' "${URL}/editMessageCaption"
} }
# internal function, send/edit formatted message with parse_mode and URL # internal function, send/edit formatted message with parse_mode and URL
# $1 CHAT $2 message $3 action $4 URL # $1 CHAT $2 message $3 action $4 URL
_format_message_url(){ _format_message_url(){
local text; text="$(JsonEscape "${2}")" local text; text="$(JsonEscape "$2")"
text="${text//$'\n'/\\n}" text="${text//$'\n'/\\n}"
[ "${#text}" -ge 4096 ] && log_error "Warning: html/markdown message longer than 4096 characters, message is rejected if formatting crosses 4096 border." [ "${#text}" -ge 4096 ] && log_error "Warning: html/markdown message longer than 4096 characters, message is rejected if formatting crosses 4096 border."
until [ -z "${text}" ]; do until [ -z "${text}" ]; do
sendJson "${1}" '"text":"'"${text:0:4096}"'"'"${3}"'' "${4}" sendJson "$1" '"text":"'"${text:0:4096}"'"'"$3"'' "$4"
text="${text:4096}" text="${text:4096}"
done done
} }
@ -102,13 +96,13 @@ _format_message_url(){
# internal function, send/edit markdownv2 message with URL # internal function, send/edit markdownv2 message with URL
# $1 CHAT $2 message $3 action $4 URL # $1 CHAT $2 message $3 action $4 URL
_markdownv2_message_url() { _markdownv2_message_url() {
local text; text="$(JsonEscape "${2}")" local text; text="$(JsonEscape "$2")"
text="${text//$'\n'/\\n}" text="${text//$'\n'/\\n}"
[ "${#text}" -ge 4096 ] && log_error "Warning: markdownv2 message longer than 4096 characters, message is rejected if formatting crosses 4096 border." [ "${#text}" -ge 4096 ] && log_error "Warning: markdownv2 message longer than 4096 characters, message is rejected if formatting crosses 4096 border."
# markdown v2 needs additional double escaping! # markdown v2 needs additional double escaping!
text="$(sed -E -e 's|([_|~`>+=#{}()!.-])|\\\1|g' <<< "$text")" text="$(sed -E -e 's|([_|~`>+=#{}()!.-])|\\\1|g' <<< "${text}")"
until [ -z "${text}" ]; do until [ -z "${text}" ]; do
sendJson "${1}" '"text":"'"${text:0:4096}"'"'"${3}"'' "${4}" sendJson "$1" '"text":"'"${text:0:4096}"'"'"$3"'' "$4"
text="${text:4096}" text="${text:4096}"
done done
} }
@ -121,61 +115,67 @@ _markdownv2_message_url() {
send_keyboard() { send_keyboard() {
if [[ "$3" != *'['* ]]; then old_send_keyboard "${@}"; return; fi if [[ "$3" != *'['* ]]; then old_send_keyboard "${@}"; return; fi
local text='"text":"'"Keyboard:"'"' local text='"text":"'"Keyboard:"'"'
if [ -n "${2}" ]; then if [ -n "$2" ]; then
text="$(JsonEscape "${2}")" text="$(JsonEscape "$2")"
text='"text":"'"${text//$'\n'/\\n}"'"' text='"text":"'"${text//$'\n'/\\n}"'"'
fi fi
local one_time=', "one_time_keyboard":true' && [ -n "$4" ] && one_time="" local one_time=', "one_time_keyboard":true' && [ -n "$4" ] && one_time=""
sendJson "${1}" "${text}"', "reply_markup": {"keyboard": [ '"${3}"' ] '"${one_time}"'}' "$MSG_URL" sendJson "$1" "${text}"', "reply_markup": {"keyboard": [ '"$3"' ] '"${one_time}"'}' "${MSG_URL}"
# '"text":"$2", "reply_markup": {"keyboard": [ ${3} ], "one_time_keyboard": true}' # '"text":"$2", "reply_markup": {"keyboard": [ $3 ], "one_time_keyboard": true}'
} }
# $1 CHAT $2 message $3 remove # $1 CHAT $2 message $3 remove
remove_keyboard() { remove_keyboard() {
local text='"text":"'"remove custom keyboard ..."'"' local text='"text":"'"remove custom keyboard ..."'"'
if [ -n "${2}" ]; then if [ -n "$2" ]; then
text="$(JsonEscape "${2}")" text="$(JsonEscape "$2")"
text='"text":"'"${text//$'\n'/\\n}"'"' text='"text":"'"${text//$'\n'/\\n}"'"'
fi fi
sendJson "${1}" "${text}"', "reply_markup": {"remove_keyboard":true}' "$MSG_URL" sendJson "$1" "${text}"', "reply_markup": {"remove_keyboard":true}' "${MSG_URL}"
# delete message if no message or $3 not empty # delete message if no message or $3 not empty
[[ -z "${2}" || -n "${3}" ]] && delete_message "${1}" "${BOTSENT[ID]}" "nolog" [[ -z "$2" || -n "$3" ]] && delete_message "$1" "${BOTSENT[ID]}" "nolog"
#JSON='"text":"$2", "reply_markup": {"remove_keyboard":true}' #JSON='"text":"$2", "reply_markup": {"remove_keyboard":true}'
} }
# $1 CHAT $2 message $3 keyboard # $1 CHAT $2 message $3 keyboard
send_inline_keyboard() { send_inline_keyboard() {
local text; text='"text":"'$(JsonEscape "${2}")'"'; [ -z "${2}" ] && text='"text":"'"Keyboard:"'"' local text; text='"text":"'$(JsonEscape "$2")'"'; [ -z "$2" ] && text='"text":"'"Keyboard:"'"'
sendJson "${1}" "${text}"', "reply_markup": {"inline_keyboard": [ '"${3}"' ]}' "$MSG_URL" sendJson "$1" "${text}"', "reply_markup": {"inline_keyboard": [ '"$3"' ]}' "${MSG_URL}"
# JSON='"text":"$2", "reply_markup": {"inline_keyboard": [ $3->[{"text":"text", "url":"url"}]<- ]}' # JSON='"text":"$2", "reply_markup": {"inline_keyboard": [ $3->[{"text":"text", "url":"url"}]<- ]}'
} }
# $1 CHAT $2 message $3 button text $4 URL # $1 CHAT $2 message $3 button text $4 URL
send_button() { send_button() {
send_inline_keyboard "${1}" "${2}" '[ {"text":"'"$(JsonEscape "${3}")"'", "url":"'"${4}"'"}]' send_inline_keyboard "$1" "$2" '[ {"text":"'"$(JsonEscape "$3")"'", "url":"'"$4"'"}]'
}
# $1 chat, $2 file_id on telegram server
send_sticker() {
sendJson "$1" '"sticker": "'"$2"'"' "${URL}/sendSticker"
} }
if [ -z "${BASHBOT_WGET}" ] && _exists curl ; then # only curl can send files ...
# there are no checks if URL or ID exists if detect_curl ; then
# $1 chat $3 ... $n URL or ID # there are no checks if URL or ID exists
# $1 chat $3 ... $n URL or ID
send_album(){ send_album(){
[ -z "${1}" ] && return 1 [ -z "$1" ] && return 1
[ -z "${3}" ] && return 2 # minimum 2 files [ -z "$3" ] && return 2 # minimum 2 files
local CHAT JSON IMAGE; CHAT="${1}"; shift local CHAT JSON IMAGE; CHAT="$1"; shift
for IMAGE in "$@" for IMAGE in "$@"
do do
[ -n "${JSON}" ] && JSON+="," [ -n "${JSON}" ] && JSON+=","
JSON+='{"type":"photo","media":"'${IMAGE}'"}' JSON+='{"type":"photo","media":"'${IMAGE}'"}'
done done
# shellcheck disable=SC2086 # shellcheck disable=SC2086
res="$("${BASHBOT_CURL}" -s -k ${BASHBOT_CURL_ARGS} "${ALBUM_URL}" -F "chat_id=${CHAT}"\ res="$("${BASHBOT_CURL}" -s -k ${BASHBOT_CURL_ARGS} "${URL}/sendMediaGroup" -F "chat_id=${CHAT}"\
-F "media=[${JSON}]" | "${JSONSHFILE}" -s -b -n 2>/dev/null )" -F "media=[${JSON}]" | "${JSONSHFILE}" -s -b -n 2>/dev/null )"
sendJsonResult "${res}" "send_album (curl)" "${CHAT}" "$@" sendJsonResult "${res}" "send_album (curl)" "${CHAT}" "$@"
[[ -z "${SOURCE}" && -n "${BASHBOT_EVENT_SEND[*]}" ]] && event_send "album" "$@" & [[ -z "${SOURCE}" && -n "${BASHBOT_EVENT_SEND[*]}" ]] && event_send "album" "$@" &
} }
else else
send_album(){ send_album(){
log_error "Sorry, wget Album upload not yet implemented" log_error "Sorry, wget Album upload not implemented"
BOTSENT[OK]="false" BOTSENT[OK]="false"
[[ -z "${SOURCE}" && -n "${BASHBOT_EVENT_SEND[*]}" ]] && event_send "album" "$@" & [[ -z "${SOURCE}" && -n "${BASHBOT_EVENT_SEND[*]}" ]] && event_send "album" "$@" &
} }
@ -183,88 +183,98 @@ fi
UPLOADDIR="${BASHBOT_UPLOAD:-${DATADIR}/upload}" UPLOADDIR="${BASHBOT_UPLOAD:-${DATADIR}/upload}"
# for now this can only send local files with curl! # supports local file, URL and file_id
# extend to allow send files by URL or telegram ID # $1 chat, $2 file https::// file_id:// , $3 caption, $4 extension (optional)
send_file() { send_file(){
local err local url what num stat err media capt file="$2" ext="$4"
upload_file "${@}"; err="$?" capt="$(JsonEscape "$3")"
# fake Telegram response to provide error if [[ "${file}" =~ ^https*:// ]]; then
if [ "${err}" != "0" ]; then media="URL"
BOTSENT=() elif [[ "${file}" == file_id://* ]]; then
BOTSENT[OK]="false" media="ID"
case "$err" in file="${file#file_id://}"
1) BOTSENT[ERROR]="Path to file $2 contains to much '../' or starts with '.'";;
2) BOTSENT[ERROR]="Path to file $2 does not match regex: ${FILE_REGEX} ";;
3) if [[ "$2" == "/"* ]];then
BOTSENT[ERROR]="File not found: $2"
else
BOTSENT[ERROR]="File not found: ${UPLOADDIR}/$2"
fi;;
esac
[ -n "${BASHBOTDEBUG}" ] && log_message "Error in upload_file: ${BOTSENT[ERROR]}"
fi
}
upload_file(){
local CUR_URL WHAT STATUS text=$3 file="$2"
# file access checks ...
[[ "$file" = *'..'* ]] && return 1 # no directory traversal
[[ "$file" = '.'* ]] && return 1 # no hidden or relative files
if [[ "$file" = '/'* ]] ; then
[[ ! "$file" =~ ${FILE_REGEX} ]] && return 2 # absolute must match REGEX
else else
file="${UPLOADDIR:-NOUPLOADDIR}/${file}" # othiers must be in UPLOADDIR # we have a file, check file location ...
media="FILE"
[[ "${file}" = *'..'* || "${file}" = '.'* ]] && err=1 # no directory traversal
if [[ "${file}" = '/'* ]] ; then
[[ ! "${file}" =~ ${FILE_REGEX} ]] && err=2 # absolute must match REGEX
else
file="${UPLOADDIR:-NOUPLOADDIR}/${file}" # others must be in UPLOADDIR
fi
[ ! -r "${file}" ] && err=3 # and file must exits of course
# file path error, generate error response
if [ -n "${err}" ]; then
BOTSENT=(); BOTSENT[OK]="false"
case "${err}" in
1) BOTSENT[ERROR]="Path to file $2 contains to much '../' or starts with '.'";;
2) BOTSENT[ERROR]="Path to file $2 does not match regex: ${FILE_REGEX} ";;
3) if [[ "$2" == "/"* ]];then
BOTSENT[ERROR]="File not found: $2"
else
BOTSENT[ERROR]="File not found: ${UPLOADDIR}/$2"
fi;;
esac
[ -n "${BASHBOTDEBUG}" ] && log_message "Error in upload_file: ${BOTSENT[ERROR]}"
return
fi
# file OK, let's continue
fi fi
[ ! -r "$file" ] && return 3 # and file must exits of course
local ext="${file##*.}"
case $ext in
mp3|flac)
CUR_URL="$AUDIO_URL"
WHAT="audio"
STATUS="upload_audio"
;;
png|jpg|jpeg|gif|pic)
CUR_URL="$PHO_URL"
WHAT="photo"
STATUS="upload_photo"
;;
webp)
CUR_URL="$STICKER_URL"
WHAT="sticker"
STATUS="upload_photo"
;;
mp4)
CUR_URL="$VIDEO_URL"
WHAT="video"
STATUS="upload_video"
;;
ogg) # no type given, use file ext, if no ext type photo
CUR_URL="$VOICE_URL" if [ -z "${ext}" ]; then
WHAT="voice" ext="${file##*.}"
STATUS="upload_audio" [ "${ext}" = "${file}" ] && ext="photo"
fi
# select upload URL
case "${ext}" in
photo|png|jpg|jpeg|gif|pic)
url="${URL}/sendPhoto"; what="photo"; num=",0"; stat="upload_photo"
;; ;;
*) audio|mp3|flac)
CUR_URL="$DOCUMENT_URL" url="${URL}/sendAudio"; what="audio"; stat="upload_audio"
WHAT="document" ;;
STATUS="upload_document" sticker|webp)
url="${URL}/sendSticker"; what="sticker"; stat="upload_photo"
;;
video|mp4)
url="${URL}/sendVideo"; what="video"; stat="upload_video"
;;
voice|ogg)
url="${URL}/sendVoice"; what="voice"; stat="record_audio"
;;
*) url="${URL}/sendDocument"; what="document"; stat="upload_document"
;; ;;
esac esac
send_action "${1}" "$STATUS"
sendUpload "$1" "${WHAT}" "${file}" "${CUR_URL}" "${text//\\n/$'\n'}" # show file upload to user
send_action "$1" "${stat}"
# select method to send
case "${media}" in
FILE) # send local file ...
sendUpload "$1" "${what}" "${file}" "${url}" "${capt//\\n/$'\n'}";;
URL|ID) # send URL, file_id ...
sendJson "$1" '"'"${what}"'":"'"${file}"'","caption":"'"${capt//\\n/$'\n'}"'"' "${url}"
esac
# get file_id and file_type
if [ "${BOTSENT[OK]}" = "true" ]; then
BOTSENT[FILE_ID]="${UPD["result,${what}${num},file_id"]}"
BOTSENT[FILE_TYPE]="${what}"
fi
return 0
} }
# typing for text messages, upload_photo for photos, record_video or upload_video for videos, record_audio or upload_audio for audio files, upload_document for general files, find_location for location # $1 typing upload_photo record_video upload_video record_audio upload_audio upload_document find_location
send_action() { send_action() {
[ -z "$2" ] && return [ -z "$2" ] && return
sendJson "${1}" '"action": "'"${2}"'"' "$ACTION_URL" & sendJson "$1" '"action": "'"$2"'"' "${URL}/sendChatAction" &
} }
# $1 CHAT $2 lat $3 long # $1 CHAT $2 lat $3 long
send_location() { send_location() {
[ -z "$3" ] && return [ -z "$3" ] && return
sendJson "${1}" '"latitude": '"${2}"', "longitude": '"${3}"'' "$LOCATION_URL" sendJson "$1" '"latitude": '"$2"', "longitude": '"$3"'' "${URL}/sendLocation"
} }
# $1 CHAT $2 lat $3 long $4 title $5 address $6 foursquard id # $1 CHAT $2 lat $3 long $4 title $5 address $6 foursquard id
@ -272,7 +282,7 @@ send_venue() {
local add="" local add=""
[ -z "$5" ] && return [ -z "$5" ] && return
[ -n "$6" ] && add=', "foursquare_id": '"$6"'' [ -n "$6" ] && add=', "foursquare_id": '"$6"''
sendJson "${1}" '"latitude": '"${2}"', "longitude": '"${3}"', "address": "'"${5}"'", "title": "'"${4}"'"'"${add}" "$VENUE_URL" sendJson "$1" '"latitude": '"$2"', "longitude": '"$3"', "address": "'"$5"'", "title": "'"$4"'"'"${add}" "${URL}/sendVenue"
} }
@ -283,7 +293,7 @@ send_venue() {
# $1 CHAT $2 from chat $3 from msg id # $1 CHAT $2 from chat $3 from msg id
forward_message() { forward_message() {
[ -z "$3" ] && return [ -z "$3" ] && return
sendJson "${1}" '"from_chat_id": '"${2}"', "message_id": '"${3}"'' "$FORWARD_URL" sendJson "$1" '"from_chat_id": '"$2"', "message_id": '"$3"'' "${URL}/forwardMessage"
} }
forward() { # backward compatibility forward() { # backward compatibility
forward_message "$@" || return forward_message "$@" || return
@ -293,50 +303,50 @@ forward() { # backward compatibility
send_message() { send_message() {
[ -z "$2" ] && return [ -z "$2" ] && return
local text keyboard btext burl no_keyboard file lat long title address sent local text keyboard btext burl no_keyboard file lat long title address sent
text="$(sed <<< "${2}" 's/ mykeyboardend.*//;s/ *my[kfltab][a-z]\{2,13\}startshere.*//')$(sed <<< "${2}" -n '/mytextstartshere/ s/.*mytextstartshere//p')" text="$(sed <<< "$2" 's/ mykeyboardend.*//;s/ *my[kfltab][a-z]\{2,13\}startshere.*//')$(sed <<< "$2" -n '/mytextstartshere/ s/.*mytextstartshere//p')"
#shellcheck disable=SC2001 #shellcheck disable=SC2001
text="$(sed <<< "${text}" 's/ *mynewlinestartshere */\n/g')" text="$(sed <<< "${text}" 's/ *mynewlinestartshere */\n/g')"
text="${text//$'\n'/\\n}" text="${text//$'\n'/\\n}"
[ "$3" != "safe" ] && { [ "$3" != "safe" ] && {
no_keyboard="$(sed <<< "${2}" '/mykeyboardendshere/!d;s/.*mykeyboardendshere.*/mykeyboardendshere/')" no_keyboard="$(sed <<< "$2" '/mykeyboardendshere/!d;s/.*mykeyboardendshere.*/mykeyboardendshere/')"
keyboard="$(sed <<< "${2}" '/mykeyboardstartshere /!d;s/.*mykeyboardstartshere *//;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')" keyboard="$(sed <<< "$2" '/mykeyboardstartshere /!d;s/.*mykeyboardstartshere *//;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')"
btext="$(sed <<< "${2}" '/mybtextstartshere /!d;s/.*mybtextstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')" btext="$(sed <<< "$2" '/mybtextstartshere /!d;s/.*mybtextstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')"
burl="$(sed <<< "${2}" '/myburlstartshere /!d;s/.*myburlstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//g;s/ *mykeyboardendshere.*//g')" burl="$(sed <<< "$2" '/myburlstartshere /!d;s/.*myburlstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//g;s/ *mykeyboardendshere.*//g')"
file="$(sed <<< "${2}" '/myfile[^s]*startshere /!d;s/.*myfile[^s]*startshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')" file="$(sed <<< "$2" '/myfile[^s]*startshere /!d;s/.*myfile[^s]*startshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')"
lat="$(sed <<< "${2}" '/mylatstartshere /!d;s/.*mylatstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')" lat="$(sed <<< "$2" '/mylatstartshere /!d;s/.*mylatstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')"
long="$(sed <<< "${2}" '/mylongstartshere /!d;s/.*mylongstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')" long="$(sed <<< "$2" '/mylongstartshere /!d;s/.*mylongstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')"
title="$(sed <<< "${2}" '/mytitlestartshere /!d;s/.*mytitlestartshere //;s/ *my[kfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')" title="$(sed <<< "$2" '/mytitlestartshere /!d;s/.*mytitlestartshere //;s/ *my[kfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')"
address="$(sed <<< "${2}" '/myaddressstartshere /!d;s/.*myaddressstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')" address="$(sed <<< "$2" '/myaddressstartshere /!d;s/.*myaddressstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')"
} }
if [ -n "$no_keyboard" ]; then if [ -n "${no_keyboard}" ]; then
remove_keyboard "$1" "$text" remove_keyboard "$1" "${text}"
sent=y sent=y
fi fi
if [ -n "$keyboard" ]; then if [ -n "${keyboard}" ]; then
if [[ "$keyboard" != *"["* ]]; then # pre 0.60 style if [[ "${keyboard}" != *"["* ]]; then # pre 0.60 style
keyboard="[ ${keyboard//\" \"/\" \] , \[ \"} ]" keyboard="[ ${keyboard//\" \"/\" \] , \[ \"} ]"
fi fi
send_keyboard "$1" "$text" "$keyboard" send_keyboard "$1" "${text}" "${keyboard}"
sent=y sent=y
fi fi
if [ -n "$btext" ] && [ -n "$burl" ]; then if [ -n "${btext}" ] && [ -n "${burl}" ]; then
send_button "$1" "$text" "$btext" "$burl" send_button "$1" "${text}" "${btext}" "${burl}"
sent=y sent=y
fi fi
if [ -n "$file" ]; then if [ -n "${file}" ]; then
send_file "$1" "$file" "$text" send_file "$1" "${file}" "${text}"
sent=y sent=y
fi fi
if [ -n "$lat" ] && [ -n "$long" ]; then if [ -n "${lat}" ] && [ -n "${long}" ]; then
if [ -n "$address" ] && [ -n "$title" ]; then if [ -n "${address}" ] && [ -n "${title}" ]; then
send_venue "$1" "$lat" "$long" "$title" "$address" send_venue "$1" "${lat}" "${long}" "${title}" "${address}"
else else
send_location "$1" "$lat" "$long" send_location "$1" "${lat}" "${long}"
fi fi
sent=y sent=y
fi fi
if [ "$sent" != "y" ];then if [ "${sent}" != "y" ];then
send_text_mode "$1" "$text" send_text_mode "$1" "${text}"
fi fi
} }

100
mycommands.conf Normal file
View File

@ -0,0 +1,100 @@
#!/bin/bash
#######################################################
#
# File: mycommands.conf
#
# Description: place your config and messages here
#
# Usage: will be sourced from mycommands.sh
#
# License: WTFPLv2 http://www.wtfpl.net/txt/copying/
# Author: KayM (gnadelwartz), kay@rrr.de
# Created: 09.01.2021 07:27
#
#### $$VERSION$$ v1.30-0-g3266427
#######################################################
##########
# adjust your language setting here, default is C.UTF-8
# https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment
export 'LC_ALL=C.UTF-8'
export 'LANG=C.UTF-8'
export 'LANGUAGE=C.UTF-8'
##########
# in UTF-8 äöü etc. are part of [:alnum:] and ranges (e.g. a-z)
# for more information see doc/4_expert.md#Character_classes
# uncomment next line if you want classic ASCII ranges for [a-z] etc.
#export LC_COLLATE=C
##########
# edit the following lines to fit your bot usage
# use ${ME} for current bot name in messages
# Note: you must escape '_' in botname with two \ in markdown messages!
# output of /info command
export bashbot_info='This is @'"${ME//_/\\\\_}"', the Telegram example bot written entirely in bash.
Edit commands and messages in mycommands.sh!
'
# output of /help command (uncomment the next 2 lines
# export bashbot_help='*Available commands*:
# '
# Set INLINE to 1 in order to receive inline queries.
# To enable this option in your bot, send the /setinline command to @BotFather.
export INLINE="0"
# if your bot is group admin it get commands sent to other bots
# Set MEONLY to 1 to ignore commands sent to other bots
export MEONLY="0"
# Set to .* to allow sending files from all locations
# NOTE: this is a regex, not shell globbing! you must use a valid egex,
# '.' matches any character and '.*' matches all remaining charatcers!
# additionally you must escape special characters with '\', e.g. '\. \? \[ \*" to match them literally
export FILE_REGEX="${BASHBOT_ETC}/.*"
# set BASHBOT_RETRY to enable retry in case of recoverable errors, e.g. throtteling
# problems with send_xxx message etc are looged to logs/ERROR.log
unset BASHBOT_RETRY
#export BASHBOT_RETRY="yes"
# set value for adaptive sleeping while waiting for uodates in millisconds
# max slepp between polling updates 10s (default 5s)
export BASHBOT_SLEEP="10000"
# add 0.2s if no update available, up to BASHBOT_SLEEP (default 0.1s)
export BASHBOT_SLEEP_STEP="200"
# if you want to use timer functions, set BASHBOT_START_TIMER to a not empty value
# default is to not start timer
unset BASHBOT_START_TIMER
#export BASHBOT_START_TIMER="yes"
# set to "yes" and give your bot admin privilegs to remove service messages from groups
export SILENCER="no"
# uncomment to remove keyboards sent from your bot
# export REMOVEKEYBOARD="yes"
# export REMOVEKEYBOARD_PRIVATE="yes"
# uncomment to say welcome to new chat members
# export WELCOME_NEWMEMBER="yes"
WELCOME_MSG="Welcome"
# uncomment to be informed about new/left chat members
# export REPORT_NEWMEMBER="yes"
# export REPORT_LEFTMEMBER="yes"
# messages for admin only commands
NOTADMIN="Sorry, this command is allowed for admin or owner only"
NOTBOTADMIN="Sorry, this command is allowed for bot owner only"
########
# special network setup may require additional ARGS to curl
#
# example: run bashbot over TOR or SOCKS proxy
# export BASHBOT_CURL_ARGS="--socks5-hostname 127.0.0.1:9050" # TOR
# export BASHBOT_CURL_ARGS="--socks5-hostname 127.0.0.1" # regular SOCKS

View File

@ -1,83 +1,30 @@
#!/bin/bash #!/bin/bash
######### #######################################################
# #
# files: mycommands.sh.dist # File: mycommands.sh.dist
# #
# this is an out of the box test and example file to show what's possible in mycommands.sh # this is an out of the box test and example file to show what's possible in mycommands.sh
# #
# #### if you start to develop your own bot, use the clean version of this file: # #### if you start to develop your own bot, use the clean version of this file:
# #### mycommands.clean # #### mycommands.clean
# #
# Usage: will be executed when a bot command is received
#
# License: WTFPLv2 http://www.wtfpl.net/txt/copying/
# Author: KayM (gnadelwartz), kay@rrr.de
#
#### $$VERSION$$ v1.30-0-g3266427
#######################################################
# shellcheck disable=SC1117 # shellcheck disable=SC1117
#### $$VERSION$$ v1.21-0-gc85af77
#
# uncomment the following lines to overwrite info and help messages ####################
# use ${ME} for current bot name in messages # Config has moved to bashbot.conf
# Note: you must escape '_' in botname with two \ in markdown messages! # shellcheck source=./commands.sh
export bashbot_info='This is @'"${ME//_/\\\\_}"', the Telegram example bot written entirely in bash. [ -r "${BASHBOT_ETC:-.}/mycommands.conf" ] && source "${BASHBOT_ETC:-.}/mycommands.conf" "$1"
Edit commands and messages in mycommands.sh!
'
# export bashbot_help='*Available commands*:
#'
export res=""
# Set INLINE to 1 in order to receive inline queries.
# To enable this option in your bot, send the /setinline command to @BotFather.
export INLINE="0"
# if your bot is group admin it get commands sent to other bots
# Set MEONLY to 1 to ignore commands sent to other bots
export MEONLY="0"
# Set to .* to allow sending files from all locations
# NOTE: this is a regex, not shell globbing! you must use a valid egex,
# '.' matches any character and '.*' matches all remaining charatcers!
# additionally you must escape special characters with '\', e.g. '\. \? \[ \*" to match them literally
export FILE_REGEX="${BASHBOT_ETC}/.*"
# set BASHBOT_RETRY to enable retry in case of recoverable errors, e.g. throtteling
# problems with send_xxx message etc are looged to logs/ERROR.log
unset BASHBOT_RETRY
#export BASHBOT_RETRY="yes"
# set value for adaptive sleeping while waiting for uodates in millisconds
# max slepp between polling updates 10s (default 5s)
export BASHBOT_SLEEP="10000"
# add 0.2s if no update available, up to BASHBOT_SLEEP (default 0.1s)
export BASHBOT_SLEEP_STEP="200"
# if you want to use timer functions, set BASHBOT_START_TIMER to a not empty value
# default is to not start timer
unset BASHBOT_START_TIMER
#export BASHBOT_START_TIMER="yes"
# set to "yes" and give your bot admin privilegs to remove service messages from groups
export SILENCER="no"
# uncomment to remove keyboards sent from your bot
# export REMOVEKEYBOARD="yes"
# export REMOVEKEYBOARD_PRIVATE="yes"
# uncomment to say welcome to new chat members
# export WELCOME_NEWMEMBER="yes"
WELCOME_MSG="Welcome"
# uncomment to be informed about new/left chat members
# export REPORT_NEWMEMBER="yes"
# export REPORT_LEFTMEMBER="yes"
# messages for admin only commands
NOTADMIN="Sorry, this command is allowed for admin or owner only"
NOTBOTADMIN="Sorry, this command is allowed for bot owner only"
########
# special network setup may require additional ARGS to curl
#
# example: run bashbot over TOR or SOCKS proxy
# export BASHBOT_CURL_ARGS="--socks5-hostname 127.0.0.1:9050" # TOR
# export BASHBOT_CURL_ARGS="--socks5-hostname 127.0.0.1" # regular SOCKS
##################
# let's go ...
if [ "$1" = "startbot" ];then if [ "$1" = "startbot" ];then
################### ###################
# this section is processed on startup # this section is processed on startup
@ -177,41 +124,45 @@ else
case "${MESSAGE}" in case "${MESSAGE}" in
################## ##################
# example commands, replace thm by your own # example commands, replace thm by your own
'/unpin'*) # unpin all messages if (bot)admin or allowed for user
user_is_allowed "${USER[ID]}" "unpin" "${CHAT[ID]}" &&\
unpinall_chat_messages "${CHAT[ID]}"
;;
'/echo'*) # example echo command '/echo'*) # example echo command
send_normal_message "${CHAT[ID]}" "$MESSAGE" send_normal_message "${CHAT[ID]}" "${MESSAGE}"
;; ;;
'/question'*) # start interactive questions '/question'*) # start interactive questions
checkproc checkproc
if [ "$res" -gt 0 ] ; then if [ "${res}" -gt 0 ] ; then
startproc "examples/question.sh" || send_normal_message "${CHAT[ID]}" "Can't start question." startproc "examples/question.sh" || send_normal_message "${CHAT[ID]}" "Can't start question."
else else
send_normal_message "${CHAT[ID]}" "$MESSAGE already running ..." send_normal_message "${CHAT[ID]}" "${MESSAGE} already running ..."
fi fi
;; ;;
'/cancel'*) # cancel interactive command '/cancel'*) # cancel interactive command
checkproc checkproc
if [ "$res" -gt 0 ] ;then if [ "${res}" -gt 0 ] ;then
killproc && send_normal_message "${CHAT[ID]}" "Command canceled." killproc && send_normal_message "${CHAT[ID]}" "Command canceled."
else else
send_normal_message "${CHAT[ID]}" "No command is currently running." send_normal_message "${CHAT[ID]}" "No command is currently running."
fi fi
;; ;;
'/run_notify'*) # start notify background job '/run_notify'*) # start notify background job
myback="notify"; checkback "$myback" myback="notify"; checkback "${myback}"
if [ "$res" -gt 0 ] ; then if [ "${res}" -gt 0 ] ; then
background "examples/notify.sh 60" "$myback" || send_normal_message "${CHAT[ID]}" "Can't start notify." background "examples/notify.sh 60" "${myback}" || send_normal_message "${CHAT[ID]}" "Can't start notify."
else else
send_normal_message "${CHAT[ID]}" "Background command $myback already running ..." send_normal_message "${CHAT[ID]}" "Background command ${myback} already running ..."
fi fi
;; ;;
'/stop_notify'*) # kill notify background job '/stop_notify'*) # kill notify background job
myback="notify"; checkback "$myback" myback="notify"; checkback "${myback}"
if [ "$res" -eq 0 ] ; then if [ "${res}" -eq 0 ] ; then
killback "$myback" killback "${myback}"
send_normal_message "${CHAT[ID]}" "Background command $myback canceled." send_normal_message "${CHAT[ID]}" "Background command ${myback} canceled."
else else
send_normal_message "${CHAT[ID]}" "No background command $myback is currently running.." send_normal_message "${CHAT[ID]}" "No background command ${myback} is currently running.."
fi fi
;; ;;
@ -247,15 +198,15 @@ else
;; ;;
"2"*) # two photos "2"*) # two photos
answer_inline_multi "${iQUERY[ID]}" " answer_inline_multi "${iQUERY[ID]}" "
$(inline_query_compose "$RANDOM" "photo" "https://avatars.githubusercontent.com/u/13046303"), $(inline_query_compose "${RANDOM}" "photo" "https://avatars.githubusercontent.com/u/13046303"),
$(inline_query_compose "$RANDOM" "photo" "https://avatars.githubusercontent.com/u/4593242") $(inline_query_compose "${RANDOM}" "photo" "https://avatars.githubusercontent.com/u/4593242")
" "
;; ;;
"3"*) # three photos "3"*) # three photos
answer_inline_multi "${iQUERY[ID]}" " answer_inline_multi "${iQUERY[ID]}" "
$(inline_query_compose "$RANDOM" "photo" "https://avatars.githubusercontent.com/u/13046303"), $(inline_query_compose "${RANDOM}" "photo" "https://avatars.githubusercontent.com/u/13046303"),
$(inline_query_compose "$RANDOM" "photo" "https://avatars.githubusercontent.com/u/4593242") $(inline_query_compose "${RANDOM}" "photo" "https://avatars.githubusercontent.com/u/4593242")
$(inline_query_compose "$RANDOM" "photo" "https://avatars.githubusercontent.com/u/102707") $(inline_query_compose "${RANDOM}" "photo" "https://avatars.githubusercontent.com/u/102707")
" "
;; ;;
@ -264,7 +215,7 @@ else
local avatar=("https://avatars.githubusercontent.com/u/13046303" "https://avatars.githubusercontent.com/u/4593242" "https://avatars.githubusercontent.com/u/102707" "https://avatars.githubusercontent.com/u/6460407") local avatar=("https://avatars.githubusercontent.com/u/13046303" "https://avatars.githubusercontent.com/u/4593242" "https://avatars.githubusercontent.com/u/102707" "https://avatars.githubusercontent.com/u/6460407")
answer_inline_multi "${iQUERY[ID]}" " answer_inline_multi "${iQUERY[ID]}" "
$(for photo in ${avatar[*]} ; do $(for photo in ${avatar[*]} ; do
printf "%s\n" "${sep}"; inline_query_compose "$RANDOM" "photo" "${photo}" "${photo}"; sep="," printf "%s\n" "${sep}"; inline_query_compose "${RANDOM}" "photo" "${photo}" "${photo}"; sep=","
done) done)
" "
;; ;;
@ -283,7 +234,7 @@ else
# $1 current date, $2 from where the function was called, $3 ... $n optional information # $1 current date, $2 from where the function was called, $3 ... $n optional information
my_debug_checks() { my_debug_checks() {
# example check because my bot created a wrong file # example check because my bot created a wrong file
[ -f ".jssh" ] && printf "%s: %s\n" "${1}" "Ups, found file \"${PWD:-.}/.jssh\"! ==========" [ -f ".jssh" ] && printf "%s: %s\n" "$1" "Ups, found file \"${PWD:-.}/.jssh\"! =========="
} }
# called when bashbot send_xxx command failed because we can not connect to telegram # called when bashbot send_xxx command failed because we can not connect to telegram
@ -303,10 +254,10 @@ else
local image result sep="" count="1" local image result sep="" count="1"
result="$(wget --user-agent 'Mozilla/5.0' -qO - "https://images.search.yahoo.com/search/images?p=$1" | sed 's/</\n</g' | grep "<img src=")" result="$(wget --user-agent 'Mozilla/5.0' -qO - "https://images.search.yahoo.com/search/images?p=$1" | sed 's/</\n</g' | grep "<img src=")"
while read -r image; do while read -r image; do
[ "$count" -gt "20" ] && break [ "${count}" -gt "20" ] && break
image="${image#* src=\'}"; image="${image%%&pid=*}" image="${image#* src=\'}"; image="${image%%&pid=*}"
[[ "${image}" = *"src="* ]] && continue [[ "${image}" = *"src="* ]] && continue
printf "%s\n" "${sep}"; inline_query_compose "$RANDOM" "photo" "${image}"; sep="," printf "%s\n" "${sep}"; inline_query_compose "${RANDOM}" "photo" "${image}"; sep=","
count=$(( count + 1 )) count=$(( count + 1 ))
done <<<"${result}" done <<<"${result}"
} }

View File

@ -1,66 +1,31 @@
#!/bin/bash #!/bin/bash
######## #######################################################
#
# File: mycommands.sh.clean
# #
# files: mycommands.sh.clean
# copy to mycommands.sh and add all your commands and functions here ... # copy to mycommands.sh and add all your commands and functions here ...
# #
#### $$VERSION$$ v1.21-0-gc85af77 # Usage: will be executed when a bot command is received
# #
# License: WTFPLv2 http://www.wtfpl.net/txt/copying/
########## # Author: KayM (gnadelwartz), kay@rrr.de
# edit the following lines to fit your bot usage
export bashbot_info='This is bashbot, the Telegram bot written entirely in bash.
'
export bashbot_help='*Available commands*:
'
export res=""
# Set INLINE to 1 in order to receive inline queries.
# To enable this option in your bot must also send the /setinline command to @BotFather.
export INLINE="0"
# if your bot is group admin it get commands sent to other bots
# Set MEONLY to 1 to ignore commands sent to other bots
export MEONLY="0"
# NOTE: this is a regex, not shell globbing! you must use a valid egex,
# '.' matches any character and '.*' matches all remaining charatcers!
# additionally you must escape special characters with '\', e.g. '\. \? \[ \*" to match them literally
# do NOT set to .* as this allow sending files from all locations!
export FILE_REGEX="${BASHBOT_ETC}/.*"
# set BASHBOT_RETRY to enable retry in case of recoverable errors, e.g. throtteling
# problems with send_,´message etc are looged to logs/ERROR.log
unset BASHBOT_RETRY
#export BASHBOT_RETRY="yes"
# set value for adaptive sleeping while waitingnfor uodates in millisconds
# max slepp between polling updates 10s (default 5s)
export BASHBOT_SLEEP="10000"
# add 0.2s if no update available, up to BASHBOT_SLEEP (default 0.1s)
export BASHBOT_SLEEP_STEP="200"
# if you want to use timer functions, set BASHBOT_START_TIMER to a not empty value
# default is to nit start timer
unset BASHBOT_START_TIMER
#export BASHBOT_START_TIMER="yes"
# set to "yes" and give your bot admin privilegs to remove service messaes from groups
export SILENCER="no"
# uncomment to remove keyboards sent by your bot
# export REMOVEKEYBOARD="yes"
# export REMOVEKEYBOARD_PRIVATE="yes"
########
# special network setup may require additional ARGS to curl
# #
# example: run bashbot over TOR or SOCKS proxy #### $$VERSION$$ v1.30-0-g3266427
# export BASHBOT_CURL_ARGS="--socks5-hostname 127.0.0.1:9050" # TOR #######################################################
# export BASHBOT_CURL_ARGS="--socks5-hostname 127.0.0.1" # regular SOCKS # shellcheck disable=SC1117
####################
# Config has moved to bashbot.conf
# shellcheck source=./commands.sh
[ -r "${BASHBOT_ETC:-.}/mycommands.conf" ] && source "${BASHBOT_ETC:-.}/mycommands.conf" "$1"
##################
# lets's go
if [ "$1" = "startbot" ];then if [ "$1" = "startbot" ];then
###################
# this section is processed on startup
# run once after startup when the first message is received # run once after startup when the first message is received
my_startup(){ my_startup(){
: :
@ -94,7 +59,7 @@ else
################## ##################
# example command, replace them by your own # example command, replace them by your own
'/echo'*) # example echo command '/echo'*) # example echo command
send_normal_message "${CHAT[ID]}" "$MESSAGE" send_normal_message "${CHAT[ID]}" "${MESSAGE}"
;; ;;
########## ##########
@ -138,10 +103,10 @@ else
local image result sep="" count="1" local image result sep="" count="1"
result="$(wget --user-agent 'Mozilla/5.0' -qO - "https://images.search.yahoo.com/search/images?p=$1" | sed 's/</\n</g' | grep "<img src=")" result="$(wget --user-agent 'Mozilla/5.0' -qO - "https://images.search.yahoo.com/search/images?p=$1" | sed 's/</\n</g' | grep "<img src=")"
while read -r image; do while read -r image; do
[ "$count" -gt "20" ] && break [ "${count}" -gt "20" ] && break
image="${image#* src=\'}"; image="${image%%&pid=*}" image="${image#* src=\'}"; image="${image%%&pid=*}"
[[ "${image}" = *"src="* ]] && continue [[ "${image}" = *"src="* ]] && continue
printf "%s\n" "${sep}"; inline_query_compose "$RANDOM" "photo" "${image}"; sep="," printf "%s\n" "${sep}"; inline_query_compose "${RANDOM}" "photo" "${image}"; sep=","
count=$(( count + 1 )) count=$(( count + 1 ))
done <<<"${result}" done <<<"${result}"
} }

View File

@ -1,12 +1,19 @@
#!/bin/bash #!/bin/bash
# file: interactive.sh ########################################################################
# template for an interactive chat #
# test: start_proc "${CHAT[ID]}" "./scripts/interactive.sh.clean" # File: interactive.sh
#
# Description: template for an interactive chat
#
# Usgage: start_proc "${CHAT[ID]}" ./scripts/interactive.sh.clean
#
# Test in CLI: ./scripts/interactive.sh.clean
# #
# This file is public domain in the USA and all free countries. # This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
########################################################################
###### ######
# parameters # parameters

View File

@ -10,7 +10,7 @@
# LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/
# AUTHOR: KayM (gnadelwartz), kay@rrr.de # AUTHOR: KayM (gnadelwartz), kay@rrr.de
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
#=============================================================================== #===============================================================================
# magic to ensure that we're always inside the root of our application, # magic to ensure that we're always inside the root of our application,

View File

@ -11,7 +11,7 @@
# LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/
# AUTHOR: KayM (gnadelwartz), kay@rrr.de # AUTHOR: KayM (gnadelwartz), kay@rrr.de
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
#=============================================================================== #===============================================================================
# common variables # common variables
@ -61,9 +61,9 @@ print_array() {
local idx t local idx t
local arrays=( "${@}" ) local arrays=( "${@}" )
for idx in "${arrays[@]}"; do for idx in "${arrays[@]}"; do
declare -n temp="$idx" declare -n temp="${idx}"
for t in "${!temp[@]}"; do for t in "${!temp[@]}"; do
printf '%s:\t%s\t%s\n' "$idx" "$t" "${temp[$t]}" printf '%s:\t%s\t%s\n' "${idx}" "${t}" "${temp[${t}]}"
done | sort done | sort
done | grep -v '^USER: 0' done | grep -v '^USER: 0'
} }
@ -71,12 +71,12 @@ print_array() {
compare_sorted() { compare_sorted() {
local ret=0 local ret=0
sort -d -o "${1}.sort" "${1}" sort -d -o "$1.sort" "$1"
sort -d -o "${2}.sort" "${2}" sort -d -o "$2.sort" "$2"
diff -c "${1}.sort" "${2}.sort" || ret=1 diff -c "$1.sort" "$2.sort" || ret=1
[[ "${1}" != "${TESTDIR}"* ]] && rm -f "${1}.sort" [[ "$1" != "${TESTDIR}"* ]] && rm -f "$1.sort"
[[ "${2}" != "${TESTDIR}"* ]] && rm -f "${2}.sort" [[ "$2" != "${TESTDIR}"* ]] && rm -f "$2.sort"
return "$ret" return "${ret}"
} }
###### ######

View File

@ -10,7 +10,7 @@
# LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/
# AUTHOR: KayM (gnadelwartz), kay@rrr.de # AUTHOR: KayM (gnadelwartz), kay@rrr.de
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
#=============================================================================== #===============================================================================
../dev/hooks/pre-commit.sh ../dev/hooks/pre-commit.sh

View File

@ -10,7 +10,7 @@
# LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/
# AUTHOR: KayM (gnadelwartz), kay@rrr.de # AUTHOR: KayM (gnadelwartz), kay@rrr.de
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
#=============================================================================== #===============================================================================
# include common functions and definitions # include common functions and definitions

View File

@ -10,7 +10,7 @@
# LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/
# AUTHOR: KayM (gnadelwartz), kay@rrr.de # AUTHOR: KayM (gnadelwartz), kay@rrr.de
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
#=============================================================================== #===============================================================================
# include common functions and definitions # include common functions and definitions
@ -24,7 +24,7 @@ TESTFILES="${TOKENFILE} ${ACLFILE} ${COUNTFILE} ${BLOCKEDFILE} ${ADMINFILE}"
# run bashbot first time with init # run bashbot first time with init
printf "Run bashbot init ...\n" printf "Run bashbot init ...\n"
"${TESTDIR}/bashbot.sh" init >"${LOGFILE}" <<EOF "${TESTDIR}/bashbot.sh" init >"${LOGFILE}" <<EOF
$TESTTOKEN ${TESTTOKEN}
nobody nobody
botadmin botadmin
@ -46,7 +46,7 @@ trap exit 1 EXIT
cd "${TESTDIR}" || exit cd "${TESTDIR}" || exit
printf "%s\n" "Test if ${JSONSHFILE} exists ..." printf "%s\n" "Test if ${JSONSHFILE} exists ..."
[ ! -x "$JSONSHFILE" ] && { printf "%s\n" "${NOSUCCESS} json.sh not found"; exit 1; } [ ! -x "${JSONSHFILE}" ] && { printf "%s\n" "${NOSUCCESS} json.sh not found"; exit 1; }
printf "Test Sourcing of bashbot.sh ...\n" printf "Test Sourcing of bashbot.sh ...\n"
# shellcheck source=./bashbot.sh # shellcheck source=./bashbot.sh

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
# include common functions and definitions # include common functions and definitions
# shellcheck source=test/ALL-tests.inc.sh # shellcheck source=test/ALL-tests.inc.sh

View File

@ -10,7 +10,7 @@
# LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/
# AUTHOR: KayM (gnadelwartz), kay@rrr.de # AUTHOR: KayM (gnadelwartz), kay@rrr.de
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
#=============================================================================== #===============================================================================
# include common functions and definitions # include common functions and definitions

View File

@ -10,7 +10,7 @@
# LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/
# AUTHOR: KayM (gnadelwartz), kay@rrr.de # AUTHOR: KayM (gnadelwartz), kay@rrr.de
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
#=============================================================================== #===============================================================================
# include common functions and definitions # include common functions and definitions

View File

@ -10,7 +10,7 @@
# LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/
# AUTHOR: KayM (gnadelwartz), kay@rrr.de # AUTHOR: KayM (gnadelwartz), kay@rrr.de
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
#=============================================================================== #===============================================================================
# include common functions and definitions # include common functions and definitions
@ -34,15 +34,15 @@ _is_function send_message || printf "Send Message not found!\n"
# over write sendJson to output parameter only # over write sendJson to output parameter only
sendEmpty() { sendEmpty() {
printf 'chat:%s\tJSON:%s\nURL:%s\n\n' "${1}" "${2}" "${3}" printf 'chat:%s\tJSON:%s\nURL:%s\n\n' "$1" "$2" "$3"
} }
sendJson() { sendJson() {
printf 'chat:%s\tJSON:%s\nURL:%s\n\n' "${1}" "${2}" "${3}" printf 'chat:%s\tJSON:%s\nURL:%s\n\n' "$1" "$2" "$3"
} }
sendUpload() { sendUpload() {
#JSON:"document":"/tmp/allowed/this_is_my.doc","caption":"Text plus absolute file will appear in chat"" #JSON:"document":"/tmp/allowed/this_is_my.doc","caption":"Text plus absolute file will appear in chat""
printf 'chat:%s\tJSON:"%s":"%s","caption":"%s"\nURL:%s\n\n' "${1}" "${2}" "${3}" "${5}" "${4}" printf 'chat:%s\tJSON:"%s":"%s","caption":"%s"\nURL:%s\n\n' "$1" "$2" "$3" "$5" "$4"
} }
# send text input to send_message # send text input to send_message
@ -51,18 +51,18 @@ printf " Send line ..."
# create dummy files for upload # create dummy files for upload
ALLOW='/tmp/allowed' ALLOW='/tmp/allowed'
FILE_REGEX="$ALLOW/.*" FILE_REGEX="${ALLOW}/.*"
[ -d "$ALLOW" ] || mkdir "$ALLOW" [ -d "${ALLOW}" ] || mkdir "${ALLOW}"
touch "$ALLOW/this_is_my.gif" "$ALLOW/this_is_my.doc" touch "${ALLOW}/this_is_my.gif" "${ALLOW}/this_is_my.doc"
touch "$DATADIR/this_is_my.gif" "$DATADIR/this_is_my.doc" touch "${DATADIR}/this_is_my.gif" "${DATADIR}/this_is_my.doc"
while read -r line ; do while read -r line ; do
set -x; set +e set -x; set +e
send_message "123456" "$line" >>"${OUTPUTFILE}" send_message "123456" "${line}" >>"${OUTPUTFILE}"
set +x; set -e set +x; set -e
printf "." printf "."
done < "${INPUTFILE}" 2>>"${LOGFILE}" done < "${INPUTFILE}" 2>>"${LOGFILE}"
[ -d "$ALLOW" ] && rm -rf "$ALLOW" [ -d "${ALLOW}" ] && rm -rf "${ALLOW}"
printf " done.\n" printf " done.\n"

View File

@ -10,7 +10,7 @@
# LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/
# AUTHOR: KayM (gnadelwartz), kay@rrr.de # AUTHOR: KayM (gnadelwartz), kay@rrr.de
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
#=============================================================================== #===============================================================================
# include common functions and definitions # include common functions and definitions

View File

@ -10,7 +10,7 @@
# LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/
# AUTHOR: KayM (gnadelwartz), kay@rrr.de # AUTHOR: KayM (gnadelwartz), kay@rrr.de
# #
#### $$VERSION$$ v1.21-0-gc85af77 #### $$VERSION$$ v1.30-0-g3266427
#=============================================================================== #===============================================================================
# include common functions and definitions # include common functions and definitions
@ -53,7 +53,7 @@ mkdir "${BASHBOT_VAR}/${DATADIR}"
# run bashbot first time with init # run bashbot first time with init
"${BASHBOT_BIN}/bashbot.sh" init >"${LOGFILE}" <<EOF "${BASHBOT_BIN}/bashbot.sh" init >"${LOGFILE}" <<EOF
$TESTTOKEN ${TESTTOKEN}
nobody nobody
botadmin botadmin
EOF EOF