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
You are Botadmin
*Available commands*:
*• /start*: _Start bot and get this message_.
*• /help*: _Get this message_.
*• /info*: _Get shorter info message about this bot_....
Available commands:
/start: _Start bot and get this message_.
/help: _Get this message_.
/info: _Get shorter info message about this bot_....
/info
@ -329,12 +329,12 @@ It features background tasks and interactive chats, and can serve as an interfac
<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>To enable debug mode, start bashbot with debug as third argument: <code>bashbot start debug</code></p>
<pre><code>├── 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)</code></pre>
<pre><code>|__ 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)</code></pre>
<hr />
<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>
@ -390,6 +390,6 @@ It features background tasks and interactive chats, and can serve as an interfac
<p>@Gnadelwartz</p>
<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>
<h4>$$VERSION$$ v1.21-0-gc85af77</h4>
<h4>$$VERSION$$ v1.30-0-g3266427</h4>
</body>
</html>

View File

@ -104,10 +104,10 @@ Now open the Telegram App on your mobile phone and start a chat with your bot (_
/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_....
Available commands:
/start: _Start bot and get this message_.
/help: _Get this message_.
/info: _Get shorter info message about this bot_....
/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`
```
├── 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)
|__ 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)
```
----
@ -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!
#### $$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.
</h2>
..
****
****oooooo*****
*****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).
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,
iicc1 and dcoomber.
Prerequisites
Released to the public domain wherever applicable.
Elsewhere, consider it released under the
[WTFPLv2](http://www.wtfpl.net/txt/copying/).
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 Linux/Unix
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
Linux/Unix 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](https://en.wikipedia.org/wiki/BusyBox#Commands) or
[toybox](https://landley.net/toybox/help.html), see [Developer
Notes](doc/7_develop.md#common-commands).
* Introduction to Telegram Bots [https://core.telegram.org/bots]
* Install Bashbot [doc/0_install.md]
**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).
o Install release
o Install from github
o Update Bashbot
o Notes on Updates
**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).
* Get Bottoken from Botfather [doc/1_firstbot.md]
* Getting Started [doc/2_usage.md]
Bashbot [Documentation](https://github.com/topkecleon/telegram-bot-bash) and
[Downloads](https://github.com/topkecleon/telegram-bot-bash/releases) are
available on [www.github.com](https://www.github.com).
o Managing your Bot
o Receive data
o Send messages
o Send files, locations, keyboards
## Documentation
* [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)
* Advanced Features [doc/3_advanced.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
bash, a [Telegram client](https://telegram.org) and a mobile phone [with a
Telegram account](https://telegramguide.com/create-a-telegram-account/).
* Expert Use [doc/4_expert.md]
First you need to [create a new Telegram Bot token](doc/1_firstbot.md) for your
bot and write it down.
o Handling UTF-8 character sets
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
and install telegram-bot-bash:
* Best Practices [doc/5_practice.md]
```bash
# create bot dir
mkdir mybot
cd mybot
o Customize mycommands.sh
o Overwrite/disable commands
o Separate logic from commands
o Test your Bot with shellcheck
# download latest release with wget or from
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)"
* Function Reference [doc/6_reference.md]
# Extract the tar archive and go into bot dir
tar -xzf *.tar.gz
cd telegram-bot-bash
o Sending Messages, Files, Keyboards
o User Access Control
o Inline Queries
o jsshDB Bashbot key-value storage
o Background and Interactive Jobs
# initialize your bot
# Enter your bot token when asked, all other questions can be answered by
hitting the \<Return\> key.
./bashbot.sh init
* Developer Notes [doc/7_develop.md]
# Now start your bot
./bashbot.sh start
o Debug bashbot
o Modules, addons, events
o Setup your environment
o Bashbot test suite
Bottoken is valid ...
Bot Name: yourbotname_bot
Session Name: yourbotname_bot-startbot
Bot started successfully.
```
* Examples Directory [examples/README.md]
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
Your very first bashbot in a nutshell
You are Botadmin
*Available commands*:
*• /start*: _Start bot and get this message_.
*• /help*: _Get this message_.
*• /info*: _Get shorter info message about this bot_....
To install and run bashbot you need access to a Linux/Unix command line with bash, a
Telegram client [https://telegram.org] and a mobile phone with_a_Telegram_account.
First you need to create a new Telegram Bot token [doc/1_firstbot.md] for your bot and
write it down.
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.
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).
# download latest release with wget or from https://github.com/topkecleon/telegram-bot-
bash/releases/latest
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;
### 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
logged to `ERROR.log`.
Start bashbot in debug mode to see all messages sent to / received from
# initialize your bot
# Enter your bot token when asked, all other questions can be answered by hitting the
\<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.
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
| |__ 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 to your Bot.
Running a Telegram Bot means it is connected to the public and you never know 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
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).
Use printf whenever possible
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.
If you're writing a script that accepts external input (e.g. from the user as arguments or
the file system), you shouldn't use echo to display it. Use printf whenever possible
[https://unix.stackexchange.com/a/6581].
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 /*)`).
Run your Bot as a restricted user
A powerful tool to improve your scripts is `shellcheck`. You can [use it
online](https://www.shellcheck.net/) or
[install shellcheck
locally](https://github.com/koalaman/shellcheck#installing). 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](doc/7_develop.md) to check if important
functionality is working as expected.
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.
### Use printf whenever possible
Secure your Bot installation
If you're writing a script that accepts external input (e.g. from the user as
arguments or the file system),
you shouldn't use echo to display it. [Use printf whenever
possible](https://unix.stackexchange.com/a/6581).
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 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
**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).
FAQ
### 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.
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 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:
```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
#Connecting to api.telegram.org (api.telegram.org)|46.38.243.234|:443...
failed: Connection timed out.
curl -m 10 https://api.telegram.org/bot
#curl: (28) Connection timed out after 10001 milliseconds
nc -w 2 api.telegram.org 443 || echo "your IP seems blocked by telegram"
#your IP seems blocked by telegram
```
wget -t 1 -T 10 https://api.telegram.org/bot
#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).
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.
---
nc -w 2 api.telegram.org 443 || echo &quot;your IP seems blocked by telegram&quot;
#your IP seems blocked by telegram
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
## 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
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.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
# a chat and takes actions if threshold is reached
#
#### $$VERSION$$ v1.21-0-gc85af77
#### $$VERSION$$ v1.30-0-g3266427
# used events:
#
@ -37,7 +37,7 @@ ANTIFL_BAN="5" # 5 minutes
# initialize after installation or update
if [[ "$1" = "init"* ]]; then
jssh_newDB "addons/$ANTIFL_ME"
jssh_newDB "addons/${ANTIFL_ME}"
fi
@ -46,7 +46,7 @@ fi
if [[ "$1" = "start"* ]]; then
ANTIFL_ADMIN="$(getConfigKey "botadmin")"
#load existing chat settings on start
jssh_readDB "ANTIFL_CHATS" "addons/$ANTIFL_ME"
jssh_readDB "ANTIFL_CHATS" "addons/${ANTIFL_ME}"
# register to CMD
BASHBOT_EVENT_CMD["${ANTIFL_ME}"]="${ANTIFL_ME}_cmd"
@ -71,14 +71,14 @@ if [[ "$1" = "start"* ]]; then
"/afdo" | "/afactive")
[[ "${CMD[1]}" =~ ^[-0-9]+$ ]] && user_is_botadmin "${USER[ID]}" && chat="$3"
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}" &
;;
# command /afactive starts counter meausares
"/afstop")
[[ "${CMD[1]}" =~ ^[-0-9]+$ ]] && user_is_botadmin "${USER[ID]}" && chat="$3"
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}" &
;;
esac
@ -90,7 +90,7 @@ if [[ "$1" = "start"* ]]; then
# save settings and reset flood level every BAN Min
antiFlood_timer(){
ANTIFL_ACTUALS=( )
jssh_writeDB "ANTIFL_CHATS" "addons/$ANTIFL_ME" &
jssh_writeDB "ANTIFL_CHATS" "addons/${ANTIFL_ME}" &
}
# register to inline and command

View File

@ -4,7 +4,7 @@
# Addons can register to bashbot events at startup
# 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.
#

View File

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

View File

@ -15,8 +15,8 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#
# Usage: bashbot.sh [-h|--help|BOTCOMMANDS]
BOTCOMMANDS="start, stop, status, help, init, suspendback, resumeback, killback"
# Usage: bashbot.sh BOTCOMMAND
BOTCOMMANDS="-h help init start stop status suspendback resumeback killback"
#
# Exit Codes:
# 0 - success (hopefully)
@ -30,7 +30,7 @@
# 8 - curl/wget missing
# 10 - not bash!
#
#### $$VERSION$$ v1.21-0-gc85af77
#### $$VERSION$$ v1.30-0-g3266427
##################################################################
# emmbeded system may claim bash but it is not
@ -42,7 +42,7 @@ fi
# are we running in a terminal?
NN="\n"
if [ -t 1 ] && [ -n "$TERM" ]; then
if [ -t 1 ] && [ -n "${TERM}" ]; then
INTERACTIVE='yes'
RED='\e[31m'
GREEN='\e[32m'
@ -63,47 +63,80 @@ if [ "$({ LC_ALL=C.utf-8 printf "%b" "\u1111"; } 2>/dev/null)" = "\u1111" ]; the
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
# returns true if command exist
_exists() {
[ "$(type -t "${1}")" = "file" ]
[ "$(type -t "$1")" = "file" ]
}
# execute function if exists
_exec_if_function() {
[ "$(type -t "${1}")" != "function" ] && return 1
[ "$(type -t "$1")" != "function" ] && return 1
"$@"
}
# returns true if function exist
_is_function() {
[ "$(type -t "${1}")" = "function" ]
[ "$(type -t "$1")" = "function" ]
}
# 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
_round_float() {
local digit="${2}"; [[ "${2}" =~ ^[0-9]+$ ]] || digit="0"
{ LC_ALL=C.utf-8 printf "%.${digit}f" "${1}"; } 2>/dev/null
local digit="$2"; [[ "$2" =~ ^[${o9o9o9}]+$ ]] || digit="0"
{ 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() {
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3
[[ "$1" =~ ^[-${azAZo9},._]+$ ]] || return 3
[ -z "${BOTCONFIG}" ] && return 1
printf '["%s"]\t"%s"\n' "${1//,/\",\"}" "${2//\"/\\\"}" >>"${BOTCONFIG}.jssh"
}
getConfigKey() {
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3
[ -r "${BOTCONFIG}.jssh" ] && sed -n 's/\["'"$1"'"\]\t*"\(.*\)"/\1/p' <"${BOTCONFIG}.jssh" | tail -n 1
[[ "$1" =~ ^[-${azAZo9},._]+$ ]] || return 3
[ -r "${BOTCONFIG}.jssh" ] && sed -n 's/\["'"$1"'"\]\t*"\(.*\)"/\1/p' "${BOTCONFIG}.jssh" | tail -n 1
}
# check if $1 seems a valid token
# return true if token seems to be valid
check_token(){
[[ "${1}" =~ ^[0-9]{8,10}:[a-zA-Z0-9_-]{35}$ ]] && return 0
[[ "$1" =~ ^[${o9o9o9}]{8,10}:[${azAZo9}_-]{35}$ ]] && return 0
return 1
}
# log $1 with date
log_error(){ printf "%s: %s\n" "$(date)" "$*" >>"${ERRORLOG}"; }
log_debug(){ printf "%s: %s\n" "$(date)" "$*" >>"${DEBUGLOG}"; }
log_update(){ printf "%s: %s\n" "$(date)" "$*" >>"${UPDATELOG}"; }
log_error(){ printf "%(%c)T: %s\n" -1 "$*" >>"${ERRORLOG}"; }
log_debug(){ printf "%(%c)T: %s\n" -1 "$*" >>"${DEBUGLOG}"; }
log_update(){ printf "%(%c)T: %s\n" -1 "$*" >>"${UPDATELOG}"; }
# 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
export BASHBOTDEBUG
@ -113,16 +146,16 @@ export BASHBOTDEBUG
# shellcheck disable=SC2094
debug_checks(){ {
[ -z "${BASHBOTDEBUG}" ] && return
local DATE WHERE MYTOKEN; DATE="$(date)"; WHERE="${1}"; shift
printf "%s: debug_checks: %s: bashbot.sh %s\n" "${DATE}" "${WHERE}" "${@##*/}"
local token where="$1"; shift
printf "%(%c)T: debug_checks: %s: bashbot.sh %s\n" -1 "${where}" "${1##*/}"
# shellcheck disable=SC2094
[ -z "${DEBUGLOG}" ] && printf "%s: %s\n" "${DATE}" "DEBUGLOG not set! =========="
MYTOKEN="$(getConfigKey "bottoken")"
[ -z "${MYTOKEN}" ] && printf "%s: %s\n" "${DATE}" "Bot token is missing! =========="
check_token "${MYTOKEN}" || printf "%s: %s\n" "${DATE}" "Invalid bot token! =========="
[ -z "$(getConfigKey "botadmin")" ] && printf "%s: %s\n" "${DATE}" "Bot admin is missing! =========="
[ -z "${DEBUGLOG}" ] && printf "%(%c)T: %s\n" -1 "DEBUGLOG not set! =========="
token="$(getConfigKey "bottoken")"
[ -z "${token}" ] && printf "%(%c)T: %s\n" -1 "Bot token is missing! =========="
check_token "${token}" || printf "%(%c)T: %s\n%s\n" -1 "Invalid bot token! ==========" "${token}"
[ -z "$(getConfigKey "botadmin")" ] && printf "%(%c)T: %s\n" -1 "Bot admin is missing! =========="
# call user defined debug_checks if exists
_exec_if_function my_debug_checks "${DATE}" "${WHERE}" "$*"
_exec_if_function my_debug_checks "$(_date)" "${where}" "$*"
} >>"${DEBUGLOG}"
}
@ -142,35 +175,37 @@ MODULEDIR="${SCRIPTDIR}/modules"
# adjust locations based on source and real name
[[ "${SCRIPT}" != "${REALME}" || "$1" == "source" ]] && SOURCE="yes"
if [ -n "$BASHBOT_HOME" ]; then
SCRIPTDIR="$BASHBOT_HOME"
if [ -n "${BASHBOT_HOME}" ]; then
SCRIPTDIR="${BASHBOT_HOME}"
else
BASHBOT_HOME="${SCRIPTDIR}"
fi
[ -z "${BASHBOT_ETC}" ] && BASHBOT_ETC="$BASHBOT_HOME"
[ -z "${BASHBOT_VAR}" ] && BASHBOT_VAR="$BASHBOT_HOME"
[ -z "${BASHBOT_ETC}" ] && BASHBOT_ETC="${BASHBOT_HOME}"
[ -z "${BASHBOT_VAR}" ] && BASHBOT_VAR="${BASHBOT_HOME}"
ADDONDIR="${BASHBOT_ETC:-.}/addons"
RUNUSER="${USER}" # USER is overwritten by bashbot array :-(, save original
# provide help
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;;
"help") HELP="${BASHBOT_HOME:-.}/README"
if [ -n "${INTERACTIVE}" ];then
_exists w3m && w3m "$HELP.html" && exit
_exists lynx && lynx "$HELP.html" && exit
_exists less && less "$HELP.txt" && exit
_exists w3m && w3m "${HELP}.html" && exit
_exists lynx && lynx "${HELP}.html" && exit
_exists less && less "${HELP}.txt" && exit
fi
cat "$HELP.txt"
cat "${HELP}.txt"
exit;;
esac
# 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}"
exit 1
fi
@ -253,7 +288,6 @@ ERRORLOG="${LOGDIR}/ERROR.log"
UPDATELOG="${LOGDIR}/BASHBOT.log"
MESSAGELOG="${LOGDIR}/MESSAGE.log"
debug_checks "start SOURCE=${SOURCE:-no}" "$@"
# read BOTTOKEN from bot database if not set
if [ -z "${BOTTOKEN}" ]; then
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"\
"${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"
[ -n "$(getConfigKey "botid")" ] && printf "\t${GREEN}Did you mean: \"${NC}$(getConfigKey "botid")${GREEN}\" ?${NN}"
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 "\n"
fi
@ -293,16 +327,13 @@ fi
BASHBOT_RETRY="" # retry by default
URL="${BASHBOT_URL:-https://api.telegram.org/bot}${BOTTOKEN}"
ME_URL=$URL'/getMe'
UPD_URL=$URL'/getUpdates?offset='
GETFILE_URL=$URL'/getFile'
ME_URL=${URL}'/getMe'
#################
# BASHBOT COMMON functions
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 UPD BOTSENT USER MESSAGE URLS CONTACT LOCATION CHAT FORWARD REPLYTO VENUE iQUERY
@ -319,6 +350,7 @@ if [ -r "${COMMANDS}" ]; then
else
[ -z "${SOURCE}" ] && printf "${RED}Warning: ${COMMANDS} does not exist or is not readable!.${NN}"
fi
debug_checks "start SOURCE=${SOURCE:-no}" "$@"
###############
# load modules
@ -343,8 +375,8 @@ fi
# outputs final filename
download() {
local empty="no.file" file="${2:-${empty}}"
if [[ "$file" = *"/"* ]] || [[ "$file" = "."* ]]; then file="${empty}"; fi
while [ -f "${DATADIR:-.}/${file}" ] ; do file="$RAMDOM-${file}"; done
if [[ "${file}" = *"/"* ]] || [[ "${file}" = "."* ]]; then file="${empty}"; fi
while [ -f "${DATADIR:-.}/${file}" ] ; do file="${RANDOM}-${file}"; done
getJson "$1" >"${DATADIR:-.}/${file}" || return
printf '%s\n' "${DATADIR:-.}/${file}"
}
@ -373,69 +405,38 @@ killallproc() {
# shellcheck disable=SC2046
[ -n "${procid}" ] && kill $(proclist -9 "$1")
fi
debug_checks "end killallproc" "${1}"
debug_checks "end killallproc" "$1"
}
# $ chat $2 msg_id $3 nolog
declare -xr DELETE_URL=$URL'/deleteMessage'
declare -xr DELETE_URL=${URL}'/deleteMessage'
delete_message() {
[ -z "$3" ] && log_update "Delete Message CHAT=${1} MSG_ID=${2}"
sendJson "${1}" '"message_id": '"${2}"'' "${DELETE_URL}"
[ -z "$3" ] && log_update "Delete Message CHAT=$1 MSG_ID=$2"
sendJson "$1" '"message_id": '"$2"'' "${DELETE_URL}"
}
get_file() {
[ -z "$1" ] && return
sendJson "" '"file_id": "'"${1}"'"' "${GETFILE_URL}"
sendJson "" '"file_id": "'"$1"'"' "${URL}/getFile"
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
if ! _exists iconv; then
log_update "Warning: iconv not installed, pls imstall iconv!"
function iconv() { cat; }
fi
TIMEOUT="${BASHBOT_TIMEOUT}"
[[ "$TIMEOUT" =~ ^[0-9]+$ ]] || TIMEOUT="20"
TIMEOUT="${BASHBOT_TIMEOUT:-20}"
[[ "${TIMEOUT}" =~ ^[${o9o9o9}]+$ ]] || TIMEOUT="20"
# usage: sendJson "chat" "JSON" "URL"
sendJson(){
local json chat=""
if [ -n "${1}" ]; then
chat='"chat_id":'"${1}"','
[[ "${1}" == *[!0-9-]* ]] && chat='"chat_id":"'"${1}"' NAN",' # chat id not a number!
if [ -n "$1" ]; then
chat='"chat_id":'"$1"','
[[ "$1" == *[!${o9o9o9}-]* ]] && chat='"chat_id":"'"$1"' NAN",' # chat id not a number!
fi
# compose final json
json='{'"${chat} $(iconv -f utf-8 -t utf-8 -c <<<"$2")"'}'
@ -451,7 +452,7 @@ sendJson(){
fi
# OK here we go ...
# route to curl/wget specific function
res="$(sendJson_do "${json}" "${3}")"
res="$(sendJson_do "${json}" "$3")"
# check telegram response
sendJsonResult "${res}" "sendJson (${DETECTED_CURL})" "$@"
[ -n "${BASHBOT_EVENT_SEND[*]}" ] && event_send "send" "${@}" &
@ -463,8 +464,8 @@ sendJson(){
if detect_curl ; then
# here we have curl ----
[ -z "${BASHBOT_CURL}" ] && BASHBOT_CURL="curl"
# $1 URL, $2 hack: log getJson if not ""
getJson(){
[[ -n "${BASHBOTDEBUG}" && -n "${3}" ]] && log_debug "getJson (curl) URL=${1##*/}"
# shellcheck disable=SC2086
"${BASHBOT_CURL}" -sL -k ${BASHBOT_CURL_ARGS} -m "${TIMEOUT}" "$1"
}
@ -473,19 +474,19 @@ if detect_curl ; then
sendJson_do(){
# shellcheck disable=SC2086
"${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
sendUpload() {
[ "$#" -lt 4 ] && return
if [ -n "$5" ]; then
[ -n "${BASHBOTDEBUG}" ] &&\
log_update "sendUpload CHAT=${1} WHAT=${2} FILE=${3} CAPT=${5}"
# shellcheck disable=SC2086
[ -n "${BASHBOTDEBUG}" ] &&\
log_update "sendUpload CHAT=$1 WHAT=$2 FILE=$3 CAPT=$5"
# shellcheck disable=SC2086
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 )"
else
# shellcheck disable=SC2086
# shellcheck disable=SC2086
res="$("${BASHBOT_CURL}" -s -k ${BASHBOT_CURL_ARGS} "$4" -F "chat_id=$1"\
-F "$2=@$3;${3##*/}" | "${JSONSHFILE}" -b -n 2>/dev/null )"
fi
@ -496,7 +497,6 @@ else
# NO curl, try wget
if _exists wget; then
getJson(){
[[ -n "${BASHBOTDEBUG}" && -z "${3}" ]] && log_debug "getJson (wget) URL=${1##*/}"
# shellcheck disable=SC2086
wget --no-check-certificate -t 2 -T "${TIMEOUT}" ${BASHBOT_WGET_ARGS} -qO - "$1"
}
@ -504,8 +504,8 @@ else
# usage: "JSON" "URL"
sendJson_do(){
# shellcheck disable=SC2086
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
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
}
sendUpload() {
log_error "Sorry, wget does not support file upload"
@ -526,9 +526,9 @@ fi
# retry sendJson
# $1 function $2 sleep $3 ... $n arguments
sendJsonRetry(){
local retry="${1}"; shift
[[ "${1}" =~ ^\ *[0-9.]+\ *$ ]] && sleep "${1}"; shift
printf "%s: RETRY %s %s %s\n" "$(date)" "${retry}" "${1}" "${2:0:60}"
local retry="$1"; shift
[[ "$1" =~ ^\ *[${o9o9o9}.]+\ *$ ]] && sleep "$1"; shift
printf "%(%c)T: RETRY %s %s %s\n" -1 "${retry}" "$1" "${2:0:60}"
case "${retry}" in
'sendJson'*)
sendJson "$@"
@ -544,7 +544,7 @@ sendJsonRetry(){
return
;;
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}"
# process sendJson result
@ -553,19 +553,21 @@ sendJsonRetry(){
sendJsonResult(){
local offset=0
BOTSENT=( )
Json2Array 'UPD' <<<"$1"
[ -n "${BASHBOTDEBUG}" ] && log_message "New Result ==========\n$1"
BOTSENT[OK]="$(JsonGetLine '"ok"' <<< "${1}")"
BOTSENT[OK]="${UPD["ok"]}"
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
# hot path everything OK!
else
# oops something went wrong!
if [ "${1}" != "" ]; then
BOTSENT[ERROR]="$(JsonGetValue '"error_code"' <<< "${1}")"
BOTSENT[DESCRIPTION]="$(JsonGetString '"description"' <<< "${1}")"
grep -qs -F '"parameters","retry_after"' <<< "${1}" &&\
BOTSENT[RETRY]="$(JsonGetValue '"parameters","retry_after"' <<< "${1}")"
if [ -n "$1" ]; then
BOTSENT[ERROR]="${UPD["error_code"]}"
BOTSENT[DESCRIPTION]="${UPD["description"]}"
[ -n "${UPD["parameters","retry_after"]}" ] && BOTSENT[RETRY]="${UPD["parameters","retry_after"]}"
else
BOTSENT[OK]="false"
BOTSENT[ERROR]="999"
@ -574,8 +576,8 @@ sendJsonResult(){
# log error
[[ "${BOTSENT[ERROR]}" = "400" && "${BOTSENT[DESCRIPTION]}" == *"starting at byte offset"* ]] &&\
offset="${BOTSENT[DESCRIPTION]%* }"
printf "%s: RESULT=%s FUNC=%s CHAT[ID]=%s ERROR=%s DESC=%s ACTION=%s\n" "$(date)"\
"${BOTSENT[OK]}" "${2}" "${3}" "${BOTSENT[ERROR]}" "${BOTSENT[DESCRIPTION]}" "${4:${offset}:100}"
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}"
# warm path, do not retry on error, also if we use wegt
[ -n "${BASHBOT_RETRY}${BASHBOT_WGET}" ] && return
@ -583,8 +585,8 @@ sendJsonResult(){
# throttled, telegram say we send too many messages
if [ -n "${BOTSENT[RETRY]}" ]; then
BASHBOT_RETRY="$(( ++BOTSENT[RETRY] ))"
printf "Retry %s in %s seconds ...\n" "${2}" "${BASHBOT_RETRY}"
sendJsonRetry "${2}" "${BASHBOT_RETRY}" "${@:3}"
printf "Retry %s in %s seconds ...\n" "$2" "${BASHBOT_RETRY}"
sendJsonRetry "$2" "${BASHBOT_RETRY}" "${@:3}"
unset BASHBOT_RETRY
return
fi
@ -592,12 +594,12 @@ sendJsonResult(){
if [ "${BOTSENT[ERROR]}" == "999" ];then
# check if default curl and args are OK
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
if _exec_if_function bashbotBlockRecover; then
BASHBOT_RETRY="2"
printf "bashbotBlockRecover returned true, retry %s ...\n" "${2}"
sendJsonRetry "${2}" "${BASHBOT_RETRY}" "${@:3}"
printf "bashbotBlockRecover returned true, retry %s ...\n" "$2"
sendJsonRetry "$2" "${BASHBOT_RETRY}" "${@:3}"
unset BASHBOT_RETRY
fi
return
@ -605,9 +607,9 @@ sendJsonResult(){
# are not blocked, default curl and args are working
if [ -n "${BASHBOT_CURL_ARGS}" ] || [ "${BASHBOT_CURL}" != "curl" ]; then
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=""
sendJsonRetry "${2}" "${BASHBOT_RETRY}" "${@:3}"
sendJsonRetry "$2" "${BASHBOT_RETRY}" "${@:3}"
unset BASHBOT_RETRY
fi
fi
@ -636,7 +638,7 @@ title2Json(){
# get bot name and id from telegram
getBotName() {
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
# save botname and id
setConfigKey "botname" "${BOTARRAY["result","username"]}"
@ -647,15 +649,14 @@ getBotName() {
# pure bash implementation, done by KayM (@gnadelwartz)
# see https://stackoverflow.com/a/55666449/9381171
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})(.*)'
while [[ "${out}" =~ $regexp ]] ; do
while [[ "${out}" =~ ${regexp} ]] ; do
U=$(( ( (0xd${BASH_REMATCH[2]} & 0x3ff) <<10 ) | ( 0xd${BASH_REMATCH[3]} & 0x3ff ) + 0x10000 ))
remain="$(printf '\\U%8.8x' "${U}")${BASH_REMATCH[4]}${remain}"
out="${BASH_REMATCH[1]}"
done
#printf "%b\n" "${out}${remain}" # seems to work ... dealyed to next dev
echo -e "${out}${remain}"
printf "%b\n" "${out}${remain}"
}
JsonGetString() {
@ -675,7 +676,7 @@ process_updates() {
max="$(grep -F ',"update_id"]' <<< "${UPDATE}" | tail -1 | cut -d , -f 2 )"
Json2Array 'UPD' <<<"${UPDATE}"
for ((num=0; num<=max; num++)); do
process_client "$num" "${debug}"
process_client "${num}" "${debug}"
done
}
@ -698,12 +699,12 @@ process_client() {
MESSAGE[0]="/_edited_message "
fi
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]})"\
"${MESSAGE:0:30}${CAPTION:0:30}${URLS[*]:0:30}" >>"${UPDATELOG}"
else
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}"
fi
#####
@ -723,7 +724,7 @@ process_client() {
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
start_timer(){
@ -737,7 +738,7 @@ start_timer(){
EVENT_SEND="0"
event_send() {
# 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
for key in "${!BASHBOT_EVENT_SEND[@]}"
do
@ -753,7 +754,7 @@ event_timer() {
for key in "${!BASHBOT_EVENT_TIMER[@]}"
do
timer="${key##*,}"
[[ ! "$timer" =~ ^-*[1-9][0-9]*$ ]] && continue
[[ ! "${timer}" =~ ^-*[1-9][0-9]*$ ]] && continue
if [ "$(( EVENT_TIMER % timer ))" = "0" ]; then
_exec_if_function "${BASHBOT_EVENT_TIMER[${key}]}" "timer" "${key}" "${debug}"
[ "$(( EVENT_TIMER % timer ))" -lt "0" ] && \
@ -845,7 +846,7 @@ event_message() {
}
pre_process_message(){
local num="${1}"
local num="$1"
# unset everything to not have old values
CMD=( ); iQUERY=( ); MESSAGE=(); CHAT=(); USER=(); CONTACT=(); LOCATION=(); unset CAPTION
REPLYTO=( ); FORWARD=( ); URLS=(); VENUE=( ); SERVICE=( ); NEWMEMBER=( ); LEFTMEMBER=( ); PINNED=( ); MIGRATE=( )
@ -858,7 +859,7 @@ pre_process_message(){
return 0
}
process_inline() {
local num="${1}"
local num="$1"
iQUERY[0]="$(JsonDecode "${UPD["result",${num},"inline_query","query"]}")"
iQUERY[USER_ID]="${UPD["result",${num},"inline_query","from","id"]}"
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
declare -A BASHBOTBLOCKED
export BASHBOT_UPDATELOG="${BASHBOT_UPDATELOG-nolog}" # allow to be ""
start_bot() {
local DEBUGMSG OFFSET=0
# adaptive sleep defaults
@ -1017,9 +1017,9 @@ start_bot() {
DEBUGMSG="Start BASHBOT updates in Mode \"${1:-normal}\" =========="
log_update "${DEBUGMSG}"
# redirect to Debug.log
[[ "${1}" == *"debug" ]] && exec &>>"${DEBUGLOG}"
log_debug "${DEBUGMSG}"; DEBUGMSG="${1}"
[[ "${DEBUGMSG}" == "xdebug"* ]] && set -x && unset BASHBOT_UPDATELOG
[[ "$1" == *"debug" ]] && exec &>>"${DEBUGLOG}"
log_debug "${DEBUGMSG}"; DEBUGMSG="$1"
[[ "${DEBUGMSG}" == "xdebug"* ]] && set -x
# cleaup old pipes and empty logfiles
find "${DATADIR}" -type p -delete
find "${DATADIR}" -size 0 -name "*.log" -delete
@ -1033,7 +1033,7 @@ start_bot() {
# start timer events
if [ -n "${BASHBOT_START_TIMER}" ] ; then
# shellcheck disable=SC2064
trap "event_timer $DEBUGMSG" ALRM
trap "event_timer ${DEBUGMSG}" ALRM
start_timer &
# shellcheck disable=SC2064
trap "kill -9 $!; exit" EXIT INT HUP TERM QUIT
@ -1042,7 +1042,7 @@ start_bot() {
jssh_deleteKeyDB "CLEAN_COUNTER_DATABASE_ON_STARTUP" "${COUNTFILE}"
[ -f "${COUNTFILE}.jssh.flock" ] && rm -f "${COUNTFILE}.jssh.flock"
# 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"
# read blocked users
jssh_readDB_async "BASHBOTBLOCKED" "${BLOCKEDFILE}"
@ -1054,7 +1054,7 @@ start_bot() {
# adaptive sleep in ms rounded to next 0.1 s
sleep "$(_round_float "${nextsleep}e-3" "1")"
# 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?
if [ -n "${UPDATE}" ]; then
# 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++))
if [ "$OFFSET" != "1" ]; then
if [ "${OFFSET}" != "1" ]; then
nextsleep="100"
process_updates "${DEBUGMSG}"
fi
@ -1091,7 +1091,7 @@ start_bot() {
# initialize bot environment, user and permissions
bot_init() {
[ -n "${BASHBOT_HOME}" ] && cd "${BASHBOT_HOME}" || exit 1
local DEBUG="$1"
local runuser chown touser botname DEBUG="$1"
# upgrade from old version
# currently no action
printf "Check for Update actions ...\n"
@ -1103,24 +1103,37 @@ bot_init() {
[ -r "${addons}" ] && source "${addons}" "init" "${DEBUG}"
done
printf "Done.\n"
# setup bashbot
[[ "${UID}" -eq "0" ]] && RUNUSER="nobody"
printf "Enter User to run bashbot [$RUNUSER]: "
read -r TOUSER
[ -z "$TOUSER" ] && TOUSER="$RUNUSER"
if ! id "$TOUSER" &>/dev/null; then
printf "${RED}User \"$TOUSER\" not found!${NN}"
# ask for bashbot user
runuser="${RUNUSER}"; [ "${UID}" = "0" ] && runuser="nobody"
printf "Enter User to run bashbot [${runuser}]: "
read -r chown
[ -z "${chown}" ] && chown="${runuser}"; touser="${chown%:*}"
# check user ...
if ! id "${touser}" &>/dev/null; then
printf "${RED}User \"${touser}\" does not exist!${NN}"
exit 3
else
printf "Adjusting files and permissions for user \"${TOUSER}\" ...\n"
[ -w "bashbot.rc" ] && sed -i '/^[# ]*runas=/ s/runas=.*$/runas="'$TOUSER'"/' "bashbot.rc"
chmod 711 .
chmod -R o-w ./*
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 -R "$TOUSER" . ./*
elif [[ "${UID}" != "0" && "${touser}" != "${runuser}" ]]; then
# different user but not root ...
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
[ -n "${INTERACTIVE}" ] && read -r runuser
fi
# adjust permissions
printf "Adjusting files and permissions for user \"${touser}\" ...\n"
chmod 711 .
chmod -R o-w ./*
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"
fi
# ask to check bottoken online
@ -1135,7 +1148,7 @@ bot_init() {
# check if botconf seems valid
printf "${GREEN}This is your bot config:${NN}"
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"
read -r ANSWER
if [[ -z "${ANSWER}" || "${ANSWER}" =~ ^[^Nn] ]]; then
@ -1167,7 +1180,7 @@ if [ -z "${SOURCE}" ]; then
##############
# internal options only for use from bashbot and developers
# shellcheck disable=SC2221,SC2222
case "${1}" in
case "$1" in
# update botname when starting only
"botname"|"start"*)
ME="$(getBotName)"
@ -1179,7 +1192,7 @@ if [ -z "${SOURCE}" ]; then
else
printf "${GREY}Info: Can't get Botname from Telegram, try cached one ...${NN}"
ME="$(getConfigKey "botname")"
if [ -z "$ME" ]; then
if [ -z "${ME}" ]; then
printf "${RED}ERROR: No cached botname, can't continue! ...${NN}"
exit 1
fi
@ -1194,7 +1207,7 @@ if [ -z "${SOURCE}" ]; then
ME="$(getConfigKey "botname")"
# read until terminated
while read -r line ;do
[ -n "$line" ] && send_message "$2" "$line"
[ -n "${line}" ] && send_message "$2" "${line}"
done
# cleanup datadir, keep logfile if not empty
rm -f -r "${DATADIR:-.}/$3"
@ -1248,7 +1261,7 @@ if [ -z "${SOURCE}" ]; then
BOTPID="$(proclist "${SESSION}")"
# shellcheck disable=SC2086
[ -n "${BOTPID}" ] && kill ${BOTPID}
nohup "$SCRIPT" "startbot" "$2" "${SESSION}" &>/dev/null &
nohup "${SCRIPT}" "startbot" "$2" "${SESSION}" &>/dev/null &
printf "Session Name: %s\n" "${SESSION}"
sleep 1
if [ -n "$(proclist "${SESSION}")" ]; then

View File

@ -13,7 +13,7 @@
# AUTHOR: KayM (gnadelwartz), kay@rrr.de
# 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
#
# USAGE: bashbot_stats.sh [-h|--help] [debug]
USAGE='bashbot_stats.sh [-h|--help] [debug]'
#
# DESCRIPTION: output bashbot user stats
#
@ -16,14 +16,14 @@
# AUTHOR: KayM (gnadelwartz), kay@rrr.de
# CREATED: 23.12.2020 20:34
#
#### $$VERSION$$ v1.21-0-gc85af77
#### $$VERSION$$ v1.30-0-g3266427
#===============================================================================
####
# parse args
case "$1" in
"-h"*)
echo "usage: send_message [-h|--help] [debug]"
printf "usage: %s\n" "${USAGE}"
exit 1
;;
'--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
#===============================================================================
# shellcheck disable=SC2059
#
# 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
# --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)
# message - message to send in specified format
@ -24,13 +27,13 @@
# AUTHOR: KayM (gnadelwartz), kay@rrr.de
# 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
MINCOUNT=2
USERDB=""
####
# broadcast is dangerous, without --doit we do a dry run ...
@ -49,13 +52,18 @@ elif [ "$1" = "--groups" ]; then
SENDTO="groups"
GROUPSALSO=" only"
shift
elif [ "$1" = "--db" ]; then
USERDB="${2%.jssh}"
MINCOUNT=""
GROUPSALSO=" and groups"
shift 2
fi
####
# parse args -----------------
SEND="send_message"
case "$1" in
"nor*"|"tex*")
"nor"*|"tex"*)
SEND="send_normal_message"
shift
;;
@ -71,11 +79,11 @@ case "$1" in
printf "missing missing arguments\n"
;&
"-h"*)
printf 'usage: send_message [-h|--help] [--groups|--both] [format] "message ...." [debug]\n'
printf 'usage: %s\n' "${USAGE}"
exit 1
;;
'--h'*)
sed -n '3,/###/p' <"$0"
sed -n -e '/# shellcheck /d' -e '3,/###/p' <"$0"
exit 1
;;
esac
@ -85,15 +93,16 @@ esac
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
jssh_readDB_async "SENDALL" "${COUNTFILE}"
jssh_readDB_async "SENDALL" "${database}"
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
# 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
[ -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
[[ ! "${USER}" =~ ^[0-9-]*$ ]] && continue
# 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++ ))
if [ -z "${DOIT}" ]; then
printf "${SEND} ${USER} $1 $2\n"

View File

@ -3,11 +3,11 @@
#
# 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
#
# 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
# MESSAGE[ID] - message to replace
# message - message to send in specified format
@ -22,14 +22,14 @@
# AUTHOR: KayM (gnadelwartz), kay@rrr.de
# CREATED: 23.12.2020 16:52
#
#### $$VERSION$$ v1.21-0-gc85af77
#### $$VERSION$$ v1.30-0-g3266427
#===============================================================================
####
# parse args
SEND="edit_normal_message"
case "$1" in
"nor*"|"tex*")
"nor"*|"tex"*)
SEND="edit_normal_message"
shift
;;
@ -37,15 +37,19 @@ case "$1" in
SEND="edit_markdownv2_message"
shift
;;
"html")
"htm"*)
SEND="edit_html_message"
shift
;;
"cap"*)
SEND="edit_message_caption"
shift
;;
'')
printf "missing arguments\n"
;&
"-h"*)
printf 'usage: send_edit_message [-h|--help] [format] "CHAT[ID]" "MESSAGE[ID]" "message ..." [debug]\n'
printf 'usage: %s\n' "${USAGE}"
exit 1
;;
'--h'*)
@ -54,10 +58,9 @@ case "$1" in
;;
esac
# set bashbot environment
# 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
#
# 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
#
# 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
# URL - send an URL instead local file
#
# caption - message to send with file
# type - photo, video, sticker, voice, document (optional)
#
# -h - display short help
# --help - this help
@ -21,18 +24,18 @@
# AUTHOR: KayM (gnadelwartz), kay@rrr.de
# CREATED: 25.12.2020 20:24
#
#### $$VERSION$$ v1.21-0-gc85af77
#### $$VERSION$$ v1.30-0-g3266427
#===============================================================================
####
# parse args
SEND="upload_file"
SEND="send_file"
case "$1" in
'')
printf "missing arguments\n"
;&
"-h"*)
printf 'usage: send_file [-h|--help] "CHAT[ID]" "file" "caption ...." [debug]\n'
printf 'usage: %s\n' "${USAGE}"
exit 1
;;
'--h'*)
@ -43,7 +46,7 @@ esac
# set bashbot environment
# 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 -----
@ -54,10 +57,11 @@ else
fi
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}" "${CHAT}" "${FILE}" "$3"
"${SEND}" "${CHAT}" "${FILE}" "$3" "$4"
# output send message result
jssh_printDB "BOTSENT" | sort -r

View File

@ -3,7 +3,7 @@
#
# 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
#
@ -21,14 +21,14 @@
# AUTHOR: KayM (gnadelwartz), kay@rrr.de
# CREATED: 16.12.2020 11:34
#
#### $$VERSION$$ v1.21-0-gc85af77
#### $$VERSION$$ v1.30-0-g3266427
#===============================================================================
####
# parse args
SEND="send_message"
case "$1" in
"nor*"|"tex*")
"nor"*|"tex"*)
SEND="send_normal_message"
shift
;;
@ -44,7 +44,7 @@ case "$1" in
printf "missing arguments\n"
;&
"-h"*)
printf 'usage: send_message [-h|--help] [format] "CHAT[ID]" "message ...." [debug]\n'
printf 'usage: %s\n' "${USAGE}"
exit 1
;;
'--h'*)
@ -55,7 +55,7 @@ esac
# set bashbot environment
# 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 -----

View File

@ -15,11 +15,10 @@
# This file is public domain in the USA and all free countries.
# 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.
# https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment
# bashbot locale defaults to c.UTF-8, adjust locale in mycommands.sh if needed
export 'LC_ALL=C.UTF-8'
export 'LANG=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
if [ -n "${1}" ]; then
if [ -n "$1" ]; then
# load all readable modules
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
[ -r "${modules}" ] && source "${modules}" "${1}"
[ -r "${modules}" ] && source "${modules}" "$1"
fi
done
fi
@ -73,13 +72,13 @@ export FILE_REGEX="${BASHBOT_ETC}/.*"
# load mycommands
# 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....
# 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
_exec_if_function myinlines

View File

@ -5,17 +5,11 @@
#
# 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,
# no matter from which directory we'll run script
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
#shellcheck disable=SC1090
source "${0%/*}/dev.inc.sh"
##########################
# create test environment
@ -52,7 +46,7 @@ do
"${test}" "${TESTENV}"
ret=$?
set +e
if [ "$ret" -eq 0 ] ; then
if [ "${ret}" -eq 0 ] ; then
printf "OK: ---- %s\n" "${test}"
passed=$((passed+1))
else
@ -64,7 +58,7 @@ done
###########################
# cleanup depending on test state
if [ "$fail" -eq 0 ]; then
if [ "${fail}" -eq 0 ]; then
printf 'SUCCESS '
exitcode=0
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"
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
#### $$VERSION$$ v1.21-0-gc85af77
#### $$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
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
#shellcheck disable=SC1090
source "${0%/*}/dev.inc.sh"
[ ! -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
[ -d "${file}" ] && continue
printf "%s" "${file} "
git add "$file"
done
printf " - Done.\n"
# stay with "." for (re)moved files!
git add .

View File

@ -1,5 +1,5 @@
#!/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!
@ -7,7 +7,7 @@
# magic to ensure that we're always inside the root of our application,
# no matter from which directory we'll run script
GIT_DIR=$(git rev-parse --git-dir)
cd "$GIT_DIR/.." || exit 1
cd "${GIT_DIR}/.." || exit 1
export HOOKDIR="dev/hooks"
LASTPUSH='.git/.lastcommit'

View File

@ -1,5 +1,5 @@
#!/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!
@ -7,7 +7,7 @@
# magic to ensure that we're always inside the root of our application,
# no matter from which directory we'll run script
GIT_DIR=$(git rev-parse --git-dir)
cd "$GIT_DIR/.." || exit 1
cd "${GIT_DIR}/.." || exit 1
export HOOKDIR="dev/hooks"
LASTPUSH='.git/.lastpush'
@ -32,9 +32,9 @@ set +f
FILES="$(find ./* -name '*.sh' | grep -v -e 'DIST\/' -e 'STANDALONE\/' -e 'JSON.sh')"
set -f
FILES="${FILES} $(sed '/^#/d' <"dev/shellcheck.files")"
if [ "$FILES" != "" ]; then
if [ "${FILES}" != "" ]; then
# shellcheck disable=SC2086
shellcheck -x ${FILES} || exit 1
shellcheck -o all -e SC2249,SC2154 -x ${FILES} || exit 1
printf " OK\n............................\n"
else
# something went wrong

View File

@ -1,5 +1,5 @@
#!/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!
@ -7,7 +7,7 @@
# magic to ensure that we're always inside the root of our application,
# no matter from which directory we'll run script
GIT_DIR=$(git rev-parse --git-dir)
cd "$GIT_DIR/.." || exit 1
cd "${GIT_DIR}/.." || exit 1
export HOOKDIR="dev/hooks"
LASTPUSH='.git/.lastpush'

View File

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

View File

@ -1,16 +1,10 @@
#!/usr/bin/env bash
# this has to run once atfer git clone
# 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,
# no matter from which directory we'll run script
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
#shellcheck disable=SC1090
source "${0%/*}/dev.inc.sh"
HOOKDIR="dev/hooks"
@ -19,7 +13,7 @@ for hook in pre-commit post-commit pre-push
do
rm -f "${GIT_DIR}/hooks/${hook}"
if [ -f "${HOOKDIR}/${hook}.sh" ]; then
printf "%s"" $hook"
printf "%s"" ${hook}"
ln -s "../../${HOOKDIR}/${hook}.sh" "${GIT_DIR}/hooks/${hook}"
fi
done

View File

@ -7,25 +7,20 @@
#
# 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,
# no matter from which directory we'll run script
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
#shellcheck disable=SC1090
source "${0%/*}/dev.inc.sh"
VERSION="$(git describe --tags | sed -e 's/-[0-9].*//' -e 's/v//')"
DISTNAME="telegram-bot-bash"
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"
DISTMKDIR="data-bot-bash logs bin bin/logs addons"
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!
for test in $1 dev/all-test*.sh
@ -47,6 +42,7 @@ cp -r ${DISTFILES} "${DISTDIR}"
cd "${DISTDIR}" || exit 1
printf "Create directories\n"
# shellcheck disable=SC2250
for dir in $DISTMKDIR
do
[ ! -d "${dir}" ] && mkdir "${dir}"
@ -54,15 +50,15 @@ done
# do not overwrite on update
printf "Create .dist files\n"
for file in mycommands.sh bashbot.rc addons/*.sh
for file in ${DISTFILESDIST}
do
[ "${file}" = "addons/*.sh" ] && continue
mv "${file}" "${file}.dist"
cp "${BASE_DIR}/${file}" "${file}.dist"
done
# inject JSON.sh into distribution
# shellcheck disable=SC1090
source "$GIT_DIR/../dev/inject-json.sh"
source "${BASE_DIR}/dev/inject-json.sh"
# make html doc
printf "Create html doc\n"
@ -73,13 +69,13 @@ source "../../dev/make-html.sh"
cd .. || exit 1
printf "Create dist archives\n"
# shellcheck disable=SC2046
zip -rq - "${DISTNAME}" --exclude $(cat "$GIT_DIR/../dev/${0##*/}.exclude") >"${DISTNAME}-${VERSION}.zip"
tar --exclude-ignore="$GIT_DIR/../dev/${0##*/}.exclude" -czf "${DISTNAME}-${VERSION}.tar.gz" "${DISTNAME}"
zip -rq - "${DISTNAME}" --exclude $(cat "${BASE_DIR}/dev/${0##*/}.exclude") >"${DISTNAME}-${VERSION}.zip"
tar --exclude-ignore="${BASE_DIR}/dev/${0##*/}.exclude" -czf "${DISTNAME}-${VERSION}.tar.gz" "${DISTNAME}"
printf "%s Done!\n" "$0"
# shellcheck disable=SC2086
ls -ld ${DISTNAME}-${VERSION}.*
ls -ld "${DISTNAME}-${VERSION}".*
# 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/*
JSON.awk
bashbot.rc
mycommands.sh
awk-patch.sh
*.jssh*
botacl

View File

@ -7,7 +7,7 @@
#
# Usage: source make-hmtl
#
#### $$VERSION$$ v1.21-0-gc85af77
#### $$VERSION$$ v1.30-0-g3266427
##############################################################
# check for correct dir
@ -28,16 +28,17 @@ else
cp README.html html/index.html
# convert *.md files in doc to *.hmtl in html
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
if [ -d "examples" ]; then
EXAMPLES="examples" # add to final conversion job
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
# final: convert links from *.md to *.html
# shellcheck disable=SC2248
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"
fi
fi

View File

@ -6,38 +6,43 @@
# Description:
# 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
# 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,
# no matter from which directory we'll run script
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
[ ! -f "bashbot.sh" ] && printf "bashbot.sh not found in %s\n" " $(pwd)" && exit 1
fi
#shellcheck disable=SC1090
source "${0%/*}/dev.inc.sh"
[ ! -f "bashbot.sh" ] && printf "bashbot.sh not found in %s\n" " $(pwd)" && exit 1
#DISTNAME="telegram-bot-bash"
DISTDIR="./STANDALONE/${DISTNAME}"
DISTFILES="bashbot.sh bashbot.rc commands.sh mycommands.sh dev/obfuscate.sh modules scripts logs LICENSE README.* doc botacl botconfig.jssh"
DISTDIR="./STANDALONE"
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
dev/hooks/pre-commit.sh
[ "$1" != "--notest" ] && dev/hooks/pre-commit.sh
# create dir for distribution and copy files
printf "Create directories and copy files\n"
mkdir -p "${DISTDIR}" 2>/dev/null
# shellcheck disable=SC2086
cp -r ${DISTFILES} "${DISTDIR}" 2>/dev/null
cd "${DISTDIR}" || exit 1
# shellcheck disable=SC2250
for dir in $DISTMKDIR
do
[ ! -d "${dir}" ] && mkdir "${dir}"
done
# inject JSON.sh into distribution
# shellcheck disable=SC1090
source "$GIT_DIR/../dev/inject-json.sh"
source "${BASE_DIR}/dev/inject-json.sh"
#######################
# here the magic starts
@ -66,7 +71,7 @@ printf "\n... create unified bashbot.sh\n"
{
# 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
printf '\n##############################\n# bashbot modules starts here ...\n'
@ -95,7 +100,7 @@ chmod +x bashbot.sh.min
# make html doc
printf "Create html doc\n"
#shellcheck disable=SC1090
source "$GIT_DIR/../dev/make-html.sh"
source "${BASE_DIR}/dev/make-html.sh"
printf "%s Done!\n" "$0"

View File

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

View File

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

View File

@ -1,6 +1,6 @@
#!/bin/bash
#
#### $$VERSION$$ v1.21-0-gc85af77
#### $$VERSION$$ v1.30-0-g3266427
# shellcheck disable=SC2016
#
# Easy Versioning in git:
@ -34,14 +34,8 @@
# run this script to (re)place Version number in files
#
# magic to ensure that we're always inside the root of our application,
# no matter from which directory we'll run script
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
#shellcheck disable=SC1090
source "${0%/*}/dev.inc.sh"
unset IFS
# 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 ./*)"
[ "$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
[ ! -f "${file}" ] && continue
#[ "${file}" == "version" ] && continue
printf "%s" " ${file}" >&2
sed -i 's/^#### $$VERSION$$.*/#### \$\$VERSION\$\$ '"${VERSION}"'/' "${file}"
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"

View File

@ -2,7 +2,7 @@
## 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.
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'
# 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
bash --version | grep "bash"
@ -23,58 +23,60 @@ bash --version | grep "bash"
## Install bashbot
1. Go to the directory you want to install bashbot, e.g.
* 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.
Installing bashbot is very simple: Download and extract the installation archive.
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 ...
**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
**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.
* your $HOME directory
* /usr/local
2. [Download latest release zip / tar archive from github](https://github.com/topkecleon/telegram-bot-bash/releases/latest)
**Important: All files may overwritten, make a backup!**
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](https://github.com/topkecleon/telegram-bot-bash/releases/latest)
3. Stop all running instances of bashbot `./bashbot.sh stop`
4. Extract all files to your existing bashbot dir
5. Run `sudo ./bashbot.sh init` to setup your environment after the update
4. Change to parent directory of bashbot installation and extract all files from archive.
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.
Now you can restart your bashbot instances.
`mycommands.conf` and `mycommands.sh` will not overwritten, this avoids losing your bot config and commands on updates.
*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.
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) ).
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
After you have checked that 'JSON.awk.dist' is working correct on your system copy it to `JSON.awk` and (re)start bashbot.
Note: If you are not using the zip / tar archive, you must install `JSON.awk` manually into the same directory as 'JSON.sh`:
*Note*: To install or update `JSON.awk` manually execute the following commands in the directory `JSON.sh/`:
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
bash patch-for-busybox-awk.sh
chmod +x JSON.awk
### 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`.
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
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`.
@ -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_)
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 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
@ -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/)
**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
or use the script: ```examples/bash2env *.sh */*.sh``` to convert them for you.
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.
Bashbot will stay with /bin/bash shebang, as using a fixed path is more secure than the portable /usr/bin/env variant, see
[Security Considerations](../README.md#Security-Considerations)
Bashbot will stay with `#!/bin/bash` shebang, as using a fixed path is IMHO more secure than the portable '!/usr/bin/env bash` variant.
I considered to make bashbot BSD sed compatible, but much of the bashbot "magic" relies on
(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,
Compatibility with BSD/MacOS 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)
to get an impression how different they are.
### 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
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!
#### [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)
#### [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.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
├── 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
│   ├── send_message.sh # send message to 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_file.sh # send file to given chat
│   ├── 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
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
@ -252,14 +256,19 @@ they contain the following variables only:
* `${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.
[Advanced Usage](3_advanced.md)
After every `send_xxx` `get_xxx` call the array BOTSENT contains the most important values from Telegram response.
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[OK]}`: contains the string `true`: after a successful transmission
* `${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
@ -314,9 +323,10 @@ send_message "${CHAT[ID]}" "lol" "safe"
#### 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
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:
```bash
@ -341,5 +351,5 @@ send_action "${CHAT[ID]}" "action"
#### [Prev Create Bot](1_firstbot.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
'/start'*)
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
bot_help "${CHAT[ID]}"
else
@ -171,7 +172,7 @@ All output of the script will be sent to the user, to stop a background job use:
```bash
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
./bashbot.sh suspendback
./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)
#### [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
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:
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
export 'LC_ALL=C.UTF-8'
@ -31,11 +31,67 @@ export 'LANGUAGE=de_DE.UTF-8'
```bash
export 'LC_ALL=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 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'`
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
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 :
```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`.
- 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
@ -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:
```bash
# fist Hello World
# first Hello World
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_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" ]'
@ -202,10 +258,10 @@ This section describe how you can customize bashbot to your needs by setting env
#### 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'.
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.**
##### BASHBOT_ETC
@ -323,7 +379,7 @@ BASHBOT_TIMEOUT to a numeric value between 1 and 999. Any non numeric or negativ
##### BASHBOT_SLEEP
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.
```bash
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)
#### [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)
#### [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
##### send_file
send_file can send different type's of files, e.g. photos, stickers, audio, media, etc.
[see Telegram API documentation](https://core.telegram.org/bots/api#sending-files).
send_file can send local files, URL's or file_id's as different filex types (_e.g. photo video sticker_)
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 `../`
*usage:* send_file "${CHAT[ID]}" "file" "caption"
*example:*
```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"
# relative to UPLOADDIR: data-bot-bash/upload/dog.jpg
@ -201,7 +214,7 @@ _keyboard_numpad
----
##### send_button
*usage:* send_button "chat-id" "message" "text" "URL"
*usage:* send_button "$CHAT[ID]" "message" "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_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
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
@ -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
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
`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_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)*
##### 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:*
```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)
#### [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)
## 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).
@ -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:
```
"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"
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.
"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`
```
```
sometimes its useful to watch the bot live in the terminal:
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 it's useful to watch the bot live in the 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=""`
### 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.
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.
**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
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_MESSAGE` any of the following message types 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_REPLYTO` a reply to a message is received
* `BASHBOT_EVENT_FORWARD` a forwarded message is received
* `BASHBOT_EVENT_CONTACT` a contact is received
* `BASHBOT_EVENT_LOCATION` a location or a venue is received
* `BASHBOT_EVENT_FILE` a file is received
* `BASHBOT_EVENT_INLINE` an inline query is received
* `BASHBOT_EVENT_MESSAGE` any of the following message types 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_REPLYTO` a reply to a message is received
* `BASHBOT_EVENT_FORWARD` a forwarded message is received
* `BASHBOT_EVENT_CONTACT` a contact is received
* `BASHBOT_EVENT_LOCATION` a location or a venue is received
* `BASHBOT_EVENT_FILE` a file is received
*usage*: BASHBOT_EVENT_xxx[ "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 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:*
```bash
@ -168,8 +166,8 @@ BASHBOT_EVENT_TIMER["example_every5","5"]="example_every5min"
# execute once on the next 10 minutes since start "event"
BASHBOT_EVENT_TIMER["example_10min","-10"]="example_in10min"
# once in exact 10 minutes
BASHBOT_EVENT_TIMER["example_10min","$(( (EVENT_TIMER+10) * -1 ))"]="example_in10min"
# once in exact 10 minutes, note the -
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:
- 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 not needed commands and functions from `mycommands.sh`
- delete unused standard commands and messages from `commands.sh`
- delete unused commands and functions from `mycommands.sh`
- 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.
@ -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`
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/`.
To update the test installation, e.g. after git pull, local changes or switch master/develop, run `dev/make-distrubition.sh` again.
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-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/)
```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:
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.*
4. `dev/git-add.sh` - *check for changed files, update version string, run git add*
5. `git commit -m "COMMIT MESSAGE"; git push`
@ -254,6 +252,8 @@ data="$(cat file)" -> data="$(<"file")"
DIR="$(dirname $0) -> DIR="${0%/*}"
date -> printf"%(%c)T\n" -1 # 100 times faster!
PROG="($basename $0)" -> PROG="${0##*/}*
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 ))
INDEX="$(( ${INDEX} + 1 ))" -> (( INDEX++ ))
```
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
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.
@ -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.
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
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
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
@ -328,7 +356,7 @@ The file `ALL-tests.inc.sh` must be included from all tests and provide the test
ADMINFILE="botadmin"
DATADIR="data-bot-bash"
# SUCCESS NOSUCCES -> echo "${SUCCESS}" or echo "${NOSUCCESS}"
# SUCCESS NOSUCCESS -> echo "${SUCCESS}" or echo "${NOSUCCESS}"
SUCCESS=" OK"
NOSUCCESS=" FAILED!"
@ -358,5 +386,5 @@ fi
#### [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
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 ...
mycommands() {
case "$MESSAGE" in
case "${MESSAGE}" in
'/run_'*)
myback="run_${MESSAGE#*_}"
if [ -x "./${myback}.sh" ]; then
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."
background "./${myback}.sh" "${myback}"
else
@ -23,7 +23,7 @@ mycommands() {
myback="run_${MESSAGE#*_}"
if [ -x "./${myback}.sh" ]; then
checkback "${myback}"
if [ "$res" -eq 0 ] ; then
if [ "${res}" -eq 0 ] ; then
killback "${myback}"
send_normal_message "${CHAT[ID]}" "Stopping ${myback}, use /run_${myback} to start again."
else
@ -56,7 +56,7 @@ watch_dir_loop() {
echo "$(date): new file: ${newfile}" >>"$0.log"
# note: loop callback must a function in the calling script!
if _is_function loop_callback ; then
loop_callback "$1/$newfile"
loop_callback "$1/${newfile}"
else
echo "ERROR: loop_callback not found!" >&2
exit 1
@ -94,8 +94,8 @@ output_file() {
sed <<< "${1}" '
s/ *mynewlinestartshere */\n/
s/ my[a-z]\{3,15}\(start\|ends\)here.*//g
' >"$publish$$"
cat "$publish" >>"$publish$$"
' >"${publish}$$"
cat "${publish}" >>"${publish}$$"
mv "${publish}$$" "${publish}"
} # >>"$0.log" 2>&1

View File

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

View File

@ -2,7 +2,7 @@
# file: run_filename
# background job to display content of all new files in WATCHDIR
#
#### $$VERSION$$ v1.21-0-gc85af77
#### $$VERSION$$ v1.30-0-g3266427
######
# parameters
@ -40,4 +40,4 @@ loop_callback() {
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
# background job to display all new files in WATCHDIR
#
#### $$VERSION$$ v1.21-0-gc85af77
#### $$VERSION$$ v1.30-0-g3266427
######
# parameters
@ -38,5 +38,5 @@ loop_callback() {
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.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#### $$VERSION$$ v1.21-0-gc85af77
#### $$VERSION$$ v1.30-0-g3266427
######
# parameters
@ -25,15 +25,15 @@ unset IFS
cat >/dev/null &
# check if $1 is a number
re='^[0-9]+$'
if [[ $1 =~ $re ]] ; then
regex='^[0-9]+$'
if [[ "$1" =~ ${regex} ]] ; then
SLEEP="$1"
else
SLEEP=10 # time between time notifications
fi
# output current time every $1 seconds
while sleep $SLEEP
while sleep "${SLEEP}"
do
date "+* It's %k:%M:%S o' clock ..."
done

View File

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

View File

@ -2,14 +2,14 @@
# file. multibot.sh
# 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"
exit 1
fi
BOT="${1}"
BOT="$1"
[ "${#BOT}" -lt 5 ] && echo "Botname must have a minimum length of 5 characters" && exit 1
# where should the bots live?

View File

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

View File

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

View File

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

View File

@ -13,7 +13,7 @@
# This file is public domain in the USA and all free countries.
# 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
do
date "+* It's %k:%M:%S o'clock ..."
sleep $SLEEP
sleep "${SLEEP}"
done

View File

@ -10,7 +10,7 @@
# This file is public domain in the USA and all free countries.
# 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
# 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'
read -r answer <"${INPUT}"
case ${answer,,} in

View File

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

View File

@ -5,7 +5,7 @@
# to show how you can customize bashbot by only editing mycommands.sh
# NOTE: this is not tested, simply copied from original source and reworked!
#
#### $$VERSION$$ v1.21-0-gc85af77
#### $$VERSION$$ v1.30-0-g3266427
#
# shellcheck disable=SC2154
# shellcheck disable=SC2034
@ -38,7 +38,7 @@ mycommands() {
local msg=""
if user_is_botadmin "${USER[ID]}" || user_is_allowed "${USER[ID]}" "systemstatus"; then
case "$CMD" in
case "${CMD}" in
'/md'*) msg="$(cat /proc/mdstat)";;
'/smb'*) msg="$(smbstatus)" ;;
'/se'*) msg="$(sensors | sed -r 's/\s|\)+//g' | sed -r 's/\(high=|\(min=/\//' | sed -r 's/\,crit=|\,max=/\//')";;
@ -51,14 +51,14 @@ mycommands() {
'/smart'*)
[ "${CMD[1]}" == "" ] && msg="example \`/smart sda\`" && return
drive="$(echo "${CMD[1]}" | cut -c 1-3)"
echo "smartctl -a /dev/$drive"
msg="$(smartctl -a "/dev/$drive")"
echo "smartctl -a /dev/${drive}"
msg="$(smartctl -a "/dev/${drive}")"
;;
'/df') msg="$(df -h | sed -r 's/^/\n/' | sed -r 's/\s+/\n/g')";;
esac
if [ "$msg" != "" ]; then
send_normal_message "${CHAT[ID]}" "$msg"
if [ "${msg}" != "" ]; then
send_normal_message "${CHAT[ID]}" "${msg}"
fi
else
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.
# 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
@ -23,36 +23,36 @@ _is_creator() {
user_is_creator "${CHAT[ID]}" "${USER[ID]}"
}
_is_allowed() {
user_is_allowed "${USER[ID]}" "${1}" "${CHAT[ID]}"
user_is_allowed "${USER[ID]}" "$1" "${CHAT[ID]}"
}
_leave() {
leave_chat "${CHAT[ID]}"
}
_kick_user() {
kick_chat_member "${CHAT[ID]}" "${1}"
kick_chat_member "${CHAT[ID]}" "$1"
}
_unban_user() {
unban_chat_member "${CHAT[ID]}" "${1}"
unban_chat_member "${CHAT[ID]}" "$1"
}
# easy sending of messages of messages
_message() {
send_normal_message "${CHAT[ID]}" "${1}"
send_normal_message "${CHAT[ID]}" "$1"
}
_normal_message() {
send_normal_message "${CHAT[ID]}" "${1}"
send_normal_message "${CHAT[ID]}" "$1"
}
_html_message() {
send_html_message "${CHAT[ID]}" "${1}"
send_html_message "${CHAT[ID]}" "$1"
}
_markdown_message() {
send_markdown_message "${CHAT[ID]}" "${1}"
send_markdown_message "${CHAT[ID]}" "$1"
}
# easy handling of keyboards
_inline_button() {
send_inline_button "${CHAT[ID]}" "" "${1}" "${2}"
send_inline_button "${CHAT[ID]}" "" "$1" "$2"
}
_inline_keyboard() {
send_inline_keyboard "${CHAT[ID]}" "" "${1}"
send_inline_keyboard "${CHAT[ID]}" "" "$1"
}
_keyboard_numpad() {
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.
# 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
# source once magic, function named like file
eval "$(basename "${BASH_SOURCE[0]}")(){ :; }"
INLINE_QUERY=$URL'/answerInlineQuery'
answer_inline_query() {
answer_inline_multi "${1}" "$(shift; inline_query_compose "$RANDOM" "$@")"
answer_inline_multi "$1" "$(shift; inline_query_compose "${RANDOM}" "$@")"
}
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
@ -27,76 +26,76 @@ answer_inline_multi() {
# followed by the optional arguments: https://core.telegram.org/bots/api#inlinequeryresult
inline_query_compose(){
local JSON="{}"
local ID="${1}"
local ID="$1"
local fours last
# title2Json title caption description markup inlinekeyboard
case "${2}" in
case "$2" in
# user provided media
"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)
[ -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)
[ -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)
[ -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)
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)
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)
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)
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
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)
[ -z "$6" ] && addr="$5"
[ -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)
[ -n "$5" ] && last=',"last_name":"'$5'"'
[ -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
# Cached media stored in Telegram server
"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)
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)
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
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)
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)
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)
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)
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

View File

@ -6,7 +6,7 @@
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#
# shellcheck disable=SC1117,SC2059
#### $$VERSION$$ v1.21-0-gc85af77
#### $$VERSION$$ v1.30-0-g3266427
# will be automatically sourced from bashbot
@ -48,9 +48,9 @@ start_back() {
}
restart_back() {
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-"
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
}
@ -62,10 +62,10 @@ start_proc() {
[ -z "$2" ] && return
[ -x "${2%% *}" ] || return 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"
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" &
}
@ -99,7 +99,7 @@ kill_proc() {
fifo="$(procname "$1" "$2")"
prid="$(proclist "${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
[ -n "${prid}" ] && kill ${prid}
[ -s "${fifo}.log" ] || rm -f "${fifo}.log"
@ -127,7 +127,7 @@ job_control() {
local BOT ADM content proc CHAT job fifo killall=""
BOT="$(getConfigKey "botname")"
ADM="$(getConfigKey "botadmin")"
debug_checks "Enter job_control" "${1}"
debug_checks "Enter job_control" "$1"
for FILE in "${DATADIR:-.}/"*-back.cmd; do
[ "${FILE}" = "${DATADIR:-.}/*-back.cmd" ] && printf "${RED}No background processes.${NN}" && break
content="$(< "${FILE}")"
@ -136,7 +136,7 @@ job_control() {
proc="${job#*:}"
job="${job%:*}"
fifo="$(procname "${CHAT}" "${job}")"
debug_checks "Execute job_control" "${1}" "${FILE##*/}"
debug_checks "Execute job_control" "$1" "${FILE##*/}"
case "$1" in
"resumeb"*|"backgr"*)
printf "Restart Job: %s %s\n" "${proc}" " ${fifo##*/}"
@ -163,7 +163,7 @@ job_control() {
# send message only onnfirst job
ADM=""
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
[ "${killall}" = "y" ] && killallproc "back-"
}

View File

@ -5,36 +5,78 @@
# This file is public domain in the USA and all free countries.
# 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
# source once magic, function named like file
eval "$(basename "${BASH_SOURCE[0]}")(){ :; }"
LEAVE_URL=$URL'/leaveChat'
KICK_URL=$URL'/kickChatMember'
UNBAN_URL=$URL'/unbanChatMember'
GETMEMBER_URL=$URL'/getChatMember'
# manage chat functions -------
# $1 chat
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")"
# $1 chat # $2 user
get_chat_member_status() {
sendJson "$1" '"user_id":'"$2"'' "$GETMEMBER_URL"
sendJson "$1" '"user_id":'"$2"'' "${URL}/getChatMember"
# shellcheck disable=SC2154
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"
JsonGetString '"result","status"' <<< "${res}"
}
user_is_creator() {
@ -62,8 +104,8 @@ user_is_admin() {
user_is_botadmin() {
[ -z "$1" ] && return 1
local admin; admin="$(getConfigKey "botadmin")"; [ -z "${admin}" ] && return 1
[[ "${admin}" == "${1}" || "${admin}" == "${2}" ]] && return 0
#[[ "${admin}" = "@*" ]] && [[ "${admin}" = "${2}" ]] && return 0
[[ "${admin}" == "$1" || "${admin}" == "$2" ]] && return 0
#[[ "${admin}" = "@*" ]] && [[ "${admin}" = "$2" ]] && return 0
if [ "${admin}" = "?" ]; then setConfigKey "botadmin" "${1:-?}"; return 0; fi
return 1
}
@ -71,17 +113,18 @@ user_is_botadmin() {
# $1 user # $2 key # $3 chat
user_is_allowed() {
[ -z "$1" ] && return 1
user_is_admin "$1" && return 0
# user can do everything
grep -F -xq "$1:*:*" <"${BOTACL}" && return 0
grep -F -xq "$1:*:*" "${BOTACL}" && return 0
[ -z "$2" ] && return 1
# 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
grep -F -xq "ALL:$2:*" <"${BOTACL}" && return 0
grep -F -xq "ALL:$2:*" "${BOTACL}" && return 0
[ -z "$3" ] && return 1
# 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
grep -F -xq "ALL:$2:$3" <"${BOTACL}" && return 0
grep -F -xq "ALL:$2:$3" "${BOTACL}" && return 0
return 1
}

View File

@ -5,7 +5,7 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#
#### $$VERSION$$ v1.21-0-gc85af77
#### $$VERSION$$ v1.30-0-g3266427
#
# 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)
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
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
jssh_updateDB() {
# for atomic update we can't use read/writeDB
[ -z "${2}" ] && return 1
local DB="${2}.jssh" # check in async
[ -z "$2" ] && return 1
local DB="$2.jssh" # check in async
[ ! -f "${DB}" ] && return 2
{ 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
# renamed to be more consistent
jssh_insertKeyDB() {
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3
[[ "$1" =~ ^${JSSH_KEYOK}+$ ]] || return 3
local DB; DB="$(jssh_checkDB "$3")"
[ -z "${DB}" ] && return 1
[ ! -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 '..'
# medium complex slow, wrapper async
jssh_deleteKeyDB() {
[ -z "${2}" ] && return 1
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3
local DB="${2}.jssh"
[ -z "$2" ] && return 1
[[ "$1" =~ ^${JSSH_KEYOK}+$ ]] || return 3
local DB="$2.jssh"
# start atomic delete here, exclusive max wait 10s
{ 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 '..'
alias jssh_getDB=jssh_getKeyDB
jssh_getKeyDB() {
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3
[[ "$1" =~ ^${JSSH_KEYOK}+$ ]] || return 3
local DB; DB="$(jssh_checkDB "$2")"
[ -z "${DB}" ] && return 1
# start atomic delete here, exclusive max wait 1s
{ 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}"
}
@ -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
# complex, wrapper to async
jssh_countKeyDB() {
[ -z "${2}" ] && return 1
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3
local DB="${2}.jssh"
[ -z "$2" ] && return 1
[[ "$1" =~ ^${JSSH_KEYOK}+$ ]] || return 3
local DB="$2.jssh"
# start atomic delete here, exclusive max wait 5
{ 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 '..'
#no own locking, so async is the same as updatekeyDB
jssh_updateKeyDB() {
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3
[ -z "${3}" ] && return 1
[[ "$1" =~ ^${JSSH_KEYOK}+$ ]] || return 3
[ -z "$3" ] && return 1
declare -A updARR
# shellcheck disable=SC2034
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 '..'
@ -156,11 +178,11 @@ if [ "$(LC_ALL=C type -t "flock")" = "file" ]; then
# $3 id used to identify caller
# medium complex, wrapper async
jssh_updateArray() {
[ -z "${2}" ] && return 1
local DB="${2}.jssh" # name check in async
[ -z "$2" ] && return 1
local DB="$2.jssh" # name check in async
[ ! -f "${DB}" ] && return 2
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
@ -206,9 +228,9 @@ jssh_checkDB(){
[ -z "$1" ] && return 1
[[ "$1" = *'../.'* ]] && return 2
if [[ "$1" == "${BASHBOT_VAR:-.}"* ]] || [[ "$1" == "${BASHBOT_DATA:-.}"* ]]; then
DB="${1}.jssh"
DB="$1.jssh"
else
DB="${BASHBOT_VAR:-.}/${1}.jssh"
DB="${BASHBOT_VAR:-.}/$1.jssh"
fi
[ "${DB}" != ".jssh" ] && printf '%s' "${DB}"
}
@ -232,7 +254,7 @@ jssh_writeDB_async() {
}
jssh_updateDB_async() {
[ -z "${2}" ] && return 1
[ -z "$2" ] && return 1
declare -n ARRAY="$1"
[ -z "${ARRAY[*]}" ] && return 1
declare -A oldARR
@ -253,7 +275,7 @@ jssh_updateDB_async() {
jssh_insertDB_async() { jssh_insertKeyDB "$@"; }
jssh_insertKeyDB_async() {
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3
[[ "$1" =~ ^${JSSH_KEYOK}+$ ]] || return 3
local DB; DB="$(jssh_checkDB "$3")"
[ -z "${DB}" ] && return 1
[ ! -f "${DB}" ] && return 2
@ -263,7 +285,7 @@ jssh_insertKeyDB_async() {
}
jssh_deleteKeyDB_async() {
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3
[[ "$1" =~ ^${JSSH_KEYOK}+$ ]] || return 3
local DB; DB="$(jssh_checkDB "$2")"
[ -z "${DB}" ] && return 1
declare -A oldARR
@ -273,14 +295,14 @@ jssh_deleteKeyDB_async() {
}
jssh_getKeyDB_async() {
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3
[[ "$1" =~ ^${JSSH_KEYOK}+$ ]] || return 3
local DB; DB="$(jssh_checkDB "$2")"
[ -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() {
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3
[[ "$1" =~ ^${JSSH_KEYOK}+$ ]] || return 3
local VAL DB; DB="$(jssh_checkDB "$2")"
[ -z "${DB}" ] && return 1
# start atomic delete here, exclusive max wait 5
@ -291,7 +313,7 @@ jssh_countKeyDB_async() {
Array2Json "oldARR" >"${DB}"
elif [ -r "${DB}" ]; then
# 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}"
fi
}
@ -302,12 +324,12 @@ jssh_countKeyDB_async() {
# $3 filename (must exist!), must be relative to BASHBOT_ETC, and not contain '..'
#no own locking, so async is the same as updatekeyDB
jssh_updateKeyDB_async() {
[[ "$1" =~ ^[-a-zA-Z0-9,._]+$ ]] || return 3
[ -z "${3}" ] && return 1
[[ "$1" =~ ^${JSSH_KEYOK}+$ ]] || return 3
[ -z "$3" ] && return 1
declare -A updARR
# shellcheck disable=SC2034
updARR["$1"]="$2"
jssh_updateDB_async "updARR" "${3}" || return 3
jssh_updateDB_async "updARR" "$3" || return 3
}
jssh_clearDB_async() {
@ -321,7 +343,7 @@ function jssh_updateArray_async() {
[ -z "${DB}" ] && return 1
[ ! -f "${DB}" ] && return 2
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
Array2Json() {
[ -z "$1" ] && return 1
local key val
local key
declare -n ARRAY="$1"
for key in "${!ARRAY[@]}"
do
# in case val contains newline convert to \n
val="${ARRAY[${key}]//$'\n'/\\n}"
printf '["%s"]\t"%s"\n' "${key//,/\",\"}" "${val//\"/\\\"}"
[[ "${key}" =~ ^${JSSH_KEYOK}+$ ]] || continue
# in case value contains newline convert to \n
: "${ARRAY[${key}]//$'\n'/\\n}"
printf '["%s"]\t"%s"\n' "${key//,/\",\"}" "${_//\"/\\\"}"
done
}

View File

@ -6,7 +6,7 @@
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#
# shellcheck disable=SC1117
#### $$VERSION$$ v1.21-0-gc85af77
#### $$VERSION$$ v1.30-0-g3266427
# will be automatically sourced from bashbot
@ -15,19 +15,8 @@ eval "$(basename "${BASH_SOURCE[0]}")(){ :; }"
# source from commands.sh to use the sendMessage functions
MSG_URL=$URL'/sendMessage'
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'
MSG_URL=${URL}'/sendMessage'
EDIT_URL=${URL}'/editMessageText'
#
# send/edit message variants ------------------
@ -35,17 +24,17 @@ ALBUM_URL=$URL'/sendMediaGroup'
# $1 CHAT $2 message
send_normal_message() {
local len text; text="$(JsonEscape "${2}")"
local len text; text="$(JsonEscape "$2")"
text="${text//$'\n'/\\n}"
until [ -z "${text}" ]; do
if [ "${#text}" -le 4096 ]; then
sendJson "${1}" '"text":"'"${text}"'"' "${MSG_URL}"
sendJson "$1" '"text":"'"${text}"'"' "${MSG_URL}"
break
else
len=4095
[ "${text:4095:2}" != "\n" ] &&\
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))}"
fi
done
@ -53,48 +42,53 @@ send_normal_message() {
# $1 CHAT $2 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
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
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
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
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
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
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
# $1 CHAT $2 message $3 action $4 URL
_format_message_url(){
local text; text="$(JsonEscape "${2}")"
local text; text="$(JsonEscape "$2")"
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."
until [ -z "${text}" ]; do
sendJson "${1}" '"text":"'"${text:0:4096}"'"'"${3}"'' "${4}"
sendJson "$1" '"text":"'"${text:0:4096}"'"'"$3"'' "$4"
text="${text:4096}"
done
}
@ -102,13 +96,13 @@ _format_message_url(){
# internal function, send/edit markdownv2 message with URL
# $1 CHAT $2 message $3 action $4 URL
_markdownv2_message_url() {
local text; text="$(JsonEscape "${2}")"
local text; text="$(JsonEscape "$2")"
text="${text//$'\n'/\\n}"
[ "${#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!
text="$(sed -E -e 's|([_|~`>+=#{}()!.-])|\\\1|g' <<< "$text")"
text="$(sed -E -e 's|([_|~`>+=#{}()!.-])|\\\1|g' <<< "${text}")"
until [ -z "${text}" ]; do
sendJson "${1}" '"text":"'"${text:0:4096}"'"'"${3}"'' "${4}"
sendJson "$1" '"text":"'"${text:0:4096}"'"'"$3"'' "$4"
text="${text:4096}"
done
}
@ -121,61 +115,67 @@ _markdownv2_message_url() {
send_keyboard() {
if [[ "$3" != *'['* ]]; then old_send_keyboard "${@}"; return; fi
local text='"text":"'"Keyboard:"'"'
if [ -n "${2}" ]; then
text="$(JsonEscape "${2}")"
if [ -n "$2" ]; then
text="$(JsonEscape "$2")"
text='"text":"'"${text//$'\n'/\\n}"'"'
fi
local one_time=', "one_time_keyboard":true' && [ -n "$4" ] && one_time=""
sendJson "${1}" "${text}"', "reply_markup": {"keyboard": [ '"${3}"' ] '"${one_time}"'}' "$MSG_URL"
# '"text":"$2", "reply_markup": {"keyboard": [ ${3} ], "one_time_keyboard": true}'
sendJson "$1" "${text}"', "reply_markup": {"keyboard": [ '"$3"' ] '"${one_time}"'}' "${MSG_URL}"
# '"text":"$2", "reply_markup": {"keyboard": [ $3 ], "one_time_keyboard": true}'
}
# $1 CHAT $2 message $3 remove
remove_keyboard() {
local text='"text":"'"remove custom keyboard ..."'"'
if [ -n "${2}" ]; then
text="$(JsonEscape "${2}")"
if [ -n "$2" ]; then
text="$(JsonEscape "$2")"
text='"text":"'"${text//$'\n'/\\n}"'"'
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
[[ -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}'
}
# $1 CHAT $2 message $3 keyboard
send_inline_keyboard() {
local text; text='"text":"'$(JsonEscape "${2}")'"'; [ -z "${2}" ] && text='"text":"'"Keyboard:"'"'
sendJson "${1}" "${text}"', "reply_markup": {"inline_keyboard": [ '"${3}"' ]}' "$MSG_URL"
local text; text='"text":"'$(JsonEscape "$2")'"'; [ -z "$2" ] && text='"text":"'"Keyboard:"'"'
sendJson "$1" "${text}"', "reply_markup": {"inline_keyboard": [ '"$3"' ]}' "${MSG_URL}"
# JSON='"text":"$2", "reply_markup": {"inline_keyboard": [ $3->[{"text":"text", "url":"url"}]<- ]}'
}
# $1 CHAT $2 message $3 button text $4 URL
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
# there are no checks if URL or ID exists
# $1 chat $3 ... $n URL or ID
# only curl can send files ...
if detect_curl ; then
# there are no checks if URL or ID exists
# $1 chat $3 ... $n URL or ID
send_album(){
[ -z "${1}" ] && return 1
[ -z "${3}" ] && return 2 # minimum 2 files
local CHAT JSON IMAGE; CHAT="${1}"; shift
[ -z "$1" ] && return 1
[ -z "$3" ] && return 2 # minimum 2 files
local CHAT JSON IMAGE; CHAT="$1"; shift
for IMAGE in "$@"
do
[ -n "${JSON}" ] && JSON+=","
JSON+='{"type":"photo","media":"'${IMAGE}'"}'
done
# 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 )"
sendJsonResult "${res}" "send_album (curl)" "${CHAT}" "$@"
[[ -z "${SOURCE}" && -n "${BASHBOT_EVENT_SEND[*]}" ]] && event_send "album" "$@" &
}
else
send_album(){
log_error "Sorry, wget Album upload not yet implemented"
log_error "Sorry, wget Album upload not implemented"
BOTSENT[OK]="false"
[[ -z "${SOURCE}" && -n "${BASHBOT_EVENT_SEND[*]}" ]] && event_send "album" "$@" &
}
@ -183,88 +183,98 @@ fi
UPLOADDIR="${BASHBOT_UPLOAD:-${DATADIR}/upload}"
# for now this can only send local files with curl!
# extend to allow send files by URL or telegram ID
send_file() {
local err
upload_file "${@}"; err="$?"
# fake Telegram response to provide error
if [ "${err}" != "0" ]; 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]}"
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
# supports local file, URL and file_id
# $1 chat, $2 file https::// file_id:// , $3 caption, $4 extension (optional)
send_file(){
local url what num stat err media capt file="$2" ext="$4"
capt="$(JsonEscape "$3")"
if [[ "${file}" =~ ^https*:// ]]; then
media="URL"
elif [[ "${file}" == file_id://* ]]; then
media="ID"
file="${file#file_id://}"
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
[ ! -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)
CUR_URL="$VOICE_URL"
WHAT="voice"
STATUS="upload_audio"
# no type given, use file ext, if no ext type photo
if [ -z "${ext}" ]; then
ext="${file##*.}"
[ "${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"
;;
*)
CUR_URL="$DOCUMENT_URL"
WHAT="document"
STATUS="upload_document"
audio|mp3|flac)
url="${URL}/sendAudio"; what="audio"; stat="upload_audio"
;;
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
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() {
[ -z "$2" ] && return
sendJson "${1}" '"action": "'"${2}"'"' "$ACTION_URL" &
sendJson "$1" '"action": "'"$2"'"' "${URL}/sendChatAction" &
}
# $1 CHAT $2 lat $3 long
send_location() {
[ -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
@ -272,7 +282,7 @@ send_venue() {
local add=""
[ -z "$5" ] && return
[ -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
forward_message() {
[ -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_message "$@" || return
@ -293,50 +303,50 @@ forward() { # backward compatibility
send_message() {
[ -z "$2" ] && return
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
text="$(sed <<< "${text}" 's/ *mynewlinestartshere */\n/g')"
text="${text//$'\n'/\\n}"
[ "$3" != "safe" ] && {
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.*//')"
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')"
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.*//')"
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.*//')"
address="$(sed <<< "${2}" '/myaddressstartshere /!d;s/.*myaddressstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *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.*//')"
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')"
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.*//')"
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.*//')"
address="$(sed <<< "$2" '/myaddressstartshere /!d;s/.*myaddressstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')"
}
if [ -n "$no_keyboard" ]; then
remove_keyboard "$1" "$text"
if [ -n "${no_keyboard}" ]; then
remove_keyboard "$1" "${text}"
sent=y
fi
if [ -n "$keyboard" ]; then
if [[ "$keyboard" != *"["* ]]; then # pre 0.60 style
if [ -n "${keyboard}" ]; then
if [[ "${keyboard}" != *"["* ]]; then # pre 0.60 style
keyboard="[ ${keyboard//\" \"/\" \] , \[ \"} ]"
fi
send_keyboard "$1" "$text" "$keyboard"
send_keyboard "$1" "${text}" "${keyboard}"
sent=y
fi
if [ -n "$btext" ] && [ -n "$burl" ]; then
send_button "$1" "$text" "$btext" "$burl"
if [ -n "${btext}" ] && [ -n "${burl}" ]; then
send_button "$1" "${text}" "${btext}" "${burl}"
sent=y
fi
if [ -n "$file" ]; then
send_file "$1" "$file" "$text"
if [ -n "${file}" ]; then
send_file "$1" "${file}" "${text}"
sent=y
fi
if [ -n "$lat" ] && [ -n "$long" ]; then
if [ -n "$address" ] && [ -n "$title" ]; then
send_venue "$1" "$lat" "$long" "$title" "$address"
if [ -n "${lat}" ] && [ -n "${long}" ]; then
if [ -n "${address}" ] && [ -n "${title}" ]; then
send_venue "$1" "${lat}" "${long}" "${title}" "${address}"
else
send_location "$1" "$lat" "$long"
send_location "$1" "${lat}" "${long}"
fi
sent=y
fi
if [ "$sent" != "y" ];then
send_text_mode "$1" "$text"
if [ "${sent}" != "y" ];then
send_text_mode "$1" "${text}"
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
#########
#######################################################
#
# 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
#
# #### if you start to develop your own bot, use the clean version of this file:
# #### 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
#### $$VERSION$$ v1.21-0-gc85af77
#
# uncomment the following lines to overwrite info and help messages
# use ${ME} for current bot name in messages
# Note: you must escape '_' in botname with two \ in markdown messages!
export bashbot_info='This is @'"${ME//_/\\\\_}"', the Telegram example bot written entirely in bash.
Edit commands and messages in mycommands.sh!
'
# export bashbot_help='*Available commands*:
#'
export res=""
####################
# Config has moved to bashbot.conf
# shellcheck source=./commands.sh
[ -r "${BASHBOT_ETC:-.}/mycommands.conf" ] && source "${BASHBOT_ETC:-.}/mycommands.conf" "$1"
# 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
###################
# this section is processed on startup
@ -177,41 +124,45 @@ else
case "${MESSAGE}" in
##################
# 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
send_normal_message "${CHAT[ID]}" "$MESSAGE"
send_normal_message "${CHAT[ID]}" "${MESSAGE}"
;;
'/question'*) # start interactive questions
checkproc
if [ "$res" -gt 0 ] ; then
if [ "${res}" -gt 0 ] ; then
startproc "examples/question.sh" || send_normal_message "${CHAT[ID]}" "Can't start question."
else
send_normal_message "${CHAT[ID]}" "$MESSAGE already running ..."
send_normal_message "${CHAT[ID]}" "${MESSAGE} already running ..."
fi
;;
'/cancel'*) # cancel interactive command
checkproc
if [ "$res" -gt 0 ] ;then
if [ "${res}" -gt 0 ] ;then
killproc && send_normal_message "${CHAT[ID]}" "Command canceled."
else
send_normal_message "${CHAT[ID]}" "No command is currently running."
fi
;;
'/run_notify'*) # start notify background job
myback="notify"; checkback "$myback"
if [ "$res" -gt 0 ] ; then
background "examples/notify.sh 60" "$myback" || send_normal_message "${CHAT[ID]}" "Can't start notify."
myback="notify"; checkback "${myback}"
if [ "${res}" -gt 0 ] ; then
background "examples/notify.sh 60" "${myback}" || send_normal_message "${CHAT[ID]}" "Can't start notify."
else
send_normal_message "${CHAT[ID]}" "Background command $myback already running ..."
send_normal_message "${CHAT[ID]}" "Background command ${myback} already running ..."
fi
;;
'/stop_notify'*) # kill notify background job
myback="notify"; checkback "$myback"
if [ "$res" -eq 0 ] ; then
killback "$myback"
send_normal_message "${CHAT[ID]}" "Background command $myback canceled."
myback="notify"; checkback "${myback}"
if [ "${res}" -eq 0 ] ; then
killback "${myback}"
send_normal_message "${CHAT[ID]}" "Background command ${myback} canceled."
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
;;
@ -247,15 +198,15 @@ else
;;
"2"*) # two photos
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/4593242")
$(inline_query_compose "${RANDOM}" "photo" "https://avatars.githubusercontent.com/u/13046303"),
$(inline_query_compose "${RANDOM}" "photo" "https://avatars.githubusercontent.com/u/4593242")
"
;;
"3"*) # three photos
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/4593242")
$(inline_query_compose "$RANDOM" "photo" "https://avatars.githubusercontent.com/u/102707")
$(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/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")
answer_inline_multi "${iQUERY[ID]}" "
$(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)
"
;;
@ -283,7 +234,7 @@ else
# $1 current date, $2 from where the function was called, $3 ... $n optional information
my_debug_checks() {
# 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
@ -303,10 +254,10 @@ else
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=")"
while read -r image; do
[ "$count" -gt "20" ] && break
[ "${count}" -gt "20" ] && break
image="${image#* src=\'}"; image="${image%%&pid=*}"
[[ "${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 ))
done <<<"${result}"
}

View File

@ -1,66 +1,31 @@
#!/bin/bash
########
#######################################################
#
# File: mycommands.sh.clean
#
# files: mycommands.sh.clean
# 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
#
##########
# 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
# License: WTFPLv2 http://www.wtfpl.net/txt/copying/
# Author: KayM (gnadelwartz), kay@rrr.de
#
# 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
#### $$VERSION$$ v1.30-0-g3266427
#######################################################
# 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
###################
# this section is processed on startup
# run once after startup when the first message is received
my_startup(){
:
@ -94,7 +59,7 @@ else
##################
# example command, replace them by your own
'/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"
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
[ "$count" -gt "20" ] && break
[ "${count}" -gt "20" ] && break
image="${image#* src=\'}"; image="${image%%&pid=*}"
[[ "${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 ))
done <<<"${result}"
}

View File

@ -1,12 +1,19 @@
#!/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.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#
#### $$VERSION$$ v1.21-0-gc85af77
#### $$VERSION$$ v1.30-0-g3266427
########################################################################
######
# parameters

View File

@ -10,7 +10,7 @@
# LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/
# 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,

View File

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

View File

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

View File

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

View File

@ -10,7 +10,7 @@
# LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/
# AUTHOR: KayM (gnadelwartz), kay@rrr.de
#
#### $$VERSION$$ v1.21-0-gc85af77
#### $$VERSION$$ v1.30-0-g3266427
#===============================================================================
# include common functions and definitions
@ -24,7 +24,7 @@ TESTFILES="${TOKENFILE} ${ACLFILE} ${COUNTFILE} ${BLOCKEDFILE} ${ADMINFILE}"
# run bashbot first time with init
printf "Run bashbot init ...\n"
"${TESTDIR}/bashbot.sh" init >"${LOGFILE}" <<EOF
$TESTTOKEN
${TESTTOKEN}
nobody
botadmin
@ -46,7 +46,7 @@ trap exit 1 EXIT
cd "${TESTDIR}" || exit
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"
# shellcheck source=./bashbot.sh

View File

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

View File

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

View File

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

View File

@ -10,7 +10,7 @@
# LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/
# AUTHOR: KayM (gnadelwartz), kay@rrr.de
#
#### $$VERSION$$ v1.21-0-gc85af77
#### $$VERSION$$ v1.30-0-g3266427
#===============================================================================
# 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
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() {
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() {
#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
@ -51,18 +51,18 @@ printf " Send line ..."
# create dummy files for upload
ALLOW='/tmp/allowed'
FILE_REGEX="$ALLOW/.*"
[ -d "$ALLOW" ] || mkdir "$ALLOW"
touch "$ALLOW/this_is_my.gif" "$ALLOW/this_is_my.doc"
touch "$DATADIR/this_is_my.gif" "$DATADIR/this_is_my.doc"
FILE_REGEX="${ALLOW}/.*"
[ -d "${ALLOW}" ] || mkdir "${ALLOW}"
touch "${ALLOW}/this_is_my.gif" "${ALLOW}/this_is_my.doc"
touch "${DATADIR}/this_is_my.gif" "${DATADIR}/this_is_my.doc"
while read -r line ; do
set -x; set +e
send_message "123456" "$line" >>"${OUTPUTFILE}"
send_message "123456" "${line}" >>"${OUTPUTFILE}"
set +x; set -e
printf "."
done < "${INPUTFILE}" 2>>"${LOGFILE}"
[ -d "$ALLOW" ] && rm -rf "$ALLOW"
[ -d "${ALLOW}" ] && rm -rf "${ALLOW}"
printf " done.\n"

View File

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

View File

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