Merge pull request #98 from topkecleon/develop

Bashbot Version 0.76
This commit is contained in:
Kay Marquardt 2019-05-17 12:57:07 +02:00 committed by GitHub
commit 792dde9a91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 775 additions and 508 deletions

View File

@ -11,14 +11,15 @@
<div id="header">
<h1 class="title">Bashbot README</h1>
</div>
<h1 id="bashbot">bashbot</h1>
<p>A Telegram bot written in bash.</p>
<h2>
<img align="middle" src="https://raw.githubusercontent.com/odb/official-bash-logo/master/assets/Logos/Icons/PNG/64x64.png" > Bashbot - A Telegram bot written in bash.
</h2>
<p>Written by Drew (<span class="citation">@topkecleon</span>), Daniil Gentili (<span class="citation">@danogentili</span>), and Kay M (<span class="citation">@gnadelwartz</span>).</p>
<p>Contributions by JuanPotato, BigNerd95, TiagoDanin, and iicc1.</p>
<p>Released to the public domain wherever applicable. Elsewhere, consider it released under the <a href="http://www.wtfpl.net/txt/copying/">WTFPLv2</a>.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>Depends on <a href="http://github.com/tmux/tmux">tmux</a>. Uses <a href="http://github.com/dominictarr/JSON.sh">JSON.sh</a>.</p>
<p>Most complete <a href="doc/4_expert.md#Bashbot-UTF-8-Support">UTF-8 support for bashbot</a> is availible if phyton is installed (optional).</p>
<p>Even bashbot is written in bash, it depends on commands typically availible in a Unix/Linux Environment. More concret on the common commands provided by <a href="https://en.wikipedia.org/wiki/List_of_GNU_Core_Utilities_commands">coreutils</a>, <a href="https://en.wikipedia.org/wiki/BusyBox#Commands">busybox</a> or <a href="https://landley.net/toybox/help.html">toybox</a>, see <a href="doc/7_develop.md#common-commands">Developer Notes</a></p>
<p>Bashbot <a href="https://github.com/topkecleon/telegram-bot-bash">Documentation</a> and <a href="https://github.com/topkecleon/telegram-bot-bash/releases">Downloads</a> are availible on www.github.com</p>
<h2 id="documentation">Documentation</h2>
<ul>
@ -78,6 +79,9 @@
<li><a href="doc/8_custom.md">Customize bashbot environment</a></li>
<li><a href="examples/README.md">Examples</a></li>
</ul>
<h4 id="you-dont-like-the-many-bashbot-files">You dont like the many bashbot files?</h4>
<p>At the beginning bashbot was simply the file <code>bashbot.sh</code> I can copy everywhere and run the bot. Now we have commands.sh, mycommands.sh, modules/*.sh and much more.</p>
<p>Hey no Problem, if you are finished with your cool bot simply run <code>dev/make-standalone.sh</code> to create a stripped down Version containing only bashbot.sh and commands.sh! For more information see <a href="doc/7_develop.md">Create a stripped down Version of your Bot</a></p>
<h2 id="security-considerations">Security Considerations</h2>
<p>Running a Telegram Bot means it is connected to the public and you never know whats send to your Bot.</p>
<p>Bash scripts in general are not designed to be bullet proof, so consider this Bot as a proof of concept. Bash programmers often struggle with quoting hell and globbing, see <a href="https://unix.stackexchange.com/questions/171346/security-implications-of-forgetting-to-quote-a-variable-in-bash-posix-shells">Implications of wrong quoting</a></p>
@ -103,6 +107,6 @@
<p><span class="citation">@Gnadelwartz</span></p>
<h2 id="thats-it">Thats it!</h2>
<p>If you feel that theres something missing or if you found a bug, feel free to submit a pull request!</p>
<h4 id="version-v0.72-1-g67c47ac"><br /><span class="math display"><em>V</em><em>E</em><em>R</em><em>S</em><em>I</em><em>O</em><em>N</em></span><br /> v0.72-1-g67c47ac</h4>
<h4 id="version-v0.76-1-ge8a1fd0"><br /><span class="math display"><em>V</em><em>E</em><em>R</em><em>S</em><em>I</em><em>O</em><em>N</em></span><br /> v0.76-1-ge8a1fd0</h4>
</body>
</html>

View File

@ -1,6 +1,6 @@
# bashbot
A Telegram bot written in bash.
<h2><img align="middle" src="https://raw.githubusercontent.com/odb/official-bash-logo/master/assets/Logos/Icons/PNG/64x64.png" >
Bashbot - A Telegram bot written in bash.
</h2>
Written by Drew (@topkecleon), Daniil Gentili (@danogentili), and Kay M (@gnadelwartz).
Contributions by JuanPotato, BigNerd95, TiagoDanin, and iicc1.
@ -12,7 +12,9 @@ Elsewhere, consider it released under the [WTFPLv2](http://www.wtfpl.net/txt/cop
Depends on [tmux](http://github.com/tmux/tmux).
Uses [JSON.sh](http://github.com/dominictarr/JSON.sh).
Most complete [UTF-8 support for bashbot](doc/4_expert.md#Bashbot-UTF-8-Support) is availible if phyton is installed (optional).
Even bashbot is written in bash, it depends on commands typically availible in a Unix/Linux Environment.
More concret on the common commands provided by [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)
Bashbot [Documentation](https://github.com/topkecleon/telegram-bot-bash) and [Downloads](https://github.com/topkecleon/telegram-bot-bash/releases) are availible on www.github.com
@ -57,6 +59,13 @@ Bashbot [Documentation](https://github.com/topkecleon/telegram-bot-bash) and [Do
* [Customize bashbot environment](doc/8_custom.md)
* [Examples](examples/README.md)
#### You don't like the many bashbot files?
At the beginning bashbot was simply the file ```bashbot.sh``` I can 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 simply run ```dev/make-standalone.sh``` to create a stripped down Version containing only
'bashbot.sh' and 'commands.sh'! For more information see [Create a stripped down Version of your Bot](doc/7_develop.md)
## Security Considerations
Running a Telegram Bot means it is connected to the public and you never know whats send to your Bot.
@ -98,4 +107,4 @@ Well, thats a damn good question ... may be because I'm an Unix/Linux admin from
If you feel that there's something missing or if you found a bug, feel free to submit a pull request!
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0

View File

@ -1,6 +1,8 @@
# bashbot
A Telegram bot written in bash.
<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>
Written by Drew (@topkecleon), Daniil Gentili (@danogentili), and Kay M
(@gnadelwartz).
@ -14,9 +16,14 @@ Elsewhere, consider it released under the
Depends on [tmux](http://github.com/tmux/tmux).
Uses [JSON.sh](http://github.com/dominictarr/JSON.sh).
Most complete [UTF-8 support for
bashbot](doc/4_expert.md#Bashbot-UTF-8-Support) is availible if phyton is
installed (optional).
Even bashbot is written in bash, it depends on commands typically availible in
a Unix/Linux Environment.
More concret on the common commands provided by
[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)
Bashbot [Documentation](https://github.com/topkecleon/telegram-bot-bash) and
[Downloads](https://github.com/topkecleon/telegram-bot-bash/releases) are
@ -64,6 +71,17 @@ all](https://core.telegram.org/bots#3-how-do-i-create-a-bot)
* [Customize bashbot environment](doc/8_custom.md)
* [Examples](examples/README.md)
#### You don't like the many bashbot files?
At the beginning bashbot was simply the file ```bashbot.sh``` I can 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 simply run
```dev/make-standalone.sh``` to create a stripped down Version containing only
'bashbot.sh' and 'commands.sh'! For more information see [Create a stripped
down Version of your Bot](doc/7_develop.md)
## Security Considerations
Running a Telegram Bot means it is connected to the public and you never know
whats send to your Bot.
@ -137,4 +155,4 @@ health status
If you feel that there's something missing or if you found a bug, feel free to
submit a pull request!
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0

View File

@ -1,7 +1,7 @@
#!/bin/sh
# description: Start or stop telegram-bash-bot
#
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
# shellcheck disable=SC2009
# shellcheck disable=SC2181

View File

@ -12,7 +12,7 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
#
# Exit Codes:
# - 0 sucess (hopefully)
@ -32,6 +32,7 @@ if [ -t 1 ] && [ "$TERM" != "" ]; then
fi
# get location and name of bashbot.sh
export SCRIPT SCRIPTDIR MODULEDIR RUNDIR RUNUSER
SCRIPT="$0"
SCRIPTDIR="$(dirname "$0")"
MODULEDIR="${SCRIPTDIR}/modules"
@ -65,16 +66,6 @@ if [ ! -f "${TOKENFILE}" ]; then
fi
fi
JSONSHFILE="${BASHBOT_JSONSH:-${RUNDIR}/JSON.sh/JSON.sh}"
[[ "${JSONSHFILE}" != *"/JSON.sh" ]] && echo -e "${RED}ERROR: \"${JSONSHFILE}\" ends not with \"JSONS.sh\".${NC}" && exit 3
if [ ! -f "${JSONSHFILE}" ]; then
echo "Seems to be first run, Downloading ${JSONSHFILE}..."
[[ "${JSONSHFILE}" = "${RUNDIR}/JSON.sh/JSON.sh" ]] && mkdir "JSON.sh" 2>/dev/null;
curl -sL -o "${JSONSHFILE}" "https://cdn.jsdelivr.net/gh/dominictarr/JSON.sh/JSON.sh"
chmod +x "${JSONSHFILE}"
fi
BOTADMIN="${BASHBOT_ETC:-.}/botadmin"
if [ ! -f "${BOTADMIN}" ]; then
if [ "${CLEAR}" = "" ]; then
@ -118,33 +109,17 @@ elif [ ! -w "${COUNTFILE}" ]; then
fi
BOTTOKEN="$(cat "${TOKENFILE}")"
URL='https://api.telegram.org/bot'$BOTTOKEN
BOTTOKEN="$(< "${TOKENFILE}")"
URL="${BASHBOT_URL:-https://api.telegram.org/bot}${BOTTOKEN}"
MSG_URL=$URL'/sendMessage'
LEAVE_URL=$URL'/leaveChat'
KICK_URL=$URL'/kickChatMember'
UNBAN_URL=$URL'/unbanChatMember'
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'
ME_URL=$URL'/getMe'
DELETE_URL=$URL'/deleteMessage'
GETMEMBER_URL=$URL'/getChatMember'
UPD_URL=$URL'/getUpdates?offset='
GETFILE_URL=$URL'/getFile'
unset USER
declare -A BOTSENT USER MESSAGE URLS CONTACT LOCATION CHAT FORWARD REPLYTO VENUE
export BOTSENT USER MESSAGE URLS CONTACT LOCATION CHAT FORWARD REPLYTO VENUE
declare -A BOTSENT USER MESSAGE URLS CONTACT LOCATION CHAT FORWARD REPLYTO VENUE iQUERY
export res BOTSENT USER MESSAGE URLS CONTACT LOCATION CHAT FORWARD REPLYTO VENUE iQUERY CAPTION NAME
COMMANDS="${BASHBOT_ETC:-.}/commands.sh"
if [ "$1" != "source" ]; then
@ -159,116 +134,36 @@ if [ "$1" != "source" ]; then
fi
send_normal_message() {
local text="${2}"
until [ -z "${text}" ]; do
sendJson "${1}" '"text":"'"${text:0:4096}"'"' "${MSG_URL}"
text="${text:4096}"
done
# returns true if command exist
_exists()
{
[ "$(LC_ALL=C type -t "$1")" = "file" ]
}
send_markdown_message() {
local text="${2}"
until [ -z "${text}" ]; do
sendJson "${1}" '"text":"'"${text:0:4096}"'","parse_mode":"markdown"' "${MSG_URL}"
text="${text:4096}"
done
}
send_html_message() {
local text="${2}"
until [ -z "${text}" ]; do
sendJson "${1}" '"text":"'"${text:0:4096}"'","parse_mode":"html"' "${MSG_URL}"
text="${text:4096}"
done
# returns true if function exist
_is_function()
{
[ "$(LC_ALL=C type -t "$1")" = "function" ]
}
DELETE_URL=$URL'/deleteMessage'
delete_message() {
sendJson "${1}" 'message_id: '"${2}"'' "${DELETE_URL}"
}
# usage: status="$(get_chat_member_status "chat" "user")"
get_chat_member_status() {
sendJson "$1" 'user_id: '"$2"'' "$GETMEMBER_URL"
JsonGetString '"result","status"' <<< "$res"
get_file() {
[ "$1" = "" ] && return
local JSON='"file_id": '"${1}"
sendJson "" "${JSON}" "${GETFILE_URL}"
jsonGetString <<< "${URL}/""${res}" '"result","file_path"'
}
kick_chat_member() {
sendJson "$1" 'user_id: '"$2"'' "$KICK_URL"
# curl is preffered, but may not availible on ebedded systems
if [ "${BASHBOT_WGET}" = "" ] && _exists curl ; then
# simple curl or wget call, output to stdout
getJson(){
curl -sL "$1"
}
unban_chat_member() {
sendJson "$1" 'user_id: '"$2"'' "$UNBAN_URL"
}
leave_chat() {
sendJson "$1" "" "$LEAVE_URL"
}
user_is_creator() {
if [ "${1:--}" = "${2:-+}" ] || [ "$(get_chat_member_status "$1" "$2")" = "creator" ]; then return 0; fi
return 1
}
user_is_admin() {
local me; me="$(get_chat_member_status "$1" "$2")"
if [ "${me}" = "creator" ] || [ "${me}" = "administrator" ]; then return 0; fi
return 1
}
user_is_botadmin() {
local admin; admin="$(head -n 1 "${BOTADMIN}")"
[ "${admin}" = "${1}" ] && return 0
[[ "${admin}" = "@*" ]] && [[ "${admin}" = "${2}" ]] && return 0
if [ "${admin}" = "?" ]; then echo "${1:-?}" >"${BOTADMIN}"; return 0; fi
return 1
}
user_is_allowed() {
local acl="$1"
[ "$1" = "" ] && return 1
grep -F -xq "${acl}:*:*" <"${BOTACL}" && return 0
[ "$2" != "" ] && acl="${acl}:$2"
grep -F -xq "${acl}:*" <"${BOTACL}" && return 0
[ "$3" != "" ] && acl="${acl}:$3"
grep -F -xq "${acl}" <"${BOTACL}"
}
old_send_keyboard() {
local text='"text":"'"${2}"'"'
shift 2
local keyboard=init
OLDIFS=$IFS
IFS=$(echo -en "\"")
for f in "$@" ;do [ "$f" != " " ] && keyboard="$keyboard, [\"$f\"]";done
IFS=$OLDIFS
keyboard=${keyboard/init, /}
sendJson "${1}" "${text}"', "reply_markup": {"keyboard": [ '"${keyboard}"' ],"one_time_keyboard": true}' "$MSG_URL"
}
ISEMPTY="ThisTextIsEmptyAndWillBeDeleted"
send_keyboard() {
if [[ "$3" != *'['* ]]; then old_send_keyboard "$@"; return; fi
local text='"text":"'"${2}"'"'; [ "${2}" = "" ] && text='"text":"'"${ISEMPTY}"'"'
local one_time=', "one_time_keyboard":true' && [ "$4" != "" ] && one_time=""
sendJson "${1}" "${text}"', "reply_markup": {"keyboard": [ '"${3}"' ] '"${one_time}"'}' "$MSG_URL"
# '"text":"$2", "reply_markup": {"keyboard": [ ${3} ], "one_time_keyboard": true}'
}
remove_keyboard() {
local text='"text":"'"${2}"'"'; [ "${2}" = "" ] && text='"text":"'"${ISEMPTY}"'"'
sendJson "${1}" "${text}"', "reply_markup": {"remove_keyboard":true}' "$MSG_URL"
#JSON='"text":"$2", "reply_markup": {"remove_keyboard":true}'
}
send_inline_keyboard() {
local text='"text":"'"${2}"'"'; [ "${2}" = "" ] && text='"text":"'"${ISEMPTY}"'"'
sendJson "${1}" "${text}"', "reply_markup": {"inline_keyboard": [ '"${3}"' ]}' "$MSG_URL"
# JSON='"text":"$2", "reply_markup": {"inline_keyboard": [ $3->[{"text":"text", "url":"url"}]<- ]}'
}
send_button() {
send_inline_keyboard "${1}" "${2}" '[ {"text":"'"${3}"'", "url":"'"${4}"'"}]'
}
# usage: sendJson "chat" "JSON" "URL"
sendJson(){
local chat="";
@ -277,8 +172,22 @@ sendJson(){
-H "Content-Type: application/json" | "${JSONSHFILE}" -s -b -n )"
BOTSENT[OK]="$(JsonGetLine '"ok"' <<< "$res")"
BOTSENT[ID]="$(JsonGetValue '"result","message_id"' <<< "$res")"
[[ "${2}" = *"${ISEMPTY}"* ]] && delete_message "${1}" "${BOTSENT[ID]}"
}
else
# simple curl or wget call outputs result to stdout
getJson(){
wget -qO - "$1"
}
# usage: sendJson "chat" "JSON" "URL"
sendJson(){
local chat="";
[ "${1}" != "" ] && chat='"chat_id":'"${1}"','
res="$(wget -qO - --post-data='{'"${chat} $2"'}' \
--header='Content-Type:application/json' "${3}" | "${JSONSHFILE}" -s -b -n )"
BOTSENT[OK]="$(JsonGetLine '"ok"' <<< "$res")"
BOTSENT[ID]="$(JsonGetValue '"result","message_id"' <<< "$res")"
}
fi
# convert common telegram entities to JSON
# title caption description markup inlinekeyboard
@ -292,94 +201,37 @@ title2Json(){
echo "${title}${caption}${desc}${markup}${keyboard}"
}
get_file() {
[ "$1" = "" ] && return
local JSON='"file_id": '"${1}"
sendJson "" "${JSON}" "${GETFILE_URL}"
echo "${URL}/$(echo "${res}" | jsonGetString '"result","file_path"')"
# get bot name
getBotName() {
sendJson "" "" "$ME_URL"
JsonGetString '"result","username"' <<< "$res"
}
send_file() {
[ "$2" = "" ] && return
local CAPTION
local chat_id=$1
local file=$2
echo "$file" | grep -qE "$FILE_REGEX" || return
local ext="${file##*.}"
case $ext in
mp3|flac)
CUR_URL=$AUDIO_URL
WHAT=audio
STATUS=upload_audio
CAPTION="$3"
;;
png|jpg|jpeg|gif)
CUR_URL=$PHO_URL
WHAT=photo
STATUS=upload_photo
CAPTION="$3"
;;
webp)
CUR_URL=$STICKER_URL
WHAT=sticker
STATUS=
;;
mp4)
CUR_URL=$VIDEO_URL
WHAT=video
STATUS=upload_video
CAPTION="$3"
;;
ogg)
CUR_URL=$VOICE_URL
WHAT=voice
STATUS=
;;
*)
CUR_URL=$DOCUMENT_URL
WHAT=document
STATUS=upload_document
CAPTION="$3"
;;
esac
send_action "$chat_id" "$STATUS"
res="$(curl -s "$CUR_URL" -F "chat_id=$chat_id" -F "$WHAT=@$file" -F "caption=$CAPTION")"
# pure bash implementaion, done by KayM (@gnadelwartz)
# see https://stackoverflow.com/a/55666449/9381171
JsonDecode() {
local out="$1" remain="" U=""
local regexp='(.*)\\u[dD]([0-9a-fA-F]{3})\\u[dD]([0-9a-fA-F]{3})(.*)'
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
echo -e "${out}${remain}"
}
# 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
send_action() {
[ "$2" = "" ] && return
sendJson "${1}" '"action": "'"${2}"'"' "$ACTION_URL"
JsonGetString() {
sed -n -e '0,/\['"$1"'\]/ s/\['"$1"'\][ \t]"\(.*\)"$/\1/p'
}
JsonGetLine() {
sed -n -e '0,/\['"$1"'\]/ s/\['"$1"'\][ \t]//p'
}
JsonGetValue() {
sed -n -e '0,/\['"$1"'\]/ s/\['"$1"'\][ \t]\([0-9.,]*\).*/\1/p'
}
send_location() {
[ "$3" = "" ] && return
sendJson "${1}" '"latitude": '"${2}"', "longitude": '"${3}"'' "$LOCATION_URL"
}
send_venue() {
local add=""
[ "$5" = "" ] && return
[ "$6" != "" ] && add=', "foursquare_id": '"$6"''
sendJson "${1}" '"latitude": '"${2}"', "longitude": '"${3}"', "address": "'"${5}"'", "title": "'"${4}"'"'"${add}" "$VENUE_URL"
}
forward_message() {
[ "$3" = "" ] && return
sendJson "${1}" '"from_chat_id": '"${2}"', "message_id": '"${3}"'' "$FORWARD_URL"
}
forward() { # backward compatibility
forward_message "$@" || return
}
# returns true if function exist
_is_function()
{
[ "$(LC_ALL=C type -t "$1")" = "function" ]
}
################
# processing of updates starts here
process_updates() {
MAX_PROCESS_NUMBER="$(sed <<< "${UPDATE}" '/\["result",[0-9]*\]/!d' | tail -1 | sed 's/\["result",//g;s/\].*//g')"
for ((PROCESS_NUMBER=0; PROCESS_NUMBER<=MAX_PROCESS_NUMBER; PROCESS_NUMBER++)); do
@ -397,19 +249,19 @@ process_client() {
fi
# Tmux
copname="$ME"_"${CHAT[ID]}"
source "${COMMANDS}"
# shellcheck source=./commands.sh
source "${COMMANDS}" "$1"
tmpcount="COUNT${CHAT[ID]}"
grep -q "$tmpcount" <"${COUNTFILE}" >/dev/null 2>&1 || echo "$tmpcount">>"${COUNTFILE}"
# To get user count execute bash bashbot.sh count
}
JsonGetString() {
sed -n -e '0,/\['"$1"'\]/ s/\['"$1"'\][ \t]"\(.*\)"$/\1/p'
}
JsonGetLine() {
sed -n -e '0,/\['"$1"'\]/ s/\['"$1"'\][ \t]//p'
}
JsonGetValue() {
sed -n -e '0,/\['"$1"'\]/ s/\['"$1"'\][ \t]\([0-9.,]*\).*/\1/p'
process_inline() {
local num="${1}"
iQUERY[0]="$(JsonDecode "$(JsonGetString <<<"${UPDATE}" '"result",0,"inline_query","query"')")"
iQUERY[USER_ID]="$(JsonGetValue <<<"${UPDATE}" '"result",'"${num}"',"inline_query","from","id"')"
iQUERY[FIRST_NAME]="$(JsonDecode "$(JsonGetString <<<"${UPDATE}" '"result",'"${num}"',"inline_query","from","first_name"')")"
iQUERY[LAST_NAME]="$(JsonDecode "$(JsonGetString <<<"${UPDATE}" '"result",'"${num}"',"inline_query","from","last_name"')")"
iQUERY[USERNAME]="$(JsonDecode "$(JsonGetString <<<"${UPDATE}" '"result",'"${num}"',"inline_query","from","username"')")"
}
process_message() {
local num="$1"
@ -490,6 +342,8 @@ process_message() {
rm "$TMP"
}
#########################
# main get updates loop, should never terminate
start_bot() {
local DEBUG="$1"
@ -500,13 +354,12 @@ start_bot() {
[[ "${DEBUG}" = *"debug" ]] && exec &>>"DEBUG.log"
[ "${DEBUG}" != "" ] && date && echo "Start BASHBOT in Mode \"${DEBUG}\""
[[ "${DEBUG}" = "xdebug"* ]] && set -x
while true; do {
UPDATE="$(curl -s "$UPD_URL$OFFSET" | "${JSONSHFILE}" -s -b -n)"
while true; do
UPDATE="$(getJson "$UPD_URL$OFFSET" | "${JSONSHFILE}" -s -b -n)"
# Offset
OFFSET="$(grep <<< "${UPDATE}" '\["result",[0-9]*,"update_id"\]' | tail -1 | cut -f 2)"
OFFSET=$((OFFSET+1))
((OFFSET++))
if [ "$OFFSET" != "1" ]; then
mysleep="100"
@ -514,21 +367,23 @@ start_bot() {
fi
# adaptive sleep in ms rounded to next lower second
[ "${mysleep}" -gt "999" ] && sleep "${mysleep%???}"
mysleep=$((mysleep+addsleep)); [ "${mysleep}" -gt "${maxsleep}" ] && mysleep="${maxsleep}"
}
# bash aritmetic
((mysleep+= addsleep , mysleep= mysleep>maxsleep ?maxsleep:mysleep))
done
}
# initialize bot environment, user and permissions
bot_init() {
# move tmpdir to datadir
# upgrade from old version
local OLDTMP="${BASHBOT_VAR:-.}/tmp-bot-bash"
[ -d "${OLDTMP}" ] && { mv -n "${OLDTMP}/"* "${TMPDIR}"; rmdir "${OLDTMP}"; }
[ -f "modules/inline.sh" ] && rm -f "modules/inline.sh"
#setup bashbot
[[ "$(id -u)" -eq "0" ]] && RUNUSER="nobody"
echo -n "Enter User to run basbot [$RUNUSER]: "
read -r TOUSER
[ "$TOUSER" = "" ] && TOUSER="$RUNUSER"
if ! compgen -u "$TOUSER" >/dev/null 2>&1; then
if ! id "$TOUSER" >/dev/null 2>&1; then
echo -e "${RED}User \"$TOUSER\" not found!${NC}"
exit 3
else
@ -543,15 +398,19 @@ bot_init() {
fi
}
# get bot name
getBotName() {
sendJson "" "" "$ME_URL"
JsonGetString '"result","username"' <<< "$res"
}
JSONSHFILE="${BASHBOT_JSONSH:-${RUNDIR}/JSON.sh/JSON.sh}"
[[ "${JSONSHFILE}" != *"/JSON.sh" ]] && echo -e "${RED}ERROR: \"${JSONSHFILE}\" ends not with \"JSONS.sh\".${NC}" && exit 3
if [ ! -f "${JSONSHFILE}" ]; then
echo "Seems to be first run, Downloading ${JSONSHFILE}..."
[[ "${JSONSHFILE}" = "${RUNDIR}/JSON.sh/JSON.sh" ]] && mkdir "JSON.sh" 2>/dev/null && chmod +w "JSON.sh"
getJson "https://cdn.jsdelivr.net/gh/dominictarr/JSON.sh/JSON.sh" >"${JSONSHFILE}"
chmod +x "${JSONSHFILE}"
fi
ME="$(getBotName)"
if [ "$ME" = "" ]; then
if [ "$(cat "${TOKENFILE}")" = "bashbottestscript" ]; then
if [ "$(< "${TOKENFILE}")" = "bashbottestscript" ]; then
ME="bashbottestscript"
else
echo -e "${RED}ERROR: Can't connect to Telegram Bot! May be your TOKEN is invalid ...${NC}"
@ -559,30 +418,6 @@ if [ "$ME" = "" ]; then
fi
fi
# use phyton JSON to decode JSON UFT-8, provide bash implementaion as fallback
if [ "${BASHBOT_DECODE}" != "" ] && which python >/dev/null 2>&1 ; then
JsonDecode() {
printf '"%s\\n"' "${1//\"/\\\"}" | python -c 'import json, sys; sys.stdout.write(json.load(sys.stdin).encode("utf-8"))'
}
else
# pure bash implementaion, done by KayM (@gnadelwartz)
# see https://stackoverflow.com/a/55666449/9381171
JsonDecode() {
local out="$1"
local remain=""
local regexp='(.*)\\u[dD]([0-9a-fA-F]{3})\\u[dD]([0-9a-fA-F]{3})(.*)'
while [[ "${out}" =~ $regexp ]] ; do
# match 2 \udxxx hex values, calculate new U, then split and replace
local W1=$(( ( 0xd${BASH_REMATCH[2]} & 0x3ff) <<10 ))
local W2=$(( 0xd${BASH_REMATCH[3]} & 0x3ff ))
local U=$(( ( W1 | W2 ) + 0x10000 ))
remain="$(printf '\\U%8.8x' "${U}")${BASH_REMATCH[4]}${remain}"
out="${BASH_REMATCH[1]}"
done
echo -e "${out}${remain}"
}
fi
# source the script with source as param to use functions in other scripts
# do not execute if read from other scripts
@ -592,6 +427,8 @@ if [ "$1" != "source" ]; then
# internal options only for use from bashbot and developers
case "$1" in
"outproc") # forward output from interactive and jobs to chat
[ "$3" = "" ] && echo "No file to read from" && exit 3
[ "$2" = "" ] && echo "No chat to send to" && exit 3
until [ "$line" = "imprettydarnsuredatdisisdaendofdacmd" ];do
line=""
read -r -t 10 line
@ -637,12 +474,10 @@ if [ "$1" != "source" ]; then
tmux kill-session -t "$ME" &>/dev/null
tmux new-session -d -s "$ME" "bash $SCRIPT startbot" && echo -e "${GREEN}Bot started successfully.${NC}"
echo "Tmux session name $ME" || echo -e "${RED}An error occurred while starting the bot. ${NC}"
send_markdown_message "${CHAT[ID]}" "*Bot started*"
;;
"kill")
${CLEAR}
tmux kill-session -t "$ME" &>/dev/null
send_markdown_message "${CHAT[ID]}" "*Bot stopped*"
echo -e "${GREEN}OK. Bot stopped successfully.${NC}"
;;
"background" | "resumeback")

View File

@ -5,10 +5,8 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
#
# shellcheck disable=SC2154
# shellcheck disable=SC2034
# 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
@ -37,45 +35,40 @@ bashbot_help='*Available commands*:
Written by Drew (@topkecleon), Daniil Gentili (@danogentili) and KayM(@gnadelwartz).
Get the code in my [GitHub](http://github.com/topkecleon/telegram-bot-bash)
'
# we don't know whom we are ...
copname=""
if [ "${1}" != "source" ]; then
# load modules needed for commands.sh only
# load modues on startup and always on on debug
if [ "${1}" = "source" ] || [[ "${1}" = *"debug"* ]] ; then
# load all readable modules
for modules in ${MODULEDIR:-.}/*.sh ; do
# shellcheck source=./modules/aliases.sh
[ -r "${MODULEDIR:-.}/aliases.sh" ] && source "${MODULEDIR:-.}/aliases.sh"
# shellcheck source=./modules/background.sh
[ -r "${MODULEDIR:-.}/background.sh" ] && source "${MODULEDIR:-.}/background.sh"
else
# defaults to no inline and nonsense home dir
INLINE="0"
FILE_REGEX='/home/user/allowed/.*'
# load modules needed for bashbot.sh also
# shellcheck source=./modules/background.sh
[ -r "${MODULEDIR:-.}/inline.sh" ] && source "${MODULEDIR:-.}/inline.sh"
[ -r "${modules}" ] && source "${modules}" "${1}"
done
fi
# defaults to no inline and nonsense home dir
export INLINE="0"
export FILE_REGEX='/home/user/allowed/.*'
# load mycommands
# shellcheck source=./commands.sh
[ -r "${BASHBOT_ETC:-.}/mycommands.sh" ] && source "${BASHBOT_ETC:-.}/mycommands.sh" "${1}"
if [ "${1}" != "source" ];then
if ! tmux ls 2>/dev/null | grep -v send | grep -q "$copname"; then
# interactive running?
[ ! -z "${URLS[*]}" ] && {
curl -s "${URLS[*]}" -o "$NAME"
send_file "${CHAT[ID]}" "$NAME" "$CAPTION"
rm -f "$NAME"
}
[ ! -z "${LOCATION[*]}" ] && send_location "${CHAT[ID]}" "${LOCATION[LATITUDE]}" "${LOCATION[LONGITUDE]}"
fi
# detect inline commands....
# no default commands, all processing is done in myinlines()
if [ "$INLINE" != "0" ] && [ "${iQUERY[ID]}" != "" ]; then
if _is_function process_inline; then
# forward iinline query to optional dispatcher
_is_function myinlines && myinlines
fi
# regular (gobal) commands ...
# your commands are in mycommands()
else
case "${MESSAGE}" in

View File

@ -1,12 +1,16 @@
#!/usr/bin/env bash
# this has to run once atfer git clone
# and every time we create new hooks
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
# 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
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
if [ "$GIT_DIR" != "" ] ; then
cd "$GIT_DIR/.." || exit 1
else
echo "Sorry, no git repository $(pwd)" && exit 1
fi
# create test environment
TESTENV="/tmp/bashbot.test$$"

View File

@ -3,12 +3,16 @@
#
# works together with git pre-push.sh and ADD all changed files since last push
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
# 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)
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
if [ "$GIT_DIR" != "" ] ; then
cd "$GIT_DIR/.." || exit 1
else
echo "Sorry, no git repository $(pwd)" && exit 1
fi
[ ! -f .git/.lastpush ] && echo "No push or hooks not installed, use \"git add\" instead ... Abort" && exit

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
############
# NOTE: you MUST run install-hooks.sh again when updating this file!

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
############
# NOTE: you MUST run install-hooks.sh again when updating this file!

View File

@ -1,12 +1,16 @@
#!/usr/bin/env bash
# this has to run once atfer git clone
# and every time we create new hooks
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
# 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)
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
if [ "$GIT_DIR" != "" ] ; then
cd "$GIT_DIR/.." || exit 1
else
echo "Sorry, no git repository $(pwd)" && exit 1
fi
HOOKDIR="dev/hooks"

View File

@ -1,12 +1,17 @@
#!/usr/bin/env bash
# this has to run once atfer git clone
# and every time we create new hooks
#### $$VERSION$$ v0.72-1-g67c47ac
# file: make-distribution.sh
# creates files and arcchives to dirtribute bashbot
#
#### $$VERSION$$ v0.76-1-ge8a1fd0
# 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)
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
if [ "$GIT_DIR" != "" ] ; then
cd "$GIT_DIR/.." || exit 1
else
echo "Sorry, no git repository $(pwd)" && exit 1
fi
VERSION="$(git describe --tags | sed -e 's/-[0-9].*//' -e 's/v//')"
@ -18,6 +23,7 @@ DISTFILES="bashbot.rc bashbot.sh commands.sh mycommands.sh doc examples modu
for test in "dev/all-tests.sh"
do
[ ! -x ""${test} ] && continue
if ! "${test}" ; then
echo "Test ${test} failed, can't create dist!"
exit 1
@ -31,6 +37,7 @@ cp -r ${DISTFILES} "${DISTDIR}"
cd "${DISTDIR}" || exit 1
# additional stuff
mv "bashbot.rc" "bashbot.rc.dist"
mv "commands.sh" "commands.sh.dist"
mv "mycommands.sh" "mycommands.sh.dist"

91
dev/make-standalone.sh Executable file
View File

@ -0,0 +1,91 @@
#!/usr/bin/env bash
# file: make-standalone.sh
# even after make-distribution.sh bashbot is not self contained as it was in the past.
#
# If you your bot is finished you can use make-standalone.sh to create the
# the old all-in-one bashbot: bashbot.sh and commands.sh only!
#
#### $$VERSION$$ v0.76-1-ge8a1fd0
# 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
[ ! -f "bashbot.sh" ] && echo "bashbot.sh not found in $(pwd)" && exit 1
fi
#DISTNAME="telegram-bot-bash"
DISTDIR="./standalone/${DISTNAME}"
DISTFILES="bashbot.sh commands.sh mycommands.sh modules LICENSE README.txt token count botacl botadmin"
# run tests first!
for test in "dev/all-tests.sh"
do
[ ! -x "${test}" ] && continue
if ! "${test}" ; then
echo "Test ${test} failed, can't create standalone!"
exit 1
fi
done
# create dir for distribution and copy files
mkdir -p "${DISTDIR}" 2>/dev/null
# shellcheck disable=SC2086
cp -r ${DISTFILES} "${DISTDIR}" 2>/dev/null
cd "${DISTDIR}" || exit 1
#######################
# here the magic starts
# create all in one bashbot.sh file
echo "OK, noe lets do the magic ..."
echo " ... create unified commands.sh"
{
# first head of commands.sh
sed -n '0,/^if / p' commands.sh | head -n -2 | grep -v 'mycommands.sh'
# then mycommands from first non comment line on
printf '\n##############################\n# my commands starts here ...\n'
sed -n '/^$/,$ p' mycommands.sh
# last tail of commands.sh
printf '\n##############################\n# default commands starts here ...\n'
sed -n '/\/mycommands.sh"/,$ p' commands.sh | tail -n +2
} >>$$commands.sh
mv $$commands.sh commands.sh
rm -f mycommands.sh
echo " ... create unified bashbot.sh"
{
# first head of bashbot.sh
sed -n '0,/\/commands.sh"/ p' bashbot.sh | head -n -2
# then mycommands from first non comment line on
printf '\n##############################\n# bashbot modules starts here ...\n'
cat modules/*.sh | sed -e 's/^#\!\/bin\/bash.*//'
# last tail of commands.sh
printf '\n##############################\n# bashbot internal functions starts here ...\n\n'
sed -n '/\/commands.sh"/,$ p' bashbot.sh
} >>$$bashbot.sh
mv $$bashbot.sh bashbot.sh
chmod +x bashbot.sh
rm -rf modules
echo "Done!"
cd .. || exit 1
echo -e "\\nStandalone bashbot files are now availible in \"${DISTDIR}\":\\n"
ls -l "${DISTDIR}"*

View File

@ -1,3 +1,3 @@
# list of additional files to check from shellcheck
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
bashbot.rc

View File

@ -1,6 +1,6 @@
#!/bin/bash
#
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
# shellcheck disable=SC2016
#
# Easy Versioning in git:
@ -36,8 +36,12 @@
# 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)
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
if [ "$GIT_DIR" != "" ] ; then
cd "$GIT_DIR/.." || exit 1
else
echo "Sorry, no git repository $(pwd)" && exit 1
fi
unset IFS
# set -f # if you are paranoid use set -f to disable globbing

View File

@ -34,13 +34,20 @@ As an alternative to download the zip files, you can clone the github repository
2. [Download latest release zip from github](https://github.com/topkecleon/telegram-bot-bash/releases)
3. Extract all files to your existing bashbot dir
**Note: all files execpt 'mycommands.sh' and 'commands.sh' may overwritten!**
4. Run ```sudo ./bashbot.sh init``` to setup your environment after the update
4. Save your your current 'commands.sh' and run ```cp commands.sh.dist commands.sh```
5. Run ```sudo ./bashbot.sh init``` to setup your environment after the update
If you modified 'commands.sh' re apply all changes to the new 'commands.sh'. To avoid this all your modifications
must be done in 'mycommands.sh' only.
### Notes on Updates
#### Location of tmp / data dir
From version 0.70 on the tmp dir is renamed to 'data-bot-bash' to reflect the fact that not only temporary files are stored. an existing 'tmp-bot-bash' will be automatically renamed after update.
From version 0.60 on your commands must be placed in 'mycommands.sh'. If you update from a version with your commands
in 'commands.sh' move all your commands and functions to 'mycommands.sh'.
From version 0.50 on the temporary files are no more placed in '/tmp'. instead a dedicated tmp dir is used.
#### Changes to send_keyboard in v0.6
@ -63,5 +70,5 @@ The old format is supported for backward compatibility, but may fail for corner
#### [Next Create Bot](1_firstbot.md)
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0

View File

@ -65,5 +65,5 @@ group. This step is up to you actually.
#### [Prev Installation](0_install.md)
#### [Next Getting started](2_usage.md)
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0

View File

@ -182,5 +182,5 @@ send_action "${CHAT[ID]}" "action"
#### [Prev Create Bot](1_firstbot.md)
#### [Next Advanced Usage](3_advanced.md)
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0

View File

@ -180,5 +180,5 @@ See also [answer_inline_multi, answer_inline_compose](6_reference.md#answer_inli
#### [Prev Getting started](2_usage.md)
#### [Next Expert Use](4_expert.md)
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0

View File

@ -104,5 +104,5 @@ An example crontab is provided in ```examples/bashbot.cron```.
#### [Prev Expert Use](4_expert.md)
#### [Next Best Practice](5_practice.md)
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0

View File

@ -153,5 +153,5 @@ The second warning is about an unused variable, this is true because in our exam
#### [Prev Best Practice](5_practice.md)
#### [Next Functions Reference](6_reference.md)
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0

View File

@ -592,5 +592,5 @@ Send Input from Telegram to waiting Interactive Chat.
#### [Prev Best Practice](5_practice.md)
#### [Next Notes for Developers](7_develop.md)
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0

View File

@ -4,7 +4,7 @@ This section is about help and best practices for new bashbot developers. The ma
bashbot development is done on github. If you want to provide fixes or new features [fork bashbot on githup](https://help.github.com/en/articles/fork-a-repo) and provide changes as [pull request on github](https://help.github.com/en/articles/creating-a-pull-request).
### Debuging Bashbot
### Debugging Bashbot
In normal mode of operation all bashbot output is discarded one more correct sent to TMUX console.
To get these messages (and more) you can start bashbot in the current shell ```./bashbot.sh startbot```. Now you can see all output or erros from bashbot.
In addition you can change the change the level of verbosity by adding a third argument after startbot.
@ -16,7 +16,19 @@ In addition you can change the change the level of verbosity by adding a third a
"xdebugterm" same as xdebug but output and errors are sent to terminal
```
### Create a stripped down Version of your Bot
Currently bashbot is more a bot development environment than a bot, containing examples, developer scripts, modules, documentation and more.
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'
- run ```dev/make-standalone.sh``` to create a a stripped down version of your bo
Now have a look at the directory 'standalone', here you find the files 'bashbot.sh' and 'commands.sh' containing everything to run your bot.
[Download make-standalone.sh](https://github.com/topkecleon/telegram-bot-bash/blob/master/dev/make-standalone.sh) from github.
### Setup your develop environment
@ -39,6 +51,49 @@ A typical bashbot develop loop looks as follow:
**If you setup your dev environment with hooks and use the scripts above, versioning, addding and testing is done automatically.**
### common commands
We state bashbot is a bash only bot, but this is not true. bashbot is a bash script using bash features PLUS external commands.
Usually bash is used in a unix/linux environment where many (GNU) commands are availible, but if commands are missing, bashbot may not work.
To avoid this and make bashbot working on as many platforms as possible - from embedded linux to mainframe - I recommed to restrict
ourself to the common commands provided by bash and coreutils/busybox/toybox.
See [Bash Builtins](https://www.gnu.org/software/bash/manual/html_node/Shell-Builtin-Commands.html),
[coreutils](https://en.wikipedia.org/wiki/List_of_GNU_Core_Utilities_commands),
[busybox](https://en.wikipedia.org/wiki/BusyBox#Commands) and [toybox](https://landley.net/toybox/help.html)
Availible commands in bash, coreutils, busybox and toybox. Do you find curl on the list?
```bash
.*, [*, [[*, basename, break, builtin*, bzcat, caller*, cat, cd*, chattr,
chgrp, chmod, chown, clear, command*, continue *, cp, cut, date, declare*,
dc, dd, df, diff, dirname, du, echo*, eval*, exec*, exit *, expr*, find,
fuser, getopt*, grep, hash*, head, hexdump, id, kill, killall, last, length,
less, let*, ln, local*, logname, ls, lsattr, lsmod, man, mapfile*, md5sum, mkdir,
mkfifo, mknod, more, mv, nice, nohup, passwd, patch, printf*, ps, pwd*, read*,
readarray*, readonly* return*, rm, rmdir, sed, seq, sha1sum, shift*, sleep,
source*, sort, split, stat, strings, su, sync, tail, tar, tee, test,
time, times*, timeout, touch, tr, trap*, true, umask*, usleep, uudecode,
uuencode, wc, wget, which, who, whoami, xargs, yes
```
commands marked with \* are bash builtins, all others are external programms. Calling an external programm is more expensive then using bulitins
or using an internal replacement. Here are some examples of internal replacement for external commands:
```bash
HOST="$(hostname)" -> HOST="$HOSTNAME"
seq 1 100 -> {0..100}
data="$(cat file)" -> data="$(<"file")"
DIR="$(dirname $0) -> DIR=""${0%/*}/""
IAM="($basename $0)" -> IAM="${0##*/}*
VAR="$(( 1 + 2 ))" -> (( var=1+2 ))
INDEX="$(( ${INDEX} + 1 ))" -> (( INDEX++ ))
```
For more examples see [Pure bash bible](https://github.com/dylanaraps/pure-bash-bible)
### 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.
@ -48,6 +103,8 @@ Usually I start with pre versions and when everything looks good I push out a re
v0.x-devx -> v0.x-prex -> v0.x-rc -> v0.x ... 0.x+1-dev ...
```
If you release a new Version run ```dev/make-distribution.sh``` to create the zip and tar.gz archives in the dist directory and attach them to the github release. Do not forget to delete directory dist afterwards.
### Versioning
Bashbot is tagged with version numbers. If you start a new development cycle you can tag your fork with a version higher than the current version.
@ -131,5 +188,5 @@ fi
#### [Prev Function Reference](6_reference.md)
#### [Next Bashbot Environment](8_custom.md)
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0

View File

@ -48,17 +48,31 @@ Full path to JSON.sh script, default: './JSON.sh/JSON.sh', must end with '/JSON.
### Change config values
#### BASHBOT_DECODE
Bashbot offers two variants for decoding JSON UTF format to UTF-8. By default bashbot uses 'json.encode' if python is installed.
If 'BASHBOT_DECODE' is set to any value (not undefined or not empty) the bash only implementation will be used.
```bash
unset BASHBOT_DECODE # autodetect python (default)
export BASHBOT_DECODE "" # autodetect python
#### BASHBOT_URL
Uses given URL instead of offical telegram API URL, useful if you have your own telegram server or for testing.
```bash
unset BASHBOT_URL # use Telegram URL https://api.telegram.org/bot<token> (default)
export BASHBOT_URL "" # use use Telegram https://api.telegram.org/bot<token>
export BASHBOT_URL "https://my.url.com/bot" # use your URL https://my.url.com/bot<token>
export BASHBOT_DECODE "yes" # force internal
export BASHBOT_DECODE "no" # also force internal!
```
#### BASHBOT_TOKEN
#### BASHBOT_WGET
Bashbot uses ```curl``` to communicate with telegram server. if ```curl``` is not availible ```wget``` is used.
If 'BASHBOT_WGET' is set to any value (not undefined or not empty) wget is used even is curl is availible.
```bash
unset BASHBOT_WGET # use curl (default)
export BASHBOT_WGET "" # use curl
export BASHBOT_WGET "yes" # use wget
export BASHBOT_WGET "no" # use wget!
```
#### BASHBOT_SLEEP
Instead of polling permanently or with a fixed delay, bashbot offers a simple adaptive polling.
@ -117,5 +131,5 @@ for every poll until the maximum of BASHBOT_SLEEP ms.
#### [Prev Notes for Developers](7_develop.md)
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0

View File

@ -55,6 +55,6 @@ convert existing bots.
**external-use** will contain some examples on how to send messages from external scripts to Telegram chats or users.
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0

View File

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

View File

@ -2,7 +2,7 @@
# file: run_filename
# background job to display content of all new files in WATCHDIR
#
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
# adjust your language setting here
# https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment

View File

@ -2,7 +2,7 @@
# file: run_filename
# background job to display all new files in WATCHDIR
#
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
# adjust your language setting here
# https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment

View File

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

View File

@ -2,7 +2,7 @@
# file. multibot.sh
# description: run multiple telegram bots from one installation
#
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
if [ "${2}" = "" ] || [ "${2}" = "-h" ]; then
echo "Usage: $0 botname command"

View File

@ -7,7 +7,7 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
SHELL=/bin/sh

View File

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

View File

@ -4,7 +4,7 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
# adjust your language setting here
# https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment
@ -27,6 +27,7 @@ else
fi
# output current time every $1 seconds
date "+* It's %k:%M:%S o' clock ..."
while sleep $SLEEP
do
date "+* It's %k:%M:%S o' clock ..."

View File

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

View File

@ -1,7 +1,7 @@
# file: botacl
# a user not listed here, will return false from 'user_is_allowed'
#
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
# Format:
# user:ressource:chat

View File

@ -5,7 +5,7 @@
# to show how you can customize bashbot by only editing mycommands.sh
# NOTE: this is not tested, simply copied from original source and reworked!
#
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
#
# shellcheck disable=SC2154
# shellcheck disable=SC2034

View File

@ -5,7 +5,7 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
#
# source from commands.sh to use the aliases

View File

@ -5,23 +5,11 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
# source from commands.sh to use the inline functions
INLINE_QUERY=$URL'/answerInlineQuery'
declare -A iQUERY
export iQUERY
process_inline() {
local num="${1}"
iQUERY[0]="$(JsonDecode "$(JsonGetString <<<"${UPDATE}" '"result",0,"inline_query","query"')")"
iQUERY[USER_ID]="$(JsonGetValue <<<"${UPDATE}" '"result",'"${num}"',"inline_query","from","id"')"
iQUERY[FIRST_NAME]="$(JsonDecode "$(JsonGetString <<<"${UPDATE}" '"result",'"${num}"',"inline_query","from","first_name"')")"
iQUERY[LAST_NAME]="$(JsonDecode "$(JsonGetString <<<"${UPDATE}" '"result",'"${num}"',"inline_query","from","last_name"')")"
iQUERY[USERNAME]="$(JsonDecode "$(JsonGetString <<<"${UPDATE}" '"result",'"${num}"',"inline_query","from","username"')")"
}
answer_inline_query() {
answer_inline_multi "${1}" "$(shift; inline_query_compose "$RANDOM" "$@")"

View File

@ -5,78 +5,10 @@
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
# source from commands.sh if you want ro use interactive or background jobs
## to statisfy shellcheck
export res
####
# I placed send_message here because main use case is interactive chats and background jobs
send_message() {
[ "$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 <<< "${text}" 's/ *mynewlinestartshere */\r\n/g')"
[ "$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}" '/myfilelocationstartshere /!d;s/.*myfilelocationstartshere //;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 [ "$no_keyboard" != "" ]; then
remove_keyboard "$1" "$text"
sent=y
fi
if [ "$keyboard" != "" ]; then
if [[ "$keyboard" != *"["* ]]; then # pre 0.60 style
keyboard="[ ${keyboard//\" \"/\" \] , \[ \"} ]"
fi
send_keyboard "$1" "$text" "$keyboard"
sent=y
fi
if [ "$btext" != "" ] && [ "$burl" != "" ]; then
send_button "$1" "$text" "$btext" "$burl"
sent=y
fi
if [ "$file" != "" ]; then
send_file "$1" "$file" "$text"
sent=y
fi
if [ "$lat" != "" ] && [ "$long" != "" ]; then
if [ "$address" != "" ] && [ "$title" != "" ]; then
send_venue "$1" "$lat" "$long" "$title" "$address"
else
send_location "$1" "$lat" "$long"
fi
sent=y
fi
if [ "$sent" != "y" ];then
send_text "$1" "$text"
fi
}
send_text() {
case "$2" in
html_parse_mode*)
send_html_message "$1" "${2//html_parse_mode}"
;;
markdown_parse_mode*)
send_markdown_message "$1" "${2//markdown_parse_mode}"
;;
*)
send_normal_message "$1" "$2"
;;
esac
}
######
# interactive and background functions
@ -99,7 +31,9 @@ checkback() {
}
checkproc() {
tmux ls | grep -q "$1${copname}"; res=$?; return $?
tmux ls | grep -q "$1${copname}"
# shellcheck disable=SC2034
res=$?; return $?
}
killback() {

63
modules/chatMember.sh Normal file
View File

@ -0,0 +1,63 @@
#!/bin/bash
# file: modules/chatMember.sh
# do not edit, this file will be overwritten on update
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#
#### $$VERSION$$ v0.76-1-ge8a1fd0
# source from commands.sh to use the member functions
LEAVE_URL=$URL'/leaveChat'
KICK_URL=$URL'/kickChatMember'
UNBAN_URL=$URL'/unbanChatMember'
GETMEMBER_URL=$URL'/getChatMember'
# usage: status="$(get_chat_member_status "chat" "user")"
get_chat_member_status() {
sendJson "$1" 'user_id: '"$2"'' "$GETMEMBER_URL"
# 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"
}
user_is_creator() {
if [ "${1:--}" = "${2:-+}" ] || [ "$(get_chat_member_status "$1" "$2")" = "creator" ]; then return 0; fi
return 1
}
user_is_admin() {
local me; me="$(get_chat_member_status "$1" "$2")"
if [ "${me}" = "creator" ] || [ "${me}" = "administrator" ]; then return 0; fi
return 1
}
user_is_botadmin() {
local admin; admin="$(head -n 1 "${BOTADMIN}")"
[ "${admin}" = "${1}" ] && return 0
[[ "${admin}" = "@*" ]] && [[ "${admin}" = "${2}" ]] && return 0
if [ "${admin}" = "?" ]; then echo "${1:-?}" >"${BOTADMIN}"; return 0; fi
return 1
}
user_is_allowed() {
local acl="$1"
[ "$1" = "" ] && return 1
grep -F -xq "${acl}:*:*" <"${BOTACL}" && return 0
[ "$2" != "" ] && acl="${acl}:$2"
grep -F -xq "${acl}:*" <"${BOTACL}" && return 0
[ "$3" != "" ] && acl="${acl}:$3"
grep -F -xq "${acl}" <"${BOTACL}"
}

232
modules/sendMessage.sh Normal file
View File

@ -0,0 +1,232 @@
#!/bin/bash
# file: modules/message.sh
# do not edit, this file will be overwritten on update
# This file is public domain in the USA and all free countries.
# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying)
#
#### $$VERSION$$ v0.76-1-ge8a1fd0
# source from commands.sh to use the sendMessage functions
MSG_URL=$URL'/sendMessage'
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'
send_normal_message() {
local text="${2}"
until [ -z "${text}" ]; do
sendJson "${1}" '"text":"'"${text:0:4096}"'"' "${MSG_URL}"
text="${text:4096}"
done
}
send_markdown_message() {
local text="${2}"
until [ -z "${text}" ]; do
sendJson "${1}" '"text":"'"${text:0:4096}"'","parse_mode":"markdown"' "${MSG_URL}"
text="${text:4096}"
done
}
send_html_message() {
local text="${2}"
until [ -z "${text}" ]; do
sendJson "${1}" '"text":"'"${text:0:4096}"'","parse_mode":"html"' "${MSG_URL}"
text="${text:4096}"
done
}
old_send_keyboard() {
local text='"text":"'"${2}"'"'
shift 2
local keyboard=init
OLDIFS=$IFS
IFS=$(echo -en "\"")
for f in "$@" ;do [ "$f" != " " ] && keyboard="$keyboard, [\"$f\"]";done
IFS=$OLDIFS
keyboard=${keyboard/init, /}
sendJson "${1}" "${text}"', "reply_markup": {"keyboard": [ '"${keyboard}"' ],"one_time_keyboard": true}' "$MSG_URL"
}
ISEMPTY="ThisTextIsEmptyAndWillBeDeleted"
sendEmpty() {
sendJson "${@}"
[[ "${2}" = *"${ISEMPTY}"* ]] && delete_message "${1}" "${BOTSENT[ID]}"
}
send_keyboard() {
if [[ "$3" != *'['* ]]; then old_send_keyboard "${@}"; return; fi
local text='"text":"'"${2}"'"'; [ "${2}" = "" ] && text='"text":"'"${ISEMPTY}"'"'
local one_time=', "one_time_keyboard":true' && [ "$4" != "" ] && one_time=""
sendEmpty "${1}" "${text}"', "reply_markup": {"keyboard": [ '"${3}"' ] '"${one_time}"'}' "$MSG_URL"
# '"text":"$2", "reply_markup": {"keyboard": [ ${3} ], "one_time_keyboard": true}'
}
remove_keyboard() {
local text='"text":"'"${2}"'"'; [ "${2}" = "" ] && text='"text":"'"${ISEMPTY}"'"'
sendEmpty "${1}" "${text}"', "reply_markup": {"remove_keyboard":true}' "$MSG_URL"
#JSON='"text":"$2", "reply_markup": {"remove_keyboard":true}'
}
send_inline_keyboard() {
local text='"text":"'"${2}"'"'; [ "${2}" = "" ] && text='"text":"'"${ISEMPTY}"'"'
sendEmpty "${1}" "${text}"', "reply_markup": {"inline_keyboard": [ '"${3}"' ]}' "$MSG_URL"
# JSON='"text":"$2", "reply_markup": {"inline_keyboard": [ $3->[{"text":"text", "url":"url"}]<- ]}'
}
send_button() {
send_inline_keyboard "${1}" "${2}" '[ {"text":"'"${3}"'", "url":"'"${4}"'"}]'
}
UPLOADDIR="${BASHBOT_UPLOAD:-${TMPDIR}/upload}"
send_file() {
[ "$2" = "" ] && return
local file="$2"
local CAPTION=',"caption":"'$3'"'; [ "$3" = "" ] && CAPTION=""
# file access checks ...
[[ "$file" = *'..'* ]] && return # no directory traversal
[[ "$file" = '.'* ]] && return # no hidden or relative files
if [[ "$file" = '/'* ]] ; then
[[ "$file" =~ $FILE_REGEX ]] || return # absulute must match REGEX
else
file="${UPLOADDIR:-NOUPLOADDIR}/${file}" # othiers must be in UPLOADDIR
fi
[ -r "$file" ] || return # 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)
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"
;;
*)
CUR_URL="$DOCUMENT_URL"
WHAT="document"
STATUS="upload_document"
;;
esac
send_action "${1}" "$STATUS"
# shellcheck disable=SC2034
sendJson "${1}" '"'"$WHAT"'":"'"$2"'"'"$CAPTION"'"' "$CUR_URL"
}
# 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
send_action() {
[ "$2" = "" ] && return
sendJson "${1}" '"action": "'"${2}"'"' "$ACTION_URL"
}
send_location() {
[ "$3" = "" ] && return
sendJson "${1}" '"latitude": '"${2}"', "longitude": '"${3}"'' "$LOCATION_URL"
}
send_venue() {
local add=""
[ "$5" = "" ] && return
[ "$6" != "" ] && add=', "foursquare_id": '"$6"''
sendJson "${1}" '"latitude": '"${2}"', "longitude": '"${3}"', "address": "'"${5}"'", "title": "'"${4}"'"'"${add}" "$VENUE_URL"
}
forward_message() {
[ "$3" = "" ] && return
sendJson "${1}" '"from_chat_id": '"${2}"', "message_id": '"${3}"'' "$FORWARD_URL"
}
forward() { # backward compatibility
forward_message "$@" || return
}
send_message() {
[ "$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 <<< "${text}" 's/ *mynewlinestartshere */\r\n/g')"
[ "$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}" '/myfilelocationstartshere /!d;s/.*myfilelocationstartshere //;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 [ "$no_keyboard" != "" ]; then
remove_keyboard "$1" "$text"
sent=y
fi
if [ "$keyboard" != "" ]; then
if [[ "$keyboard" != *"["* ]]; then # pre 0.60 style
keyboard="[ ${keyboard//\" \"/\" \] , \[ \"} ]"
fi
send_keyboard "$1" "$text" "$keyboard"
sent=y
fi
if [ "$btext" != "" ] && [ "$burl" != "" ]; then
send_button "$1" "$text" "$btext" "$burl"
sent=y
fi
if [ "$file" != "" ]; then
send_file "$1" "$file" "$text"
sent=y
fi
if [ "$lat" != "" ] && [ "$long" != "" ]; then
if [ "$address" != "" ] && [ "$title" != "" ]; then
send_venue "$1" "$lat" "$long" "$title" "$address"
else
send_location "$1" "$lat" "$long"
fi
sent=y
fi
if [ "$sent" != "y" ];then
send_text "$1" "$text"
fi
}
send_text() {
case "$2" in
html_parse_mode*)
send_html_message "$1" "${2//html_parse_mode}"
;;
markdown_parse_mode*)
send_markdown_message "$1" "${2//markdown_parse_mode}"
;;
*)
send_normal_message "$1" "$2"
;;
esac
}

View File

@ -2,38 +2,35 @@
# files: mycommands.sh.dist
# copy to mycommands.sh and add all your commands and functions here ...
#
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
#
# shellcheck disable=SC2154
# shellcheck disable=SC2034
# uncomment the following lines to overwrite info and help messages
# bashbot_info='This is bashbot, the Telegram bot written entirely in bash.
#'
# bashbot_help='*Available commands*:
#'
res=""
if [ "$1" = "source" ];then
# Set INLINE to 1 in order to receive inline queries.
# To enable this option in your bot, send the /setinline command to @BotFather.
INLINE="0"
export INLINE="0"
# Set to .* to allow sending files from all locations
FILE_REGEX='/home/user/allowed/.*'
export FILE_REGEX='/home/user/allowed/.*'
else
if [ "$1" != "source" ];then
# your additional bahsbot commands
# NOTE: command can have @botname attached, you must add * in case tests...
mycommands() {
case "$MESSAGE" in
case "${MESSAGE}" in
'/echo'*) # example echo command
send_normal_message "${CHAT[ID]}" "$MESSAGE"
;;
'/question'*) # start interactive questions
checkproc
if [ "$res" -gt 0 ] ; then
startproc "example/question"
startproc "examples/question.sh"
else
send_normal_message "${CHAT[ID]}" "$MESSAGE already running ..."
fi
@ -42,7 +39,7 @@ else
'/run_notify'*) # start notify background job
myback="notify"; checkback "$myback"
if [ "$res" -gt 0 ] ; then
background "example/notify 60" "$myback" # notify every 60 seconds
background "examples/notify.sh 60" "$myback" # notify every 60 seconds
else
send_normal_message "${CHAT[ID]}" "Background command $myback already running ..."
fi
@ -64,6 +61,7 @@ else
#######################
# Inline query examples, do not use them in production (exept image search ;-)
# shellcheck disable=SC2128
iQUERY="${iQUERY,,}" # all lowercase
case "${iQUERY}" in
"image "*) # search images with yahoo
local search="${iQUERY#* }"
@ -107,6 +105,7 @@ else
answer_inline_query "${iQUERY[ID]}" "cached_gif" "BQADBAADIwYAAmwsDAABlIia56QGP0YC"
;;
esac
set +x
}
# place your processing functions here
@ -116,7 +115,7 @@ 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 "9" ] && break
[ "$count" -gt "20" ] && break
image="${image#* src=\'}"; image="${image%%&pid=*}"
[[ "${image}" = *"src="* ]] && continue
echo "${sep}"; inline_query_compose "$RANDOM" "photo" "${image}"; sep=","

View File

@ -2,7 +2,7 @@
#
# ADD a new test skeleton to test dir, but does not activate test
#
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
# magic to ensure that we're always inside the root of our application,
# no matter from which directory we'll run script
@ -65,6 +65,7 @@ cd "\${TESTDIR}" || exit 1
# source bashbot.sh function, uncomment if you want to test functions
# shellcheck source=./bashbot.sh
# source "\\${TESTDIR}/bashbot.sh" source
# source "\\${TESTDIR}/commands.sh" source
# start writing your tests here ...

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
# common variables
export TESTME DIRME TESTDIR LOGFILE REFDIR TESTNAME
@ -11,12 +11,13 @@ export TESTME DIRME TESTDIR LOGFILE REFDIR TESTNAME
TESTNAME="${REFDIR//-/ }"
# common filenames
export TOKENFILE ACLFILE COUNTFILE ADMINFILE DATADIR
export TOKENFILE ACLFILE COUNTFILE ADMINFILE DATADIR JSONSHFILE
TOKENFILE="token"
ACLFILE="botacl"
COUNTFILE="count"
ADMINFILE="botadmin"
DATADIR="data-bot-bash"
JSONSHFILE="JSON.sh/JSON.sh"
# SUCCESS NOSUCCES
export SUCCESS NOSUCCESS

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
../dev/hooks/pre-commit.sh

View File

@ -1,6 +1,6 @@
#!/usr/bin/env bash
# file: b-example-test.sh
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
# include common functions and definitions
# shellcheck source=test/ALL-tests.inc.sh

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
# include common functions and definitions
# shellcheck source=test/ALL-tests.inc.sh
@ -24,18 +24,22 @@ export FAIL="0"
for file in ${TESTFILES}
do
ls -d "${TESTDIR}/${file}" >>"${LOGFILE}"
if ! diff -q "${TESTDIR}/${file}" "${REFDIR}/${file}" >>"${LOGFILE}"; then echo "${NOSUCCESS} Fail diff ${file}!"; FAIL="1"; fi
diff -q "${TESTDIR}/${file}" "${REFDIR}/${file}" >>"${LOGFILE}" || { echo "${NOSUCCESS} Fail diff ${file}!"; FAIL="1"; }
done
[ "${FAIL}" != "0" ] && exit "${FAIL}"
echo "${SUCCESS}"
echo "Test Sourcing of bashbot.sh ..."
trap exit 1 EXIT
cd "${TESTDIR}" || exit
echo "Test if $JSONSHFILE exists ..."
[ ! -x "$JSONSHFILE" ] && { echo "${NOSUCCESS} Fail diff ${file}!"; exit 1; }
echo "Test Sourcing of bashbot.sh ..."
# shellcheck source=./bashbot.sh
source "${TESTDIR}/bashbot.sh" source
source "${TESTDIR}/commands.sh" source
trap '' EXIT
cd "${DIRME}" || exit 1
echo "${SUCCESS}"

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
# include common functions and definitions
# shellcheck source=test/ALL-tests.inc.sh

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
# include common functions and definitions
# shellcheck source=test/ALL-tests.inc.sh
@ -12,7 +12,7 @@ cd "${TESTDIR}" || exit 1
# shellcheck source=./bashbot.sh
source "${TESTDIR}/bashbot.sh" source
# shellcheck source=./bashbot.sh
source "${TESTDIR}/modules/inline.sh" source
source "${TESTDIR}/modules/answerInline.sh" source
# overwrite get_file for test
get_file() {

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
# include common functions and definitions
# shellcheck source=test/ALL-tests.inc.sh
@ -11,6 +11,8 @@ set -e
cd "${TESTDIR}" || exit 1
# shellcheck source=./bashbot.sh
source "${TESTDIR}/bashbot.sh" source
# shellcheck source=./bashbot.sh
source "${TESTDIR}/commands.sh" source
# overwrite get_file for test
get_file() {
@ -21,13 +23,8 @@ get_file() {
export UPDATE
UPDATE="$(cat "${INPUTFILE}")"
# run process_message with and without phyton
# run process_message
echo "Check process_message ..."
for i in 1 2
do
[ "${i}" = "1" ] && ! which python >/dev/null 2>&1 && continue
[ "${i}" = "1" ] && echo " ... with JsonDecode Phyton" && unset BASHBOT_DECODE
[ "${i}" = "2" ] && echo " ... with JsonDecode Bash" && export BASHBOT_DECODE="yes"
set -x
{ process_message "0"; set +x; } >>"${LOGFILE}" 2>&1;
@ -35,6 +32,5 @@ do
print_array "USER" "CHAT" "REPLYTO" "FORWARD" "URLS" "CONTACT" "CAPTION" "LOCATION" "MESSAGE" "VENUE" >"${OUTPUTFILE}"
diff -c "${REFFILE}" "${OUTPUTFILE}" || exit 1
echo "${SUCCESS}"
done
cd "${DIRME}" || exit 1

View File

@ -1,34 +1,42 @@
#!/usr/bin/env bash
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
# include common functions and definitions
# shellcheck source=test/ALL-tests.inc.sh
source "./ALL-tests.inc.sh"
set -e
set +f
cd "${TESTDIR}" || exit 1
# source bashbot.sh function, uncomment if you want to test functions
# shellcheck source=./bashbot.sh
source "${TESTDIR}/bashbot.sh" source
source "${TESTDIR}/modules/background.sh"
# shellcheck source=./bashbot.sh
source "${TESTDIR}/commands.sh" source
_is_function send_message || echo "Send Message not found!"
# start writing your tests here ...
# over write sendJson to output parameter only
sendEmpty() {
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}"
}
# send text input to send_message
#set -x
echo -n " Send line ..."
while IFS='' read -r line || [[ -n "$line" ]]; do
while read -r line ; do
echo -n "."
send_message "123456" "$line" >>"${OUTPUTFILE}"
done < "${INPUTFILE}" 2>>"${LOGFILE}"
done < "${INPUTFILE}" #2>>"${LOGFILE}"
echo " done."
{ diff -c "${REFFILE}" "${OUTPUTFILE}" || exit 1; } | cat -v

View File

@ -8,10 +8,8 @@ markdown_parse_mode This is a *MARKDOWN* text mynewlinestartshere with a line br
# test for keyboard, file, venue output
Text plus keyboard will appear in chat mykeyboardstartshere [ "Yep, sure" , "No, highly unlikely" ]
Text plus file will appear in chat myfilelocationstartshere /home/user/doge.jpg
Text plus location will appear in chat mylatstartshere la10 mylongstartshere lo20
Text plus vuene will appear in chat mylatstartshere la10 mylongstartshere lo20 mytitlestartshere my home myaddressstartshere Diagon Alley N. 37
All in one will appear in chat mykeyboardstartshere [ "Yep, sure" , "No, highly unlikely" ] myfilelocationstartshere /home/user/doge.jpg mylatstartshere la10 mylongstartshere lo20
# test for new inline button
Text plus keyboard will appear in chat mybtextstartshere Button Text myburlstartshere https://www...

View File

@ -28,24 +28,12 @@ URL:https://api.telegram.org/botbashbottestscript/sendMessage
chat:123456 JSON:"text":"Text plus keyboard will appear in chat", "reply_markup": {"keyboard": [ [ "Yep, sure" , "No, highly unlikely" ] ] , "one_time_keyboard":true}
URL:https://api.telegram.org/botbashbottestscript/sendMessage
chat:123456 JSON:"action": "upload_photo"
URL:https://api.telegram.org/botbashbottestscript/sendChatAction
chat:123456 JSON:"latitude": la10, "longitude": lo20
URL:https://api.telegram.org/botbashbottestscript/sendLocation
chat:123456 JSON:"latitude": la10, "longitude": lo20, "address": "Diagon Alley N. 37", "title": "my home"
URL:https://api.telegram.org/botbashbottestscript/sendVenue
chat:123456 JSON:"text":"All in one will appear in chat", "reply_markup": {"keyboard": [ [ "Yep, sure" , "No, highly unlikely" ] ] , "one_time_keyboard":true}
URL:https://api.telegram.org/botbashbottestscript/sendMessage
chat:123456 JSON:"action": "upload_photo"
URL:https://api.telegram.org/botbashbottestscript/sendChatAction
chat:123456 JSON:"latitude": la10, "longitude": lo20
URL:https://api.telegram.org/botbashbottestscript/sendLocation
chat:123456 JSON:"text":"# test for new inline button"
URL:https://api.telegram.org/botbashbottestscript/sendMessage

View File

@ -1,17 +1,20 @@
#!/usr/bin/env bash
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
# include common functions and definitions
# shellcheck source=test/ALL-tests.inc.sh
source "./ALL-tests.inc.sh"
set -e
set +f
cd "${TESTDIR}" || exit 1
# source bashbot.sh function, uncomment if you want to test functions
# shellcheck source=./bashbot.sh
source "${TESTDIR}/bashbot.sh" source
# shellcheck source=./bashbot.sh
source "${TESTDIR}/commands.sh" source
# start writing your tests here ...

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
#### $$VERSION$$ v0.72-1-g67c47ac
#### $$VERSION$$ v0.76-1-ge8a1fd0
# include common functions and definitions
# shellcheck source=test/ALL-tests.inc.sh