├── .gitignore ├── LICENSE ├── README.html ├── README.md ├── README.txt ├── addons ├── antiFlood.sh └── example.sh ├── bashbot.rc ├── bashbot.sh ├── bin ├── any_command.sh ├── bashbot_env.inc.sh ├── bashbot_init.inc.sh ├── bashbot_stats.sh ├── delete_message.sh ├── edit_buttons.sh ├── edit_message.sh ├── kickban_user.sh ├── process_batch.sh ├── process_update.sh ├── promote_user.sh ├── send_broadcast.sh ├── send_buttons.sh ├── send_dice.sh ├── send_file.sh └── send_message.sh ├── commands.sh ├── db.json ├── dev ├── all-tests.sh ├── dev.inc.sh ├── git-add.sh ├── hooks │ ├── post-commit.sh │ ├── pre-commit.sh │ └── pre-push.sh ├── inject-json.sh ├── install-hooks.sh ├── make-distribution.sh ├── make-distribution.sh.exclude ├── make-html.sh ├── make-standalone.sh ├── make-standalone.sh.include ├── obfuscate.sh ├── shellcheck.files └── version.sh ├── doc ├── 0_install.md ├── 1_firstbot.md ├── 2_usage.md ├── 3_advanced.md ├── 4_expert.md ├── 5_practice.md ├── 6_reference.md ├── 7_develop.md └── bashbot.ascii ├── examples ├── README.md ├── background-scripts │ ├── mycommands.sh │ ├── run_diskusage.sh │ ├── run_filecontent.sh │ ├── run_filename.sh │ └── run_notify.sh ├── bash2env.sh ├── bashbot-multi.sh ├── bashbot.cron ├── calc.sh ├── jsonDB-keyboard │ └── mycommands.sh ├── notify.sh ├── question.sh ├── send-system-status │ ├── botacl │ └── mycommands.sh └── webhook │ ├── BASHBOT_HOME │ ├── README.md │ ├── index.php │ └── json.txt ├── modules ├── aliases.sh ├── answerInline.sh ├── background.sh ├── chatMember.sh ├── jsonDB.sh ├── processUpdates.sh └── sendMessage.sh ├── mycommands.conf ├── mycommands.sh ├── mycommands.sh.clean ├── scripts └── interactive.sh.clean └── test ├── ADD-test-new.sh ├── ALL-tests.inc.sh ├── a-commit-test.sh ├── b-example-test.sh ├── c-init-test.sh ├── c-init-test ├── blocked.jssh ├── botacl ├── botconfig.jssh ├── count.jssh ├── count.test └── stats.out ├── d-JSON.sh-test.sh ├── d-JSON.sh-test ├── JSON26783.log.in ├── JSON26783.log.result-1 ├── JSON26783.log.result-2 ├── JSON30458.log.in ├── JSON30458.log.result-1 ├── JSON30458.log.result-2 ├── JSON32034.log.in ├── JSON32034.log.result-1 └── JSON32034.log.result-2 ├── d-process_inline-test.sh ├── d-process_inline-test ├── d-process_inline-test.input └── d-process_inline-test.result ├── d-process_message-test.sh ├── d-process_message-test ├── d-process_message-test-left_chat_member.input ├── d-process_message-test-left_chat_member.result ├── d-process_message-test-mesage.result ├── d-process_message-test-message.input ├── d-process_message-test-message.result ├── d-process_message-test-new_chat_member.input ├── d-process_message-test-new_chat_member.result ├── d-process_message-test-new_chat_picture.input ├── d-process_message-test-new_chat_picture.result ├── d-process_message-test-new_chat_title.input ├── d-process_message-test-new_chat_title.result ├── d-process_message-test-pinned_message.input └── d-process_message-test-pinned_message.result ├── d-send_message-test.sh ├── d-send_message-test ├── d-send_message-test.input └── d-send_message-test.result ├── d-user_is-test.sh ├── e-env-test.sh └── e-env-test ├── blocked.jssh ├── botacl ├── botconfig.jssh └── count.jssh /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | /.github/ 3 | /count* 4 | /token* 5 | /blocked* 6 | /botconf* 7 | /botacl* 8 | /botown* 9 | *.jssh 10 | *.save 11 | *.log 12 | *.swp 13 | *.swo 14 | /logs/ 15 | /JSON.sh/ 16 | /data-bot-bash/ 17 | /DIST/ 18 | /STANDALONE/ 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This project is released to the public domain where applicable. 2 | 3 | Otherwise, it is released under the terms of the WTFPLv2: 4 | 5 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 6 | Version 2, December 2004 7 | 8 | Copyright (C) 2004 Sam Hocevar 9 | 10 | Everyone is permitted to copy and distribute verbatim or modified 11 | copies of this license document, and changing it is allowed as long 12 | as the name is changed. 13 | 14 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 15 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 16 | 17 | 0. You just DO WHAT THE FUCK YOU WANT TO. 18 | 19 | -------------------------------------------------------------------------------- /addons/antiFlood.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # file: addons/antiFlood.sh.dist 3 | # 4 | # this addon counts how many files, e.g. stickers, are sent to 5 | # a chat and takes actions if threshold is reached 6 | # 7 | #### $$VERSION$$ v1.52-1-g0dae2db 8 | 9 | # used events: 10 | # 11 | # BASHBOT_EVENT_TEXT message containing message text received 12 | # BASHBOT_EVENT_CMD a command is received 13 | # BASHBOT_EVENT_FILE file received 14 | # 15 | # all global variables and functions can be used in registered functions. 16 | # 17 | # parameters when loaded 18 | # $1 event: init, startbot ... 19 | # $2 debug: use "[[ "$2" = *"debug"* ]]" if you want to output extra diagnostic 20 | # 21 | # parameters on events 22 | # $1 event: inline, message, ..., file 23 | # $2 debug: use "[[ "$2" = *"debug"* ]]" if you want to output extra diagnostic 24 | # 25 | # shellcheck disable=SC2140 26 | 27 | # export used events 28 | export BASHBOT_EVENT_TEXT BASHBOT_EVENT_CMD BASHBOT_EVENT_FILE BASHBOT_EVENT_TIMER 29 | 30 | # any global variable defined by addons MUST be prefixed by addon name 31 | ANTIFL_ME="antiFlood" 32 | 33 | declare -Ax ANTIFL_CHATS ANTIFL_ACTUALS 34 | 35 | ANTIFL_DEFAULT="5" # 5 files per minute 36 | ANTIFL_BAN="5" # 5 minutes 37 | 38 | # initialize after installation or update 39 | if [[ "$1" = "init"* ]]; then 40 | jssh_newDB "addons/${ANTIFL_ME}" 41 | fi 42 | 43 | 44 | 45 | # register on startbot 46 | if [[ "$1" = "start"* ]]; then 47 | ANTIFL_ADMIN="$(getConfigKey "botadmin")" 48 | #load existing chat settings on start 49 | jssh_readDB "ANTIFL_CHATS" "addons/${ANTIFL_ME}" 50 | 51 | # register to CMD 52 | BASHBOT_EVENT_CMD["${ANTIFL_ME}"]="${ANTIFL_ME}_cmd" 53 | 54 | antiFlood_cmd(){ 55 | # shellcheck disable=SC2153 56 | local chat="${CHAT[ID]}" 57 | 58 | case "${CMD[0]}" in 59 | # command /afstart starts detection, $1 floodlevel 60 | "/afstart") 61 | # allow bot admin to activate for other chats 62 | [[ "${CMD[3]}" =~ ^[-0-9]+$ ]] && user_is_botadmin "${USER[ID]}" && chat="$3" 63 | [[ "${CMD[1]}" =~ ^[0-9]+$ ]] && ANTIFL_CHATS["${chat}","level"]="${CMD[1]}" \ 64 | || ANTIFL_CHATS["${chat}","level"]="${ANTIFL_DEFAULT}" 65 | [[ "${CMD[2]}" =~ ^[0-9]+$ ]] && ANTIFL_CHATS["${chat}","ban"]="${CMD[2]}" \ 66 | || ANTIFL_CHATS["${chat}","ban"]="${ANTIFL_BAN}" 67 | antiFlood_timer 68 | send_normal_message "${USER[ID]}" "Antiflood set for chat ${chat}" & 69 | ;; 70 | # command /afactive starts counter meausares 71 | "/afdo" | "/afactive") 72 | [[ "${CMD[1]}" =~ ^[-0-9]+$ ]] && user_is_botadmin "${USER[ID]}" && chat="$3" 73 | ANTIFL_CHATS["${chat}","active"]="yes" 74 | jssh_writeDB "ANTIFL_CHATS" "addons/${ANTIFL_ME}" & 75 | send_normal_message "${USER[ID]}" "Antiflood activated for chat ${chat}" & 76 | ;; 77 | # command /afactive starts counter meausares 78 | "/afstop") 79 | [[ "${CMD[1]}" =~ ^[-0-9]+$ ]] && user_is_botadmin "${USER[ID]}" && chat="$3" 80 | ANTIFL_CHATS["${chat}","active"]="no" 81 | jssh_writeDB "ANTIFL_CHATS" "addons/${ANTIFL_ME}" & 82 | send_normal_message "${USER[ID]}" "Antiflood stopped for chat ${chat}" & 83 | ;; 84 | esac 85 | } 86 | 87 | # register to timer 88 | BASHBOT_EVENT_TIMER["${ANTIFL_ME}","${ANTIFL_BAN}"]="antiFlood_timer" 89 | 90 | # save settings and reset flood level every BAN Min 91 | antiFlood_timer(){ 92 | ANTIFL_ACTUALS=( ) 93 | jssh_writeDB "ANTIFL_CHATS" "addons/${ANTIFL_ME}" & 94 | } 95 | 96 | # register to inline and command 97 | BASHBOT_EVENT_TEXT["${ANTIFL_ME}"]="${ANTIFL_ME}_multievent" 98 | BASHBOT_EVENT_FILE["${ANTIFL_ME}"]="${ANTIFL_ME}_multievent" 99 | 100 | antiFlood_multievent(){ 101 | # not started 102 | [ -z "${ANTIFL_CHATS["${CHAT[ID]}","level"]}" ] && return 103 | # count user flood text 104 | if [ "$1" = "text" ]; then 105 | if [ "${#MESSAGE[0]}" -gt "${ANTIFL_CHATS["${CHAT[ID]}","level"]}" ]; then 106 | (( ANTIFL_ACTUALS["${CHAT[ID]}","${USER[ID]}"]-- )) 107 | # shellcheck disable=SC2154 108 | (( ANTIFL_ACTUALS["${CHAT[ID]}","${USER[ID]}","file"]-- )) 109 | else 110 | # shellcheck disable=SC2154 111 | (( ANTIFL_ACTUALS["${CHAT[ID]}","${USER[ID]}"]++ )) 112 | fi 113 | fi 114 | # count user chat flood 115 | if [ "$1" = "file" ]; then 116 | # shellcheck disable=SC2154 117 | (( ANTIFL_ACTUALS["${CHAT[ID]}","${USER[ID]}","file"]++ )) 118 | # shellcheck disable=SC2154 119 | (( ANTIFL_ACTUALS["${CHAT[ID]}","file"]++ )) 120 | antiFlood_action & # do actions in subshell 121 | fi 122 | } 123 | 124 | # check and handle actions 125 | antiFlood_action() { 126 | # check flood level of user 127 | if [ "$(( ANTIFL_ACTUALS["${CHAT[ID]}","${USER[ID]}","file"] +1))" -gt "${ANTIFL_CHATS["${CHAT[ID]}","level"]}" ]; then 128 | if [ "${ANTIFL_CHATS["${CHAT[ID]}","active"]}" = "yes" ]; then 129 | # remove message 130 | delete_message "${CHAT[ID]}" "${MESSAGE[ID]}" 131 | else 132 | # inform admin 133 | send_markdown_message "${ANTIFL_ADMIN}" "User ${USER[USERNAME]} reached flood level in chat ${CHAT[USERNAME]}!" 134 | fi 135 | fi 136 | # check flood level of chat 137 | if [ "$(( ANTIFL_ACTUALS["${CHAT[ID]}","file"] +1))" -gt "$(( ANTIFL_CHATS["${CHAT[ID]}","level"] * ANTIFL_BAN ))" ]; then 138 | if [ "${ANTIFL_CHATS["${CHAT[ID]}","active"]}" = "yes" ]; then 139 | # remove message 140 | delete_message "${CHAT[ID]}" "${MESSAGE[ID]}" 141 | else 142 | # inform admin 143 | send_markdown_message "${ANTIFL_ADMIN}" "Chat ${CHAT[USERNAME]} reached max flood level!" 144 | fi 145 | fi 146 | } 147 | fi 148 | -------------------------------------------------------------------------------- /addons/example.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # file: addons/example.sh.dist 3 | # 4 | # Addons can register to bashbot events at startup 5 | # by providing their name and a callback per event 6 | # 7 | #### $$VERSION$$ v1.52-1-g0dae2db 8 | # 9 | # If an event occurs each registered event function is called. 10 | # 11 | # Events run in the same context as the main bashbot event loop 12 | # so variables set here are persistent as long bashbot is running. 13 | # 14 | # Note: For the same reason event function MUST return imideatly! 15 | # compute intensive tasks must be run in a nonblocking subshell, 16 | # e.g. "(long running) &" 17 | # 18 | 19 | # Available events: 20 | # on events startbot and init, this file is sourced 21 | # 22 | # BASHBOT_EVENT_INLINE inline query received 23 | # BASHBOT_EVENT_MESSAGE any type of message received 24 | # BASHBOT_EVENT_TEXT message containing message text received 25 | # BASHBOT_EVENT_CMD a command is received 26 | # BASHBOT_EVENT_REPLYTO reply to message received 27 | # BASHBOT_EVENT_FORWARD forwarded message received 28 | # BASHBOT_EVENT_CONTACT contact received 29 | # BASHBOT_EVENT_LOCATION location or venue received 30 | # BASHBOT_EVENT_FILE file received 31 | # 32 | # BASHBOT_EVENT_TIMER this event is a bit special as it fires every Minute 33 | # and has 3 meanings: oneshot, every time, every X minutes. 34 | # 35 | # all global variables and functions can be used in registered functions. 36 | # 37 | # parameters when loaded 38 | # $1 event: init, startbot ... 39 | # $2 debug: use "[[ "$2" = *"debug"* ]]" if you want to output extra diagnostic 40 | # 41 | # parameters on events 42 | # $1 event: inline, message, ..., file 43 | # $2 key: key of array BASHBOT_EVENT_xxx 44 | # $3 debug: use "[[ "$2" = *"debug"* ]]" if you want to output extra diagnostic 45 | # 46 | 47 | # export used events 48 | export BASHBOT_EVENT_INLINE BASHBOT_EVENT_CMD BASHBOT_EVENT_REPLY BASHBOT_EVENT_TIMER BASHBOT_EVENT_SEND 49 | 50 | # any global variable defined by addons MUST be prefixed by addon name 51 | EXAMPLE_ME="example" 52 | 53 | # initialize after installation or update 54 | if [[ "$1" = "init"* ]]; then 55 | : # nothing to do 56 | fi 57 | 58 | 59 | # register on startbot 60 | if [[ "$1" = "start"* ]]; then 61 | # register to reply 62 | BASHBOT_EVENT_REPLY["${EXAMPLE_ME}"]="${EXAMPLE_ME}_reply" 63 | EXAMPLE_ADMIN="$(getConfigKey "botadmin")" 64 | 65 | # any function defined by addons MUST be prefixed by addon name 66 | # function local variables can have any name, but must be LOCAL 67 | example_reply(){ 68 | local msg="message" event="$1" key="$2" 69 | send_markdown_message "${CHAT[ID]}" "User *${USER[USERNAME]}* replied to ${msg} from *${REPLYTO[USERNAME]}* (Event: ${event} Key:{${key})" & 70 | } 71 | 72 | # register to inline and command 73 | BASHBOT_EVENT_INLINE["${EXAMPLE_ME}"]="${EXAMPLE_ME}_multievent" 74 | BASHBOT_EVENT_CMD["${EXAMPLE_ME}"]="${EXAMPLE_ME}_multievent" 75 | 76 | # any function defined by addons MUST be prefixed by addon name 77 | # function local variables can have any name, but must be LOCAL 78 | example_multievent(){ 79 | local event="$1" key="$2" 80 | local msg="${MESSAGE[0]}" 81 | # shellcheck disable=SC2154 82 | [ "${type}" = "inline" ] && msg="${iQUERY[0]}" 83 | send_normal_message "${CHAT[ID]}" "${event} from ${key} received: ${msg}" & 84 | } 85 | 86 | BASHBOT_EVENT_TIMER["${EXAMPLE_ME}after5min","-5"]="${EXAMPLE_ME}_after5min" 87 | 88 | # any function defined by addons MUST be prefixed by addon name 89 | # function local variables can have any name, but must be LOCAL 90 | example_after5min(){ 91 | send_markdown_message "${EXAMPLE_ADMIN}" "This is a one time event after 5 Minutes!" & 92 | } 93 | 94 | BASHBOT_EVENT_TIMER["${EXAMPLE_ME}every2min","2"]="${EXAMPLE_ME}_every2min" 95 | 96 | # any function defined by addons MUST be prefixed by addon name 97 | # function local variables can have any name, but must be LOCAL 98 | example_every2min(){ 99 | send_markdown_message "${EXAMPLE_ADMIN}" "This a a every 2 minute event ..." & 100 | } 101 | 102 | # register to send 103 | BASHBOT_EVENT_SEND["${EXAMPLE_ME}"]="${EXAMPLE_ME}_log" 104 | EXAMPLE_LOG="${BASHBOT_ETC:-.}/addons/${EXAMPLE_ME}.log" 105 | 106 | # any function defined by addons MUST be prefixed by addon name 107 | # function local variables can have any name, but must be LOCAL 108 | # $1 = send / upload 109 | # $* remaining args are from sendJson and sendUpload 110 | # Note: do not call any send message functions from EVENT_SEND! 111 | example_log(){ 112 | local send="$1"; shift 113 | printf "%s: Type: %s Args: %s\n" "$(date)" "${send}" "$*" >>"${EXAMPLE_LOG}" 114 | } 115 | fi 116 | -------------------------------------------------------------------------------- /bashbot.rc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # description: Start or stop telegram-bash-bot 3 | # 4 | # example service script to run bashbot in background as specified user 5 | # 6 | # tested on: ubuntu, opensuse, debian 7 | # 8 | #### $$VERSION$$ v1.52-1-g0dae2db 9 | # shellcheck disable=SC2009 10 | # shellcheck disable=SC2181 11 | # shellcheck disable=SC2250 12 | 13 | # 14 | ### BEGIN INIT INFO 15 | # Provides: bashbot 16 | # Required-Start: $network $syslog 17 | # Required-Stop: $network 18 | # Default-Start: 2 3 5 19 | # Default-Stop: 0 1 6 20 | # Description: Start or stop telegram-bot-bash server 21 | ### END INIT INFO 22 | 23 | # save default values 24 | TERM="" # disable bashbot clear and color output 25 | runcmd="echo Dry run:" # not activated until you edit lines below 26 | 27 | ####################### 28 | # Configuration Section 29 | 30 | # edit the next line to fit the user you want to run bashbot, e.g. nobody: 31 | runas="nobody" 32 | 33 | # uncomment one of the example lines to fit your system 34 | # runcmd="su ${runas} -s /bin/bash -c " # runasuser with *su* 35 | # runcmd="/usr/sbin/runuser ${runas} -s /bin/bash -c " # runasuser with *runuser* 36 | 37 | # edit the values of the following lines to fit your config: 38 | # your bot name as given to botfather, e.g. mysomething_bot 39 | name="" 40 | [ -z "${name}" ] && name="unknown" 41 | 42 | # your bot installation dir 43 | bashbotdir="/usr/local/telegram-bot-bash" 44 | databotdir="${bashbotdir}/data-bot-bash" 45 | FIFO="${databotdir}/webhook-fifo-${name}" 46 | 47 | # programs to run 48 | bashbot="cd ${bashbotdir}; ${bashbotdir}/bashbot.sh" 49 | webhook="cd ${bashbotdir}; nohup ${bashbotdir}/bin/process_batch.sh --startbot --watch ${FIFO}" 50 | # set additionl parameter, e.g. debug 51 | mode="" 52 | 53 | # select logfile for webhook start stop and script errors 54 | hooklog="DEBUG" 55 | hooklog="WEBHOOK" 56 | 57 | # END Configuration 58 | ####################### 59 | 60 | 61 | # check for bot status 62 | stat="" 63 | ps -f -u "${runas}" | grep "${name}" | grep -qF "bashbot.sh startbot" 64 | if [ "$?" = "0" ]; then 65 | # printf "bashbot (%s) is running in poll mode\n" "${name}" 66 | stat="${stat} polling" 67 | fi 68 | ps -f -u "${runas}" | grep "${name}" | grep -qF "process_batch.sh --startbot" 69 | if [ "$?" = "0" ]; then 70 | #printf "bashbot (%s) is running in webhook mode\n" "${name}" 71 | stat="${stat} webhook" 72 | elif [ "${name}" != "unknown" ]; then 73 | #printf "bashbot (%s) is stopped\n" "${name}" 74 | stat="stop" 75 | else 76 | stat="unknown" 77 | fi 78 | 79 | case "$1" in 80 | 'start') 81 | [ "${stat}" != "stop" ] && printf "Warning, bot is already running in mode: %s\n" "${stat}" 82 | $runcmd "$bashbot start $mode" # >/dev/null 2>&1 >${bashbotdir}/logs/${hooklog}.log &" # >/dev/null 2>&1 /dev/null; wait ${KILLID} 2>/dev/null" 105 | sleep 1 106 | fi 107 | RETVAL=$? 108 | $0 status 109 | ;; 110 | 'status') 111 | case "${stat}" in 112 | *"poll"*) printf "bashbot (%s) is running in polling mode\n" "${name}" 113 | RETVAL=0 114 | ;;& 115 | *"hook"*) printf "bashbot (%s) is running in webhook mode\n" "${name}" 116 | RETVAL=0 117 | ;; 118 | *"stop"*) printf "bashbot (%s) is not running\n" "${name}" 119 | RETVAL=1 120 | ;; 121 | *) printf "bashbot (%s) status is %s\n" "${name}" "${stat}" 122 | RETVAL=2 123 | ;; 124 | esac 125 | ;; 126 | 'restart'|'reload') 127 | $0 stop; $0 start 128 | RETVAL=$? 129 | ;; 130 | 'restarthook'|'reloadhook') 131 | $0 stophook; $0 starthook 132 | RETVAL=$? 133 | ;; 134 | 'restartback') 135 | $0 suspendback; $0 resumeback 136 | RETVAL=$? 137 | ;; 138 | 'suspendback'|'resumeback'|'killback') 139 | # shellcheck disable=SC2250 140 | $runcmd "$bashbot $1" 141 | RETVAL=$? 142 | # kill inotifywait from runuser 143 | if [ "$1" != "resumeback" ]; then 144 | # shellcheck disable=SC2046 145 | kill -9 $(ps -u "${runas}" | grep inotifywait | sed 's/ .*//') >/dev/null 2>&1 146 | fi 147 | ;; 148 | *) 149 | printf "%s\n" "Usage: $0 [ start | stop | restart | starthook | stophook | restarthook ]" 150 | printf "%s\n" " $0 [ status | restartback | suspendback | resumeback | killback ]" 151 | RETVAL=1 152 | ;; 153 | esac 154 | exit "${RETVAL}" 155 | -------------------------------------------------------------------------------- /bin/any_command.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # shellcheck disable=SC1090,SC2034,SC2059 3 | #=============================================================================== 4 | # 5 | # FILE: bin/any_command.sh 6 | # 7 | USAGE='any_command.sh [-h|--help] [--force|--reference] bot_command args ...' 8 | # 9 | # DESCRIPTION: execute (almost) any bashbot command/function 10 | # can be used for testing commands while bot development 11 | # 12 | # OPTIONS: -- force - execute unknown commands/functions 13 | # by default only commands in 6_reference.md are allowed 14 | # 15 | # -h - display short help 16 | # --help - this help 17 | # 18 | # Set BASHBOT_HOME to your installation directory 19 | # 20 | # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ 21 | # AUTHOR: KayM (gnadelwartz), kay@rrr.de 22 | # CREATED: 30.01.2021 10:24 23 | # 24 | #### $$VERSION$$ v1.52-1-g0dae2db 25 | #=============================================================================== 26 | 27 | #### 28 | # parse args 29 | COMMAND="" 30 | 31 | # set bashbot environment 32 | source "${0%/*}/bashbot_env.inc.sh" "debug" # debug 33 | print_help "$1" 34 | 35 | 36 | error="" 37 | # check options 38 | if [[ "$1" = "--force" ]]; then 39 | # skip checks 40 | shift 41 | else 42 | # check for --ref 43 | ref="$1"; [[ "$1" == "--ref"* ]] && shift 44 | if [ "${#1}" -lt 11 ];then 45 | printf "${RED}Command must be minimum 11 characters!${NC}\n" 46 | error=3 47 | fi 48 | if [[ "$1" != *"_"* ]];then 49 | printf "${RED}Command must contain _ (underscore)!${NC}\n" 50 | error=3 51 | fi 52 | # simple hack to get allowed commands from doc 53 | if grep -q "^##### $1" <<<"$(sed -n -e '/^##### _is_/,$ d' -e '/^##### /p' "${BASHBOT_HOME:-..}doc/"6_*)"; then 54 | # oiutput reference and exit 55 | if [[ "${ref}" == "--ref"* ]]; then 56 | sed -n -e '/^##### '"$1"'/,/^##/ p' "${BASHBOT_HOME:-..}doc/"6_* 57 | exit 58 | fi 59 | else 60 | printf "Command ${GREY}%s${NC} not found in 6_reference.md, use ${GREY}--force${NC} to execute!\n" "$1" 61 | error=4 62 | fi 63 | [ -n "${error}" ] && exit "${error}" 64 | fi 65 | 66 | 67 | #### 68 | # ready, do stuff here ----- 69 | COMMAND="$1" 70 | if [ "$2" == "BOTADMIN" ]; then 71 | ARG1="${BOTADMIN}" 72 | else 73 | ARG1="$2" 74 | fi 75 | 76 | # clear result and response 77 | BOTSENT=() 78 | UPD=() 79 | 80 | # send message in selected format 81 | "${COMMAND}" "${ARG1}" "${@:3}" 82 | 83 | # output result an telegram response 84 | print_result 85 | print_response 86 | -------------------------------------------------------------------------------- /bin/bashbot_env.inc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #=============================================================================== 3 | # 4 | # FILE: bashbot_env.inc.sh 5 | # 6 | # USAGE: source bashbot_env.inc.sh [debug] 7 | # 8 | # DESCRIPTION: set bashbot environment for all scripts in this directory 9 | # 10 | # OPTIONS: $1 - will be forwarded ro bashbot, e.g. debug 11 | # 12 | # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ 13 | # AUTHOR: KayM (gnadelwartz), kay@rrr.de 14 | # CREATED: 18.12.2020 12:27 15 | # 16 | #### $$VERSION$$ v1.52-1-g0dae2db 17 | #=============================================================================== 18 | 19 | ############ 20 | # set where your bashbot lives 21 | export BASHBOT_HOME BASHBOT_ETC BASHBOT_VAR FILE_REGEX ME 22 | 23 | # default: one dir up 24 | BASHBOT_HOME="$(cd "${BASH_SOURCE[0]%/*}/../" >/dev/null 2>&1 && pwd)" 25 | [ "${BASHBOT_HOME}" = "" ] && BASHBOT_HOME="../" 26 | 27 | # set you own BASHBOT_HOME if different, e.g. 28 | # BASHBOT_HOME="/usr/local/telegram-bot-bash" 29 | BASHBOT_VAR="${BASHBOT_HOME}" 30 | BASHBOT_ETC="${BASHBOT_HOME}" 31 | 32 | ##### 33 | # if files are not readable, eviroment is wrong or bashbot is not initialized 34 | 35 | # check for bashbot 36 | if [ ! -r "${BASHBOT_HOME}/bashbot.sh" ]; then 37 | printf "%s\n" "Bashbot.sh not found in \"${BASHBOT_HOME}\"" 38 | exit 4 39 | fi 40 | 41 | dev=" Are we in dev or did you forget to run init?" 42 | # check for botconfig.jssh readable 43 | if [ ! -r "${BASHBOT_ETC}/botconfig.jssh" ]; then 44 | printf "%s\n" "Bashbot config file in \"${BASHBOT_ETC}\" does not exist or is not readable. ${dev}" 45 | exit 3 46 | fi 47 | # check for count.jssh readable 48 | if [ ! -r "${BASHBOT_VAR}/count.jssh" ]; then 49 | printf "%s\n" "Bashbot count file in \"${BASHBOT_VAR}\" does not exist or is not readable. ${dev}" 50 | exit 3 51 | fi 52 | 53 | # shellcheck disable=SC1090 54 | source "${BASHBOT_HOME}/bashbot.sh" source "$1" 55 | 56 | # overwrite bot FILE regex to BASHBOT_VAR 57 | # change this to the location you want to allow file uploads from 58 | UPLOADDIR="${BASHBOT_VAR%/bin*}" 59 | FILE_REGEX="${UPLOADDIR}/.*" 60 | 61 | # get and check ADMIN and NAME 62 | BOTNAME="$(getConfigKey "botname")" 63 | ME="${BOTNAME}" 64 | [[ -z "${BOTADMIN}" || "${BOTADMIN}" == "?" ]] && printf "%s\n" "${ORANGE}Warning: Botadmin not set, send bot command${NC} /start" 65 | [[ -z "${BOTNAME}" ]] && printf "%s\n" "${ORANGE}Warning: Botname not set, run bashbot.sh botname" 66 | 67 | # default webhook pipe 68 | export WEBHOOK="${DATADIR}/webhook-fifo-${ME}" 69 | 70 | 71 | # output command result or Telegram response 72 | print_result() { jssh_printDB "BOTSENT" | sort -r; } 73 | print_response() { jssh_printDB "UPD"; } 74 | 75 | # check and output help 76 | print_help() { 77 | case "$1" in 78 | '') 79 | printf "missing arguments\n" 80 | ;& 81 | "-h"*) 82 | printf 'usage: %s\n' "${USAGE}" 83 | exit 1 84 | ;; 85 | '--h'*) 86 | sed -n '/^#====/,/^#====/p' <"$0" 87 | exit 1 88 | ;; 89 | esac 90 | } 91 | 92 | -------------------------------------------------------------------------------- /bin/bashbot_stats.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # shellcheck disable=SC1090,SC2034 3 | #=============================================================================== 4 | # 5 | # FILE: bin/bashbot_stats.sh 6 | # 7 | USAGE='bashbot_stats.sh [-h|--help] [debug]' 8 | # 9 | # DESCRIPTION: output bashbot user stats 10 | # 11 | # OPTIONS: -h - display short help 12 | # --help - this help 13 | # 14 | # Set BASHBOT_HOME to your installation directory 15 | # 16 | # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ 17 | # AUTHOR: KayM (gnadelwartz), kay@rrr.de 18 | # CREATED: 23.12.2020 20:34 19 | # 20 | #### $$VERSION$$ v1.52-1-g0dae2db 21 | #=============================================================================== 22 | 23 | # set bashbot environment 24 | source "${0%/*}/bashbot_env.inc.sh" "$1" 25 | [ -n "$1" ] && print_help "$1" 26 | 27 | #### 28 | # ready, do stuff here ----- 29 | 30 | echo -e "${GREEN}Hi I'm ${BOTNAME}.${NC}" 31 | declare -A STATS 32 | jssh_readDB_async "STATS" "${COUNTFILE}" 33 | for MSG in ${!STATS[*]} 34 | do 35 | [[ ! "${MSG}" =~ ^[0-9-]*$ ]] && continue 36 | (( USERS++ )) 37 | done 38 | for MSG in ${STATS[*]} 39 | do 40 | (( MESSAGES+=MSG )) 41 | done 42 | if [ "${USERS}" != "" ]; then 43 | echo -e "${GREY}A total of ${NC}${MESSAGES}${GREY} messages from ${NC}${USERS}${GREY} users are processed.${NC}" 44 | else 45 | echo -e "${ORANGE}No one used your bot so far ...${NC}" 46 | fi 47 | jssh_readDB_async "STATS" "${BLOCKEDFILE}" 48 | for MSG in ${!STATS[*]} 49 | do 50 | [[ ! "${MSG}" =~ ^[0-9-]*$ ]] && continue 51 | (( BLOCKS++ )) 52 | done 53 | if [ "${BLOCKS}" != "" ]; then 54 | echo -e "${ORANGE}${BLOCKS} user(s) are blocked:${NC}${GREY}" 55 | sort -r "${BLOCKEDFILE}.jssh" 56 | echo -e "${NC}\c" 57 | else 58 | echo -e "${GREEN}No user is blocked currently ...${NC}" 59 | fi 60 | # show user created bot stats 61 | _exec_if_function my_bashbot_stats "$@" 62 | 63 | -------------------------------------------------------------------------------- /bin/delete_message.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # shellcheck disable=SC1090,SC2034 3 | #=============================================================================== 4 | # 5 | # FILE: bin/delete_message.sh 6 | # 7 | USAGE='delete_message.sh [-h|--help] "CHAT[ID]" "MESSAGE[ID]" [debug]' 8 | # 9 | # DESCRIPTION: delete a message in the given user/group 10 | # 11 | # OPTIONS: CHAT[ID] - ID number of CHAT or BOTADMIN 12 | # MESSAGE[ID] - message to delete 13 | # 14 | # -h - display short help 15 | # --help - this help 16 | # 17 | # Set BASHBOT_HOME to your installation directory 18 | # 19 | # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ 20 | # AUTHOR: KayM (gnadelwartz), kay@rrr.de 21 | # CREATED: 03.01.2021 15:37 22 | # 23 | #### $$VERSION$$ v1.52-1-g0dae2db 24 | #=============================================================================== 25 | 26 | #### 27 | # parse args 28 | DELETE="delete_message" 29 | 30 | # set bashbot environment 31 | source "${0%/*}/bashbot_env.inc.sh" "${3:-debug}" # $3 debug 32 | print_help "$1" 33 | 34 | #### 35 | # ready, do stuff here ----- 36 | if [ "$1" == "BOTADMIN" ]; then 37 | CHAT="${BOTADMIN}" 38 | else 39 | CHAT="$1" 40 | fi 41 | 42 | # delete message 43 | "${DELETE}" "${CHAT}" "$2" 44 | 45 | [ "${BOTSENT[OK]}" = "true" ] && BOTSENT[ID]="$2" 46 | 47 | # output send message result 48 | print_result 49 | -------------------------------------------------------------------------------- /bin/edit_buttons.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # shellcheck disable=SC1090,SC2034 3 | #=============================================================================== 4 | # 5 | # FILE: bin/edit_buttons.sh 6 | # 7 | USAGE='send_message.sh [-h|--help] "CHAT[ID]" "MESSAGE[ID]" "text|url" ...' 8 | # 9 | # DESCRIPTION: send a send buttons in a row to the given user/group 10 | # 11 | # OPTIONS: CHAT[ID] - ID number of CHAT or BOTADMIN to send to yourself 12 | # MESSAGE[ID] - ID of MESSAGE with buttons to edit 13 | # text|url - buttons to send, each button as "text|url" pair or 14 | # "url" only to show url as text also, "" starts new row 15 | # "url" not http(s):// or tg:// is sent as callback_data 16 | # 17 | # -h - display short help 18 | # --help - this help 19 | # 20 | # EXAMPLE: 2 buttons on 2 rows, first shows Amazon, second the url as text 21 | # send_buttons.sh "Amazon|https://www.amazon.com" "" "https://mydealz.de" ... 22 | # 23 | # Set BASHBOT_HOME to your installation directory 24 | # 25 | # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ 26 | # AUTHOR: KayM (gnadelwartz), kay@rrr.de 27 | # CREATED: 21.01.2021 08:10 28 | # 29 | #### $$VERSION$$ v1.52-1-g0dae2db 30 | #=============================================================================== 31 | 32 | #### 33 | # parse args 34 | SEND="edit_inline_keyboard" 35 | 36 | # set bashbot environment 37 | source "${0%/*}/bashbot_env.inc.sh" "debug" 38 | print_help "$1" 39 | 40 | #### 41 | # ready, do stuff here ----- 42 | if [ "$1" == "BOTADMIN" ]; then 43 | CHAT="${BOTADMIN}" 44 | else 45 | CHAT="$1" 46 | fi 47 | MESSAGE_ID="$2" 48 | shift 2 49 | 50 | # send message in selected format 51 | "${SEND}" "${CHAT}" "${MESSAGE_ID}" "$(_button_row "$@")" 52 | 53 | # output send message result 54 | print_result 55 | -------------------------------------------------------------------------------- /bin/edit_message.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # shellcheck disable=SC1090,SC2034 3 | #=============================================================================== 4 | # 5 | # FILE: bin/edit_message.sh 6 | # 7 | USAGE='send_edit_message.sh [-h|--help] [format|caption] "CHAT[ID]" "MESSAGE[ID]" "message ...." [debug]' 8 | # 9 | # DESCRIPTION: replace a message in the given user/group 10 | # 11 | # OPTIONS: format - normal, markdown, html or caption for file caption (optional) 12 | # CHAT[ID] - ID number of CHAT or BOTADMIN to send to yourself 13 | # MESSAGE[ID] - message to replace 14 | # message - message to send in specified format 15 | # if no format is given send_normal_message() format is used 16 | # 17 | # -h - display short help 18 | # --help - this help 19 | # 20 | # Set BASHBOT_HOME to your installation directory 21 | # 22 | # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ 23 | # AUTHOR: KayM (gnadelwartz), kay@rrr.de 24 | # CREATED: 23.12.2020 16:52 25 | # 26 | #### $$VERSION$$ v1.52-1-g0dae2db 27 | #=============================================================================== 28 | 29 | #### 30 | # parse args 31 | SEND="edit_normal_message" 32 | case "$1" in 33 | "nor"*|"tex"*) 34 | SEND="edit_normal_message" 35 | shift 36 | ;; 37 | "mark"*) 38 | SEND="edit_markdownv2_message" 39 | shift 40 | ;; 41 | "htm"*) 42 | SEND="edit_html_message" 43 | shift 44 | ;; 45 | "cap"*) 46 | SEND="edit_message_caption" 47 | shift 48 | ;; 49 | esac 50 | 51 | # set bashbot environment 52 | source "${0%/*}/bashbot_env.inc.sh" "${4:-debug}" # $4 debug 53 | print_help "$1" 54 | 55 | #### 56 | # ready, do stuff here ----- 57 | if [ "$1" == "BOTADMIN" ]; then 58 | CHAT="${BOTADMIN}" 59 | else 60 | CHAT="$1" 61 | fi 62 | 63 | # send message in selected format 64 | "${SEND}" "${CHAT}" "$2" "$3" 65 | 66 | # output send message result 67 | print_result 68 | -------------------------------------------------------------------------------- /bin/kickban_user.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # shellcheck disable=SC1090,SC2034 3 | #=============================================================================== 4 | # 5 | # FILE: bin/kickban_user.sh 6 | # 7 | USAGE='kickban_user.sh [-h|--help] [-u|--unban] "CHAT[ID]" "USER[ID]" [debug]' 8 | # 9 | # DESCRIPTION: kickban or unban a user from the given group 10 | # 11 | # OPTIONS: -u | --unban - unban user 12 | # CHAT[ID] - ID number of CHAT or BOTADMIN to send to yourself 13 | # USER[ID] - user to (un)ban 14 | # 15 | # -h - display short help 16 | # --help - this help 17 | # 18 | # 19 | # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ 20 | # AUTHOR: KayM (gnadelwartz), kay@rrr.de 21 | # CREATED: 25.01.2021 20:34 22 | # 23 | #### $$VERSION$$ v1.52-1-g0dae2db 24 | #=============================================================================== 25 | 26 | #### 27 | # parse args 28 | BAN="kick_chat_member" 29 | case "$1" in 30 | "-u"|"--unban") 31 | BAN="unban_chat_member" 32 | shift 33 | ;; 34 | esac 35 | 36 | # set bashbot environment 37 | source "${0%/*}/bashbot_env.inc.sh" "${3:-debug}" # $3 debug 38 | print_help "$1" 39 | 40 | #### 41 | # ready, do stuff here ----- 42 | 43 | # send message in selected format 44 | "${BAN}" "$1" "$2" 45 | 46 | # output send message result 47 | print_result 48 | -------------------------------------------------------------------------------- /bin/process_batch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # shellcheck disable=SC1090,SC2034,SC2059 3 | #=============================================================================== 4 | # 5 | # FILE: bin/process_batch.sh 6 | # 7 | USAGE='process_batch.sh [-h|--help] [-s|--startbot] [-w|--watch] [-n|--lines n] [file] [debug]' 8 | # 9 | # DESCRIPTION: processes last 10 telegram updates in file, one update per line 10 | # 11 | # -s --startbot load addons, start TIMER, trigger startup actions 12 | # -w --watch watch for new updates added to file 13 | # -n --lines read only last "n" lines 14 | # file to read updates from 15 | # empty means read from webhook pipe 16 | # 17 | # -h - display short help 18 | # --help - this help 19 | # 20 | # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ 21 | # AUTHOR: KayM (gnadelwartz), kay@rrr.de 22 | # CREATED: 27.02.2021 13:14 23 | # 24 | #### $$VERSION$$ v1.52-1-g0dae2db 25 | #=============================================================================== 26 | 27 | #### 28 | # parse args 29 | COMMAND="process_multi_updates" 30 | lines="-n 10" 31 | mode="batch" 32 | 33 | opt=0 34 | while [[ "${opt}" -lt 5 && "$1" == "-"* ]] 35 | do 36 | (( opt++ )) 37 | case "$1" in 38 | "-s"|"--startbot") 39 | startbot="yes" 40 | shift 41 | ;; 42 | "-w"|"--watch") 43 | follow="-f" 44 | mode="webhook" 45 | shift 46 | ;; 47 | "-n"|"--lines") 48 | lines="-n $2" 49 | shift 2 50 | ;; 51 | esac 52 | done 53 | 54 | # set bashbot environment 55 | source "${0%/*}/bashbot_env.inc.sh" "debug" # debug 56 | print_help "${1:-nix}" 57 | 58 | # empty file is webhook 59 | file="${WEBHOOK}" 60 | [ -n "$1" ] && file="$1" 61 | 62 | # start bot 63 | if [ -n "${startbot}" ]; then 64 | # warn when starting bot without pipe 65 | [ -p "${file}" ] || printf "%(%c)T: %b\n" -1 "${ORANGE}Warning${NC}: File is not a pipe:${GREY} ${file##*/}${NC}" 66 | start_bot "$2" "${mode}" 67 | printf "%(%c)T: %b\n" -1 "${GREEN}Bot startup actions done, start ${mode} updates ...${NC}" 68 | fi 69 | # check file exist 70 | if [[ ! -r "${file}" || -d "${file}" ]]; then 71 | printf "%(%c)T: %b\n" -1 "${RED}Error${NC}: File not readable:${GREY} ${file}${NC}." 72 | exit 1 73 | fi 74 | 75 | #### 76 | # ready, do stuff here ----- 77 | 78 | # kill all sub processes on exit 79 | trap 'printf "%(%c)T: %s\n" -1 "Bot in '"${mode}"' mode stopped"; kill $(jobs -p) 2>/dev/null; wait $(jobs -p) 2>/dev/null; send_normal_message "'"${BOTADMIN}"'" "Bot '"${BOTNAME} ${mode}"' stopped ..."' EXIT HUP QUIT 80 | 81 | # wait after (first) update to avoid processing to many in parallel 82 | UPDWAIT="0.5" 83 | # use tail to read appended updates 84 | # shellcheck disable=SC2086,SC2248 85 | tail ${follow} ${lines} "${file}" 2>/dev/null |\ 86 | while IFS="" read -r input 2>/dev/null 87 | do 88 | # read json from stdin and convert update format 89 | # replace any ID named BOTADMIN with ID of bot admin 90 | : "${input//\"id\":BOTADMIN,/\"id\":${BOTADMIN},}" 91 | json='{"result": ['"${_}"']}' 92 | UPDATE="$(${JSONSHFILE} -b -n <<<"${json}" 2>/dev/null)" 93 | 94 | # process telegram update 95 | "${COMMAND}" "$2" 96 | sleep "${UPDWAIT}" 97 | UPDWAIT="0.05" 98 | done 99 | -------------------------------------------------------------------------------- /bin/process_update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # shellcheck disable=SC1090,SC2034,SC2059 3 | #=============================================================================== 4 | # 5 | # FILE: bin/process_update.sh 6 | # 7 | USAGE='process_update.sh [-h|--help] [debug] [/dev/null)" 38 | 39 | # process telegram update 40 | "${COMMAND}" "$1" 41 | 42 | -------------------------------------------------------------------------------- /bin/promote_user.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # shellcheck disable=SC1090,SC2034 3 | #=============================================================================== 4 | # 5 | # FILE: bin/promote_user.sh 6 | # 7 | USAGE='promote_user.sh [-h|--help] "CHAT[ID]" "USER[ID]" "right[:true|false]" ..' 8 | # 9 | # DESCRIPTION: promote / denote user rights in given group 10 | # 11 | # OPTIONS: CHAT[ID] - ID number of CHAT or BOTADMIN to send to yourself 12 | # USER[ID] - user to (un)ban 13 | # rights[:true|false] - rights to grant in long or short form, 14 | # followed by :true to grant or :false to renove 15 | # long: is_anonymous can_change_info can_post_messages can_edit_messages 16 | # can_delete_messages can_invite_users can_restrict_members 17 | # can_pin_messages can_promote_member` 18 | # short: anon change post edit delete invite restrict pin promote 19 | # 20 | # -h - display short help 21 | # --help - this help 22 | # 23 | # 24 | # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ 25 | # AUTHOR: KayM (gnadelwartz), kay@rrr.de 26 | # CREATED: 25.01.2021 22:34 27 | # 28 | #### $$VERSION$$ v1.52-1-g0dae2db 29 | #=============================================================================== 30 | 31 | #### 32 | # parse args 33 | PROMOTE="promote_chat_member" 34 | 35 | # set bashbot environment 36 | source "${0%/*}/bashbot_env.inc.sh" "debug" # debug 37 | print_help "$1" 38 | 39 | #### 40 | # ready, do stuff here ----- 41 | 42 | # send message in selected format 43 | "${PROMOTE}" "$@" 44 | 45 | # output send message result 46 | print_result 47 | -------------------------------------------------------------------------------- /bin/send_broadcast.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # shellcheck disable=SC1090,SC2034 3 | #=============================================================================== 4 | # shellcheck disable=SC2059 5 | # 6 | # FILE: bin/broadcast_message.sh 7 | # 8 | USAGE='broadcast_message.sh [-h|--help] [--doit] [--groups|--both|--db=file] [format] "message ...." [debug]' 9 | # 10 | # DESCRIPTION: send a message to all users listed in a jsonDB (default count db) 11 | # 12 | # OPTIONS: --doit - broadcast is dangerous, simulate run without --doit 13 | # --groups - send to groups instead of users 14 | # --both - send to users and groups (default with --db) 15 | # --db name - send to all user/groups in jsonDB database (e.g. blocked) 16 | # db file: name.jssh, db keys are user/chat id, values are ignored 17 | # 18 | # format - normal, markdown, html (optional) 19 | # message - message to send in specified format 20 | # if no format is givern send_message() format is used 21 | # 22 | # -h - display short help 23 | # --help - this help 24 | # 25 | # Set BASHBOT_HOME to your installation directory 26 | # 27 | # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ 28 | # AUTHOR: KayM (gnadelwartz), kay@rrr.de 29 | # CREATED: 16.12.2020 16:14 30 | # 31 | #### $$VERSION$$ v1.52-1-g0dae2db 32 | #=============================================================================== 33 | 34 | #### 35 | # minimum messages seen in a chat before send a broadcast to it 36 | MINCOUNT=2 37 | USERDB="" 38 | 39 | #### 40 | # broadcast is dangerous, without --doit we do a dry run ... 41 | if [ "$1" = "--doit" ]; then 42 | DOIT="yes" 43 | shift 44 | fi 45 | 46 | #### 47 | # send to users by default, --group sends groups, --both to both 48 | SENDTO="users" 49 | if [ "$1" = "--both" ]; then 50 | GROUPSALSO=" and groups" 51 | shift 52 | elif [ "$1" = "--groups" ]; then 53 | SENDTO="groups" 54 | GROUPSALSO=" only" 55 | shift 56 | elif [ "$1" = "--db" ]; then 57 | USERDB="${2%.jssh}" 58 | MINCOUNT="" 59 | GROUPSALSO=" and groups" 60 | shift 2 61 | fi 62 | 63 | #### 64 | # parse args ----------------- 65 | SEND="send_message" 66 | case "$1" in 67 | "nor"*|"tex"*) 68 | SEND="send_normal_message" 69 | shift 70 | ;; 71 | "mark"*) 72 | SEND="send_markdownv2_message" 73 | shift 74 | ;; 75 | "html") 76 | SEND="send_html_message" 77 | shift 78 | ;; 79 | esac 80 | 81 | # set bashbot environment 82 | source "${0%/*}/bashbot_env.inc.sh" "$2" # $3 debug 83 | print_help "$1" 84 | 85 | # read in users from given DB or count.jssh 86 | database="${USERDB:-${COUNTFILE}}" 87 | declare -A SENDALL 88 | jssh_readDB_async "SENDALL" "${database}" 89 | if [ -z "${SENDALL[*]}" ]; then 90 | printf "${ORANGE}User database not found or empty: ${NC}${database}\n" 91 | fi 92 | 93 | # loop over users 94 | printf "${GREEN}Sending broadcast message to ${SENDTO}${GROUPSALSO} of ${BOTNAME} using database:${NC}${GREY} ${database##*/}" 95 | 96 | { # dry run 97 | [ -z "${DOIT}" ] && printf "${NC}\n${ORANGE}DRY RUN! use --doit as first argument to execute broadcast...${NC}\n" 98 | 99 | for USER in ${!SENDALL[*]} 100 | do 101 | # send to users, groups or both ... 102 | [[ -z "${GROUPSALSO}" && "${USER}" == *"-"* ]] && continue 103 | [[ "${SENDTO}" != "users" && "${USER}" != *"-"* ]] && continue 104 | # ignore everything not a user or group 105 | [[ ! "${USER}" =~ ^[0-9-]*$ ]] && continue 106 | # ignore chats with no count or lower MINCOUNT 107 | [[ -n "${MINCOUNT}" && ( ! "${SENDALL[${USER}]}" =~ ^[0-9]*$ || "${SENDALL[${USER}]}" -lt "${MINCOUNT}" ) ]] && continue 108 | (( COUNT++ )) 109 | if [ -z "${DOIT}" ]; then 110 | printf "${SEND} ${USER} $1 $2\n" 111 | else 112 | "${SEND}" "${USER}" "$1" "$2" 113 | printf "." 1>&2 114 | # ups, kicked or banned ... 115 | if [ "${BOTSENT[ERROR]}" = "403" ]; then 116 | # remove chat from future broadcasts 117 | jssh_insertKeyDB "${USER}" "${SENDALL[${USER}]} banned" "${COUNTFILE}" 118 | printf "${ORANGE}Warning: bot banned from chat${NC} %s ${ORANGE}after${NC} %s ${ORANGE}commands${NC}\n"\ 119 | "${USER}" "${SENDALL[${USER}]}" 120 | fi 121 | sleep 0.1 122 | fi 123 | done 124 | # printout final stats message 125 | printf "${NC}\n${GREEN}Message${NC} $1 ${GREEN}sent to${NC} ${COUNT} ${GREEN}${SENDTO}${GROUPSALSO}.${NC}\n" 126 | } | more 127 | 128 | -------------------------------------------------------------------------------- /bin/send_buttons.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # shellcheck disable=SC1090,SC2034 3 | #=============================================================================== 4 | # 5 | # FILE: bin/send_message.sh 6 | # 7 | USAGE='send_message.sh [-h|--help] "CHAT[ID]" "message" "text|url" ...' 8 | # 9 | # DESCRIPTION: send a send buttons in a row to the given user/group 10 | # 11 | # OPTIONS: CHAT[ID] - ID number of CHAT or BOTADMIN to send to yourself 12 | # message - message to send 13 | # text|url - buttons to send, each button as "text|url" pair or 14 | # "url" not http(s):// or tg:// is sent as callback_data 15 | # "url" only to show url as text also, "" starts new row 16 | # 17 | # -h - display short help 18 | # --help - this help 19 | # 20 | # EXAMPLE: 2 buttons on 2 rows, first shows Amazon, second the url as text 21 | # send_buttons.sh "Amazon|https://www.amazon.com" "" "https://mydealz.de" ... 22 | # 23 | # Set BASHBOT_HOME to your installation directory 24 | # 25 | # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ 26 | # AUTHOR: KayM (gnadelwartz), kay@rrr.de 27 | # CREATED: 18.01.2021 11:34 28 | # 29 | #### $$VERSION$$ v1.52-1-g0dae2db 30 | #=============================================================================== 31 | 32 | #### 33 | # parse args 34 | SEND="send_inline_keyboard" 35 | 36 | # set bashbot environment 37 | source "${0%/*}/bashbot_env.inc.sh" "debug" 38 | print_help "$1" 39 | 40 | #### 41 | # ready, do stuff here ----- 42 | if [ "$1" == "BOTADMIN" ]; then 43 | CHAT="${BOTADMIN}" 44 | else 45 | CHAT="$1" 46 | fi 47 | MESSAGE="$2" 48 | shift 2 49 | 50 | # send message in selected format 51 | "${SEND}" "${CHAT}" "${MESSAGE}" "$(_button_row "$@")" 52 | 53 | # output send message result 54 | print_result 55 | -------------------------------------------------------------------------------- /bin/send_dice.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # shellcheck disable=SC1090,SC2034 3 | #=============================================================================== 4 | # 5 | # FILE: bin/send_dice.sh 6 | # 7 | USAGE='send_dice.sh [-h|--help] "CHAT[ID]" "emoji" [debug]' 8 | # 9 | # DESCRIPTION: send an animated emoji (dice) to given chat 10 | # 11 | # OPTIONS: CHAT[ID] - ID number of CHAT or BOTADMIN to send to yourself 12 | # emoji - must be one of: “🎲”, “🎯”, “🏀”, “⚽” “🎰” "🎳" 13 | # :game_die: :dart: :basketball: :soccer: :slot_machine: :bowling: 14 | # 15 | # -h - display short help 16 | # --help - this help 17 | # 18 | # Set BASHBOT_HOME to your installation directory 19 | # 20 | # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ 21 | # AUTHOR: KayM (gnadelwartz), kay@rrr.de 22 | # CREATED: 07.02.2021 18:45 23 | # 24 | #### $$VERSION$$ v1.52-1-g0dae2db 25 | #=============================================================================== 26 | 27 | #### 28 | # parse args 29 | SEND="send_dice" 30 | 31 | # set bashbot environment 32 | source "${0%/*}/bashbot_env.inc.sh" "${3:-debug}" # $5 debug 33 | print_help "$1" 34 | 35 | #### 36 | # ready, do stuff here ----- 37 | if [ "$1" == "BOTADMIN" ]; then 38 | CHAT="${BOTADMIN}" 39 | else 40 | CHAT="$1" 41 | fi 42 | 43 | # send message in selected format 44 | "${SEND}" "${CHAT}" "$2" 45 | 46 | # output send message result 47 | print_result 48 | -------------------------------------------------------------------------------- /bin/send_file.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # shellcheck disable=SC1090,SC2034 3 | #=============================================================================== 4 | # 5 | # FILE: bin/send_file.sh 6 | # 7 | USAGE='send_file.sh [-h|--help] "CHAT[ID]" "file|URL" "caption ...." [type] [debug]' 8 | # 9 | # DESCRIPTION: send a file to the given user/group 10 | # 11 | # OPTIONS: CHAT[ID] - ID number of CHAT or BOTADMIN to send to yourself 12 | # file - local file to send, must be an absolute path or relative to pwd 13 | # Note: must not contain .. or . and located below BASHBOT_ETC 14 | # URL - send an URL instead local file 15 | # 16 | # caption - message to send with file 17 | # type - photo, video, sticker, voice, document (optional) 18 | # 19 | # -h - display short help 20 | # --help - this help 21 | # 22 | # Set BASHBOT_HOME to your installation directory 23 | # 24 | # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ 25 | # AUTHOR: KayM (gnadelwartz), kay@rrr.de 26 | # CREATED: 25.12.2020 20:24 27 | # 28 | #### $$VERSION$$ v1.52-1-g0dae2db 29 | #=============================================================================== 30 | 31 | #### 32 | # parse args 33 | SEND="send_file" 34 | 35 | # set bashbot environment 36 | source "${0%/*}/bashbot_env.inc.sh" "${5:-debug}" # $5 debug 37 | print_help "$1" 38 | 39 | #### 40 | # ready, do stuff here ----- 41 | if [ "$1" == "BOTADMIN" ]; then 42 | CHAT="${BOTADMIN}" 43 | else 44 | CHAT="$1" 45 | fi 46 | 47 | FILE="$2" 48 | # convert to absolute path if not start with / or http:// 49 | [[ ! ( "$2" == "/"* || "$2" =~ ^https*:// || "$2" == "file_id://"*) ]] && FILE="${PWD}/$2" 50 | 51 | # send message in selected format 52 | "${SEND}" "${CHAT}" "${FILE}" "$3" "$4" 53 | 54 | # output send message result 55 | print_result 56 | -------------------------------------------------------------------------------- /bin/send_message.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # shellcheck disable=SC1090,SC2034 3 | #=============================================================================== 4 | # 5 | # FILE: bin/send_message.sh 6 | # 7 | USAGE='send_message.sh [-h|--help] [format] "CHAT[ID]" "message ...." [debug]' 8 | # 9 | # DESCRIPTION: send a message to the given user/group 10 | # 11 | # OPTIONS: format - normal, markdown, html, stdin, - (optional) 12 | # CHAT[ID] - ID number of CHAT or BOTADMIN to send to yourself 13 | # message - message to send in specified format 14 | # if no format is givern send_message() format is used 15 | # 16 | # use format "stdin" to read message from stdin or from a file: 17 | # send_message.sh stdin "CHAT[ID]" /dev/null 23 | 24 | # mkdir needed dirs 25 | mkdir "${TESTENV}/data-bot-bash" 26 | 27 | # inject JSON.sh 28 | mkdir "${TESTENV}/JSON.sh" 29 | curl -sL "https://cdn.jsdelivr.net/gh/dominictarr/JSON.sh/JSON.sh" >"${TESTENV}/JSON.sh/JSON.sh" 30 | chmod +x "${TESTENV}/JSON.sh/JSON.sh" 31 | 32 | ######################## 33 | #prepare and run tests 34 | #set -e 35 | fail=0 36 | tests=0 37 | passed=0 38 | #all_tests=${__dirname:} 39 | #printf PLAN ${#all_tests} 40 | for test in $(find ./*-test.sh | sort -u) ; 41 | do 42 | [ "${test}" = "dev/all-tests.sh" ] && continue 43 | [ ! -x "${test}" ] && continue 44 | tests=$((tests+1)) 45 | printf "TEST: %s\n" "${test}" 46 | "${test}" "${TESTENV}" 47 | ret=$? 48 | set +e 49 | if [ "${ret}" -eq 0 ] ; then 50 | printf "OK: ---- %s\n" "${test}" 51 | passed=$((passed+1)) 52 | else 53 | printf "FAIL: %s\n" "${test} ${fail}" 54 | fail=$((fail+ret)) 55 | break 56 | fi 57 | done 58 | 59 | ########################### 60 | # cleanup depending on test state 61 | if [ "${fail}" -eq 0 ]; then 62 | printf 'SUCCESS ' 63 | exitcode=0 64 | rm -rf "${TESTENV}" 65 | else 66 | printf 'FAILURE ' 67 | exitcode=1 68 | rm -rf "${TESTENV}/test" 69 | find "${TESTENV}/"* ! -name '[a-z]-*' -delete 70 | fi 71 | 72 | ######################### 73 | # show test result and test logs 74 | printf "%s\n\n" "${passed} / ${tests}" 75 | [ -d "${TESTENV}" ] && printf "Logfiles from run are in %s\n" "${TESTENV}" 76 | 77 | ls -ld /tmp/bashbot.test* 2>/dev/null && printf "Do not forget to delete bashbot test files in /tmp!!\n" 78 | 79 | exit "${exitcode}" 80 | -------------------------------------------------------------------------------- /dev/dev.inc.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ############################################################# 3 | # 4 | # File: dev/dev.inc.sh 5 | # 6 | # Description: common stuff for all dev scripts 7 | # 8 | #### $$VERSION$$ v1.52-1-g0dae2db 9 | ############################################################# 10 | 11 | # magic to ensure that we're always inside the root of our application, 12 | # no matter from which directory we'll run script 13 | 14 | # shellcheck disable=SC2034 15 | GIT_DIR=$(git rev-parse --git-dir 2>/dev/null) 16 | BASE_DIR=$(git rev-parse --show-toplevel 2>/dev/null) 17 | if [ "${BASE_DIR}" != "" ] ; then 18 | cd "${BASE_DIR}" || exit 1 19 | else 20 | printf "Sorry, no git repository %s\n" "$(pwd)" && exit 1 21 | fi 22 | 23 | HOOKDIR="dev/hooks" 24 | LASTCOMMIT=".git/.lastcommit" 25 | -------------------------------------------------------------------------------- /dev/git-add.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # file: git-add.sh 3 | # 4 | # works together with git pre-push.sh and ADD all changed files since last push 5 | 6 | #### $$VERSION$$ v1.52-1-g0dae2db 7 | 8 | #shellcheck disable=SC1090 9 | source "${0%/*}/dev.inc.sh" 10 | 11 | # check for last commit date 12 | if [ ! -f "${LASTCOMMIT}" ]; then 13 | if ! touch -d "$(git log -1 --format=%cD)" "${LASTCOMMIT}"; then 14 | printf "No previous commit found, use \"git add\" instead ... Abort\n" 15 | exit 16 | fi 17 | fi 18 | 19 | set +f 20 | FILES="$(find ./* -newer "${LASTCOMMIT}" | grep -v -e 'DIST\/' -e 'STANDALONE\/' -e 'JSON.sh')" 21 | set -f 22 | # FILES="$(find ./* -newer .git/.lastpush)" 23 | [ "${FILES}" = "" ] && printf "Nothing changed since last commit ...\n" && exit 24 | 25 | # run pre_commit on files 26 | dev/hooks/pre-commit.sh 27 | 28 | printf "Add files to repo: " 29 | # shellcheck disable=SC2086 30 | for file in ${FILES} 31 | do 32 | [ -d "${file}" ] && continue 33 | printf "%s" "${file} " 34 | done 35 | printf " - Done.\n" 36 | 37 | # stay with "." for (re)moved files! 38 | git add . 39 | 40 | -------------------------------------------------------------------------------- /dev/hooks/post-commit.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #### $$VERSION$$ v1.52-1-g0dae2db 3 | 4 | ############ 5 | # NOTE: you MUST run install-hooks.sh again when updating this file! 6 | 7 | # magic to ensure that we're always inside the root of our application, 8 | # no matter from which directory we'll run script 9 | GIT_DIR=$(git rev-parse --git-dir) 10 | cd "${GIT_DIR}/.." || exit 1 11 | 12 | export HOOKDIR="dev/hooks" 13 | LASTPUSH='.git/.lastcommit' 14 | 15 | # if any command inside script returns error, exit and return that error 16 | set -e 17 | 18 | #printf "Running post-commit hook\n............................\n" 19 | 20 | unset IFS; set -f 21 | 22 | # note date of last push for version 23 | touch "${LASTPUSH}" 24 | -------------------------------------------------------------------------------- /dev/hooks/pre-commit.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #### $$VERSION$$ v1.52-1-g0dae2db 3 | 4 | ############ 5 | # NOTE: you MUST run install-hooks.sh again when updating this file! 6 | 7 | # magic to ensure that we're always inside the root of our application, 8 | # no matter from which directory we'll run script 9 | GIT_DIR=$(git rev-parse --git-dir) 10 | cd "${GIT_DIR}/.." || exit 1 11 | 12 | export HOOKDIR="dev/hooks" 13 | LASTPUSH='.git/.lastpush' 14 | 15 | # if any command inside script returns error, exit and return that error 16 | set -e 17 | 18 | printf "Running pre-commit hook\n............................\n" 19 | 20 | unset IFS; set -f 21 | 22 | # check for shellcheck 23 | if command -v shellcheck >/dev/null 2>&1; then 24 | printf "Test all scripts with shellcheck\n" 25 | else 26 | printf "Error: shellcheck is not installed. Please install shellcheck\n" 27 | exit 1 28 | fi 29 | 30 | # run shellcheck before commit 31 | set +f 32 | FILES="$(find ./* -name '*.sh' | grep -v -e 'DIST\/' -e 'STANDALONE\/' -e 'JSON.sh')" 33 | set -f 34 | FILES="${FILES} $(sed '/^#/d' <"dev/shellcheck.files")" 35 | if [ "${FILES}" != "" ]; then 36 | # shellcheck disable=SC2086 37 | shellcheck -o all -e SC2249,SC2154 -x ${FILES} || exit 1 38 | printf " OK\n............................\n" 39 | else 40 | # something went wrong 41 | exit 1 42 | fi 43 | 44 | # get version strings 45 | REMOTEVER="$(git ls-remote -t --refs 2>/dev/null | tail -1 | sed -e 's/.*\/v//' -e 's/-.*//')" 46 | VERSION="$(git describe --tags | sed -e 's/-.*//' -e 's/v//' -e 's/,/./')" 47 | [ -z "${REMOTEVER}" ] && REMOTEVER="${VERSION}" 48 | 49 | # LOCAL version must greater than latest REMOTE release version 50 | printf "Update Version of modified files\n" 51 | if ! command -v bc &> /dev/null || (( $(printf "%s\n" "${VERSION} >= ${REMOTEVER}" | bc -l) )); then 52 | # update version in bashbot files on push 53 | set +f 54 | [ -f "${LASTPUSH}" ] && LASTFILES="$(find ./* -newer "${LASTPUSH}" ! -path "./DIST/*" ! -path "./STANDALONE/*")" 55 | [ "${LASTFILES}" = "" ] && exit 56 | printf " " 57 | # shellcheck disable=SC2086 58 | dev/version.sh ${LASTFILES} 2>/dev/null || exit 1 59 | printf " OK\n............................\n" 60 | else 61 | printf "Error: local version %s must be equal to or greater then release version%s\n" "${VERSION}" "${REMOTEVER}." 62 | printf "use \"git tag vx.zz\" to create a new local version\n" 63 | exit 1 64 | fi 65 | 66 | if command -v codespell &>/dev/null; then 67 | printf "Running codespell\n............................\n" 68 | codespell -q 3 --skip="*.zip,*gz,*.log,*.html,*.txt,.git*,jsonDB-keyboard,DIST,STANDALONE" -L "ba" 69 | printf "if there are (to many) typo's shown, consider running:\ncodespell -i 3 -w --skip=\"*.log,*.html,*.txt,.git*,examples\" -L \"ba\"\n" 70 | else 71 | printf "consider installing codespell: pip install codespell\n" 72 | fi 73 | printf "............................\n" 74 | 75 | -------------------------------------------------------------------------------- /dev/hooks/pre-push.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #### $$VERSION$$ v1.52-1-g0dae2db 3 | 4 | ############ 5 | # NOTE: you MUST run install-hooks.sh again when updating this file! 6 | 7 | # magic to ensure that we're always inside the root of our application, 8 | # no matter from which directory we'll run script 9 | GIT_DIR=$(git rev-parse --git-dir) 10 | cd "${GIT_DIR}/.." || exit 1 11 | 12 | export HOOKDIR="dev/hooks" 13 | LASTPUSH='.git/.lastpush' 14 | 15 | # if any command inside script returns error, exit and return that error 16 | set -e 17 | 18 | printf "Running pre-push hook\n............................\n" 19 | 20 | unset IFS; set -f 21 | 22 | # note date of last push for version 23 | touch "${LASTPUSH}" 24 | -------------------------------------------------------------------------------- /dev/inject-json.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ############################################################## 3 | # 4 | # File: inject-json.sh 5 | # 6 | # Description: download and prepare JSON.sh and JSON.awk 7 | # 8 | # Usage: source inject-json.sh 9 | # 10 | #### $$VERSION$$ v1.52-1-g0dae2db 11 | ############################################################## 12 | 13 | # download JSON.sh 14 | JSONSHFILE="JSON.sh/JSON.sh" 15 | if [ ! -r "${JSONSHFILE}" ]; then 16 | printf "Inject JSON.sh ... " 17 | mkdir "JSON.sh" 2>/dev/null 18 | curl -sL -o "${JSONSHFILE}" "https://cdn.jsdelivr.net/gh/dominictarr/JSON.sh/JSON.sh" 19 | chmod +x "${JSONSHFILE}" 20 | printf "Done!\n" 21 | fi 22 | 23 | # download JSON.awk 24 | JSONSHFILE="JSON.sh/JSON.awk.dist" 25 | if [ ! -r "${JSONSHFILE}" ]; then 26 | printf "Inject JSON.awk ... " 27 | curl -sL -o "${JSONSHFILE}" "https://cdn.jsdelivr.net/gh/step-/JSON.awk/JSON.awk" 28 | curl -sL -o "${JSONSHFILE%/*}/awk-patch.sh" "https://cdn.jsdelivr.net/gh/step-/JSON.awk/tool/patch-for-busybox-awk.sh" 29 | chmod +x "${JSONSHFILE}" 30 | printf "Done!\n" 31 | bash "${JSONSHFILE%/*}/awk-patch.sh" "${JSONSHFILE}" 32 | fi 33 | # delete backup files 34 | rm -f "${JSONSHFILE%/*}"/*.bak 35 | 36 | -------------------------------------------------------------------------------- /dev/install-hooks.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # this has to run once atfer git clone 3 | # and every time we create new hooks 4 | #### $$VERSION$$ v1.52-1-g0dae2db 5 | 6 | #shellcheck disable=SC1090 7 | source "${0%/*}/dev.inc.sh" 8 | 9 | printf "Installing hooks..." 10 | for hook in pre-commit post-commit pre-push 11 | do 12 | rm -f "${GIT_DIR}/hooks/${hook}" 13 | if [ -f "${HOOKDIR}/${hook}.sh" ]; then 14 | printf "%s"" ${hook}" 15 | ln -s "../../${HOOKDIR}/${hook}.sh" "${GIT_DIR}/hooks/${hook}" 16 | fi 17 | done 18 | printf " Done!\n" 19 | -------------------------------------------------------------------------------- /dev/make-distribution.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ############################################################## 3 | # 4 | # File: make-distribution.sh 5 | # 6 | # Description: creates files and arcchives to distribute bashbot 7 | # 8 | # Options: --notest - skip tests 9 | # 10 | #### $$VERSION$$ v1.52-1-g0dae2db 11 | ############################################################## 12 | 13 | #shellcheck disable=SC1090 14 | source "${0%/*}/dev.inc.sh" 15 | 16 | VERSION="$(git describe --tags | sed -e 's/-[0-9].*//' -e 's/v//')" 17 | 18 | DISTNAME="telegram-bot-bash" 19 | DISTDIR="./DIST/${DISTNAME}" 20 | DISTMKDIR="data-bot-bash logs bin bin/logs addons" 21 | 22 | DISTFILES="bashbot.sh commands.sh mycommands.sh.clean bin doc examples scripts modules LICENSE README.md README.txt README.html" 23 | DISTFILESDEV="dev/make-standalone.sh dev/inject-json.sh dev/make-html.sh dev/obfuscate.sh" 24 | DISTFILESDIST="mycommands.sh mycommands.conf bashbot.rc $(echo "addons/"*.sh)" 25 | 26 | # run tests first! 27 | for test in $1 dev/all-test*.sh 28 | do 29 | [[ "${test}" == "--notest"* ]] && break 30 | [ ! -x "${test}" ] && continue 31 | if ! "${test}" ; then 32 | printf "ERROR: Test %s failed, can't create dist!\n" "${test}" 33 | exit 1 34 | fi 35 | done 36 | 37 | # create dir for distribution and copy files 38 | mkdir -p "${DISTDIR}" 2>/dev/null 39 | 40 | printf "Copy files\n" 41 | # shellcheck disable=SC2086 42 | cp -r ${DISTFILES} "${DISTDIR}" 43 | mkdir -p "${DISTDIR}/dev" 44 | # shellcheck disable=SC2086 45 | cp ${DISTFILESDEV} "${DISTDIR}/dev" 46 | cd "${DISTDIR}" || exit 1 47 | 48 | printf "Create directories\n" 49 | # shellcheck disable=SC2250 50 | for dir in $DISTMKDIR 51 | do 52 | [ ! -d "${dir}" ] && mkdir "${dir}" 53 | done 54 | 55 | # do not overwrite on update 56 | printf "Create .dist files\n" 57 | for file in ${DISTFILESDIST} 58 | do 59 | [ "${file}" = "addons/*.sh" ] && continue 60 | cp "${BASE_DIR}/${file}" "${file}.dist" 61 | done 62 | 63 | # inject JSON.sh into distribution 64 | # shellcheck disable=SC1090 65 | source "${BASE_DIR}/dev/inject-json.sh" 66 | 67 | # make html doc 68 | printf "Create html doc\n" 69 | # shellcheck disable=SC1090,SC1091 70 | source "../../dev/make-html.sh" 71 | 72 | # create archive 73 | cd .. || exit 1 74 | printf "Create dist archives\n" 75 | # shellcheck disable=SC2046 76 | zip -rq - "${DISTNAME}" --exclude $(cat "${BASE_DIR}/dev/${0##*/}.exclude") >"${DISTNAME}-${VERSION}.zip" 77 | tar --exclude-ignore="${BASE_DIR}/dev/${0##*/}.exclude" -czf "${DISTNAME}-${VERSION}.tar.gz" "${DISTNAME}" 78 | 79 | printf "%s Done!\n" "$0" 80 | 81 | # shellcheck disable=SC2086 82 | ls -ld "${DISTNAME}-${VERSION}".* 83 | 84 | # an empty DEBUG.log is created ... :-( 85 | rm -f "${BASE_DIR}/test/"*.log 86 | -------------------------------------------------------------------------------- /dev/make-distribution.sh.exclude: -------------------------------------------------------------------------------- 1 | STANDALONE 2 | data-bot-bash/* 3 | test 4 | webhook-fifo* 5 | JSON.awk 6 | bashbot.rc 7 | mycommands.sh 8 | mycommands.conf 9 | awk-patch.sh 10 | make-standalone.sh.include 11 | *.jssh* 12 | botacl 13 | *.flock 14 | *.log 15 | *.last 16 | *.ok 17 | *.bad 18 | *.bak 19 | *.jpg 20 | *.jpeg 21 | *.png 22 | *.zip 23 | *.gz 24 | -------------------------------------------------------------------------------- /dev/make-html.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ############################################################## 3 | # 4 | # File: make-html.sh 5 | # 6 | # Description: creates html version from *.md files 7 | # 8 | # Usage: source make-hmtl 9 | # 10 | #### $$VERSION$$ v1.52-1-g0dae2db 11 | ############################################################## 12 | 13 | # check for correct dir 14 | if [[ ! ( -f README.html && -f README.md ) ]]; then 15 | printf "Error: Can't create html, script must run where README.md and README.html is!\n" 16 | 17 | else 18 | # check if pandoc installed 19 | if [ "$(type -t pandoc)" != "file" ]; then 20 | printf "pandoc not found, skipping html generation ...\n" 21 | 22 | else 23 | ######## 24 | # everything seems ok, start html generation 25 | printf "Start hmtl conversion " 26 | # create dir for html doc and index.html there 27 | mkdir html 2>/dev/null 28 | cp README.html html/index.html 29 | # convert *.md files in doc to *.hmtl in html 30 | find doc -iname "*.md" -type f -exec sh -c\ 31 | 'printf "."; pandoc -s -f commonmark -M "title=Bashobot Documentation - ${0%.md}.html" "$0" -o "./html/$(basename ${0%.md}.html)"' {} \; 32 | # html for examples dir 33 | if [ -d "examples" ]; then 34 | EXAMPLES="examples" # add to final conversion job 35 | find examples -iname "*.md" -type f -exec sh -c\ 36 | 'printf "."; pandoc -s -f commonmark -M "title=Bashobot Documentation - ${0%.md}.html" "$0" -o "${0%.md}.html"' {} \; 37 | fi 38 | # final: convert links from *.md to *.html 39 | # shellcheck disable=SC2248 40 | find README.html html ${EXAMPLES} -iname "*.html" -type f -exec sh -c\ 41 | 'sed -i -E "s/href=\"(\.\.\/)*doc\//href=\"\1html\//g;s/href=\"(.*).md(#.*)*\"/href=\"\1.html\"/g" $0' {} \; 42 | printf " Done!\n" 43 | fi 44 | fi 45 | -------------------------------------------------------------------------------- /dev/make-standalone.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ################################################################### 3 | # 4 | # File: make-standalone.sh 5 | # 6 | # Description: 7 | # even after make-distribution.sh bashbot is not self contained as it was in the past. 8 | # 9 | # Options: --notest 10 | # 11 | # If you your bot is finished you can use make-standalone.sh to create the 12 | # the old all-in-one bashbot: bashbot.sh and commands.sh only! 13 | # 14 | #### $$VERSION$$ v1.52-1-g0dae2db 15 | ################################################################### 16 | 17 | # include git config and change to base dir 18 | incfile="${0%/*}/dev.inc.sh" 19 | #shellcheck disable=SC1090 20 | [ -f "${incfile}" ] && source "${incfile}" 21 | 22 | # seems we are not in a dev env 23 | if [ -z "${BASE_DIR}" ]; then 24 | BASE_DIR="$(pwd)" 25 | [[ "${BASE_DIR}" == *"/dev" ]] && BASE_DIR="${BASE_DIR%/*}" 26 | # go to basedir 27 | cd "${BASE_DIR}" || exit 1 28 | fi 29 | 30 | # see if if bashbot is in base dir 31 | [ ! -f "bashbot.sh" ] && printf "bashbot.sh not found in %s\n" " $(pwd)" && exit 1 32 | 33 | # run pre_commit if exist 34 | [[ -f "dev/dev.inc.sh" && "$1" != "--notest" ]] && dev/hooks/pre-commit.sh 35 | 36 | # files and dirs to copy 37 | #DISTNAME="telegram-bot-bash" 38 | DISTDIR="./STANDALONE" 39 | DISTMKDIR="data-bot-bash logs bin/logs addons" 40 | DISTFILES="bashbot.sh commands.sh mycommands.sh modules scripts LICENSE README.* doc addons" 41 | DISTBINFILES="bin/bashbot_env.inc.sh bin/bashbot_stats.sh bin/process_batch.sh bin/process_update.sh bin/send_broadcast.sh bin/send_message.sh" 42 | 43 | # add extra files, minimum mycommands.conf 44 | extrafile="${BASE_DIR}/dev/${0##*/}.include" 45 | [ ! -f "${extrafile}" ] && printf "bashbot.rc\nbotacl\nbotconfig.jssh\nmycommands.conf\ndev/obfuscate.sh\n" >"${extrafile}" 46 | DISTFILES+=" $(<"${extrafile}")" 47 | 48 | # create dir for distribution and copy files 49 | printf "Create directories and copy files\n" 50 | mkdir -p "${DISTDIR}/bin" 2>/dev/null 51 | # shellcheck disable=SC2086 52 | cp -rp ${DISTFILES} "${DISTDIR}" 2>/dev/null 53 | # shellcheck disable=SC2086 54 | cp -p ${DISTBINFILES} "${DISTDIR}/bin" 2>/dev/null 55 | 56 | cd "${DISTDIR}" || exit 1 57 | 58 | # remove log files 59 | find . -name '*.log' -delete 60 | 61 | # shellcheck disable=SC2250 62 | for dir in $DISTMKDIR 63 | do 64 | [ ! -d "${dir}" ] && mkdir "${dir}" 65 | done 66 | 67 | # inject JSON.sh into distribution 68 | # shellcheck disable=SC1090 69 | source "${BASE_DIR}/dev/inject-json.sh" 70 | 71 | ####################### 72 | # here the magic starts 73 | # create all in one bashbot.sh file 74 | 75 | printf "OK, now lets do the magic ...\n\t... create unified commands.sh\n" 76 | 77 | { 78 | # first head of commands.sh 79 | sed -n '0,/^if / p' commands.sh | grep -v -F -e "___" -e "*MUST*" -e "mycommands.sh.dist" -e "mycommands.sh.clean"| head -n -2 80 | 81 | # then mycommands from first non comment line on 82 | printf '\n##############################\n# my commands starts here ...\n' 83 | sed -n '/^$/,$ p' mycommands.sh 84 | 85 | # last tail of commands.sh 86 | printf '\n##############################\n# default commands starts here ...\n' 87 | sed -n '/source .*\/mycommands.sh"/,$ p' commands.sh | tail -n +2 88 | 89 | } >>$$commands.sh 90 | 91 | mv $$commands.sh commands.sh 92 | rm -f mycommands.sh 93 | 94 | printf "\t... create unified bashbot.sh\n" 95 | 96 | { 97 | # first head of bashbot.sh 98 | sed -n '0,/for module in/ p' bashbot.sh | head -n -3 99 | 100 | # then modules without shebang 101 | printf '\n##############################\n# bashbot modules starts here ...\n' 102 | # shellcheck disable=SC2016 103 | cat modules/*.sh | sed -e 's/^#\!\/bin\/bash.*//' -e '/^#.*\$\$VERSION\$\$/d' 104 | 105 | # last remaining commands.sh 106 | printf '\n##############################\n' 107 | sed -n '/^# read commands file/,$ p' bashbot.sh 108 | 109 | } >>$$bashbot.sh 110 | 111 | mv $$bashbot.sh bashbot.sh 112 | chmod +x bashbot.sh 113 | 114 | rm -rf modules 115 | 116 | printf "Create minimized Version of bashbot.sh and commands.sh\n" 117 | # shellcheck disable=SC2016 118 | sed -E -e '/(shellcheck)|(^#!\/)|(\$\$VERSION\$\$)/! s/^[[:space:]]*#.*//' -e '/shellcheck/! s/\t+#.*//' -e 's/^[[:space:]]*//'\ 119 | -e '/^$/d' bashbot.sh | sed 'N;s/\\\n/ /;P;D' | sed 'N;s/\\\n/ /;P;D' > bashbot.sh.min 120 | # shellcheck disable=SC2016 121 | sed -E -e '/(shellcheck)|(^#!\/)|(\$\$VERSION\$\$)/! s/^[[:space:]]*#.*//' -e '/shellcheck/! s/\t+#.*//' -e 's/^[[:space:]]*//'\ 122 | -e '/^$/d' commands.sh | sed 'N;s/\\\n/ /;P;D' > commands.sh.min 123 | chmod +x bashbot.sh.min 124 | 125 | # make html doc 126 | printf "Create html doc\n" 127 | #shellcheck disable=SC1090 128 | source "${BASE_DIR}/dev/make-html.sh" 129 | 130 | printf "%s Done!\n" "$0" 131 | 132 | cd .. || exit 1 133 | 134 | printf "\nStandalone bashbot files are now available in %s:\n\n" "${DISTDIR}" 135 | ls -l "${DISTDIR}" 136 | 137 | -------------------------------------------------------------------------------- /dev/make-standalone.sh.include: -------------------------------------------------------------------------------- 1 | bashbot.rc 2 | botacl 3 | botconfig.jssh 4 | mycommands.conf 5 | dev/obfuscate.sh 6 | -------------------------------------------------------------------------------- /dev/obfuscate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # joke hack to obfuscate bashbot.min.sh 4 | # 5 | #### $$VERSION$$ v1.52-1-g0dae2db 6 | # shellcheck disable=SC2028,SC2016,SC1117 7 | 8 | infile="bashbot.sh" 9 | outfile="./bashbot.obf.sh" 10 | 11 | if [ ! -f "${infile}" ]; then 12 | printf "This is a hack to obfuscate %s, run me in STANDALONE after running make-standalone.sh\n" "${infile}" 13 | exit 1 14 | fi 15 | # create gzipped base64 encoded file plus commands to decode 16 | { 17 | # shellcheck disable=SC2183 18 | printf '#!/bin/bash\na="$PWD";cd "$(mktemp -d)"||exit;%s'\ 19 | 'printf '"'$(gzip -9 <"${infile}" | base64)'"'|base64 -d|gunzip >a;export BASHBOT_HOME="$a";chmod +x a;./a "$@";a="$PWD";cd ..;rm -rf "$a"' 20 | } >"${outfile}" 21 | 22 | chmod +x "${outfile}" 23 | ls -l "${outfile}" 24 | printf "Try to run %s init ;-)\n" "${outfile}" 25 | -------------------------------------------------------------------------------- /dev/shellcheck.files: -------------------------------------------------------------------------------- 1 | # list of additional files to check from shellcheck 2 | #### $$VERSION$$ v1.52-1-g0dae2db 3 | bashbot.rc 4 | mycommands.conf 5 | mycommands.sh.clean 6 | -------------------------------------------------------------------------------- /dev/version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | #### $$VERSION$$ v1.52-1-g0dae2db 4 | # shellcheck disable=SC2016 5 | # 6 | # Easy Versioning in git: 7 | # 8 | # for setting your Version in git use e.g.: 9 | # git tag -a v0.5 -m 'Version 0.5' 10 | # 11 | # Push tags upstream—this is not done by default: 12 | # git push --tags 13 | # 14 | # # in case of a wrong tag remove it: 15 | # git tag -d v0.5 16 | # 17 | # delete remote tag (eg, GitHub version) 18 | # git push origin :refs/tags/v0.5 19 | # 20 | # Then use the describe command: 21 | # 22 | # git describe --tags --long 23 | # This gives you a string of the format: 24 | # 25 | # v0.5-0-gdeadbee 26 | # ^ ^ ^^ 27 | # | | || 28 | # | | |'-- SHA of HEAD (first seven chars) 29 | # | | '-- "g" is for git 30 | # | '---- number of commits since last tag 31 | # | 32 | # '--------- last tag 33 | # 34 | # run this script to (re)place Version number in files 35 | # 36 | 37 | #shellcheck disable=SC1090 38 | source "${0%/*}/dev.inc.sh" 39 | 40 | unset IFS 41 | # set -f # if you are paranoid use set -f to disable globbing 42 | 43 | VERSION="$(git describe --tags --long)" 44 | printf "Update to version %s ...\n" "${VERSION}" 45 | 46 | # only regular files, ignore .dot files/dirs, e.g. .git .gitinore in BASEDIR 47 | if [ -n "$1" ]; then 48 | FILES="$*" 49 | else 50 | printf "Update version string in all files? (y/N)\b\b" 51 | read -r answer 52 | [[ "${answer}" != "y" && "${answer}" != "Y" ]] && exit 53 | FILES="$(find ./* -type f ! -path "./DIST/*" ! -path "./STANDALONE/*")" 54 | fi 55 | 56 | # autogenerate REMADME.html REMADE.txt 57 | if [[ "${FILES}" == *"README.md"* ]]; then 58 | FILES+=" README.html README.txt" 59 | type -f pandoc >/dev/null && pandoc -s -f commonmark -M "title=Bashbot README" README.md >README.html 60 | cat "doc/bashbot.ascii" >"README.txt" 61 | if [ -r "README.html" ] && type -f html2text >/dev/null; then 62 | # convert html links to text [link] 63 | sed -E 's/([^<#]+)<\/a>/\2 [\1]/g' >README.txt 65 | else 66 | type -f fold >/dev/null && fold -s -w 90 README.md >>README.txt 67 | fi 68 | fi 69 | 70 | # change version string in given files 71 | for file in ${FILES} 72 | do 73 | # symlink is a file :-( 74 | [[ -L "${file}" || ! -f "${file}" ]] && continue 75 | #[ "${file}" == "version" ] && continue 76 | printf "%s" " ${file}" >&2 77 | sed -i 's/^#### $$VERSION$$.*/#### \$\$VERSION\$\$ '"${VERSION}"'/' "${file}" 78 | done 79 | 80 | printf " done.\n" 81 | 82 | -------------------------------------------------------------------------------- /doc/0_install.md: -------------------------------------------------------------------------------- 1 | #### [Home](../README.md) 2 | 3 | ## Check bash installation 4 | 5 | There may systems where bash seems to be installed but it is not (_e.g. embedded systems_) or where bash is to old. 6 | Bashbot has some builtin checks but it may better to check before installing bashbot. 7 | 8 | Run the following commands to see if your bash looks ok ... 9 | 10 | ```bash 11 | # system say bash is there? 12 | if which bash; then echo "bash seems available..."; else echo "NO bash"; fi 13 | 14 | # real bash supports ARRAY 15 | bash -c 'if eval "a[1]=1"; then echo "Shell support arrays..."; else echo "Shell has NO arrays"; fi' 16 | 17 | # check for bash version by feature 18 | bash -c 'if [ "$(LANG=C.UTF-8 echo -e "\u1111")" != "\u1111" ]; then echo "Bash version ok ..."; else echo "Bash version may to old ..."; fi' 19 | 20 | # display bash version, must be greater than 4.3 21 | bash --version | grep "bash" 22 | ``` 23 | 24 | ## Install bashbot 25 | 26 | Installing bashbot is very simple: Download and extract the installation archive. 27 | 28 | 1. Choose a directory to install bashbot (_e.g.your HOME or /usr/local_) 29 | 2. Download [latest release zip / tar archive](https://github.com/topkecleon/telegram-bot-bash/releases/latest) and extract all files. 30 | 3. Change into the directory `telegram-bot-bash` 31 | 4. Copy `mycommands.conf.dist` `mycommands.conf` 32 | 4. Copy `mycommands.sh.dist` or `mycommands.sh.clean` to `mycommands.sh` 33 | 5. Run `./bashbot.sh init`\* to setup the environment and enter your Bots token given by botfather. 34 | 35 | Edit config in `mycommands.conf` and commands in `mycommands.sh` to fit your need. 36 | Now your Bot is ready to start ... 37 | 38 | *If you are new to Bot development read [Bots: An introduction for developers](https://core.telegram.org/bots)* 39 | 40 | \* _Run with sudo if you want to run bashbot from different user, e.g. from `bashbot.rc`._ 41 | 42 | ### Update bashbot 43 | 44 | Update bashbot is almost identical to installing bashbot: Download and extract the installation archive. 45 | 46 | **Important: All files may overwritten, make a backup!** 47 | 48 | 1. Go to the directory where bashbot is installed (_e.g.$HOME/telegram-bot-bash or /usr/local/telegram-bot-bash_) 49 | 2. Download [latest release zip / tar archive](https://github.com/topkecleon/telegram-bot-bash/releases/latest) 50 | 3. Stop all running instances of bashbot `./bashbot.sh stop` 51 | 4. Change to parent directory of bashbot installation and extract all files from archive. 52 | 5. Run `./bashbot.sh init`\* to setup your environment after the update 53 | 6. Restart your bot `./bashbot.sh start` 54 | 55 | `mycommands.conf` and `mycommands.sh` will not overwritten, this avoids losing your bot config and commands on updates. 56 | 57 | *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! 58 | 59 | ### Use JSON.awk 60 | 61 | [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. 62 | On most systems you can use `JSON.awk` with system default awk installation. 63 | ( [gnu awk, posix awk, mawk, busybox akw](https://github.com/step-/JSON.awk#compatibility-with-awk-implementations) ). 64 | 65 | After you have checked that `JSON.awk.dist` is working on your system copy it to `JSON.awk` and (re)start bashbot. 66 | 67 | BSD and MacOS users must install `gnu awk` and adjust the shebang, see below 68 | 69 | *Note*: To install or update `JSON.awk` manually execute the following commands in the directory `JSON.sh/`: 70 | 71 | wget https://cdn.jsdelivr.net/gh/step-/JSON.awk/JSON.awk 72 | wget https://cdn.jsdelivr.net/gh/step-/JSON.awk/tool/patch-for-busybox-awk.sh 73 | bash patch-for-busybox-awk.sh 74 | chmod +x JSON.awk 75 | 76 | 77 | ### Install bashbot from git repo 78 | 79 | Installation and updates should be done using the zip / tar archives provided on github to avoid 80 | problems and not overwriting your bot config and `mycommands.sh`. 81 | 82 | Nevertheless you can install or update bashbot from a git repo, see next chapter ... 83 | 84 | 85 | ### Create Installation / Update archives 86 | 87 | To install or update bashbot from git repo execute `dev/make-distribution.sh`. 88 | This creates the installation archives in `DIST/` and a ready to run test installation in `DIST/telegram.bot-bash`. 89 | 90 | *Note:* You should be familiar with `git`. 91 | 92 | 1. Run `git clone https://github.com/topkecleon/telegram-bot-bash.git` 93 | 2. Change into the directory `telegram-bot-bash` 94 | 3. Optional: Run ` git checkout develop` for latest develop version 95 | 4. Run ` dev/make-distribution.sh` (_add --notest to skip tests_) 96 | 5. Change to dir `DIST/` 97 | 98 | Use the installation archives to install or update bashbot as described above. 99 | 100 | 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`. 101 | To update the test installation (_after git pull, local changes or switch master/develop_) run `dev/make-distribution.sh` again. 102 | 103 | 104 | ### Note for BSD and MacOS 105 | 106 | **On MacOS** you must install a more recent version of bash, as the default bash is way to old, 107 | see e.g. [Install Bash on Mac](http://macappstore.org/bash/) 108 | 109 | **On BSD and MacOS** I recommend to install gnu coreutils and include them in your PATH 110 | environment variable before running bashbot, e.g. the gnu versions of sed, grep, find, awk ... 111 | 112 | 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 113 | or use the script: `examples/bash2env *.sh */*.sh` to convert them for you. 114 | 115 | Bashbot will stay with `#!/bin/bash` shebang, as using a fixed path is IMHO more secure than the portable '!/usr/bin/env bash` variant. 116 | 117 | Compatibility with BSD/MacOS will result in a rewrite of all grep/sed commands with an uncertain outcome, 118 | see [BSD/MacOS vs. GNU sed](https://riptutorial.com/sed/topic/9436/bsd-macos-sed-vs--gnu-sed-vs--the-posix-sed-specification) 119 | to get an impression how different they are. 120 | 121 | 122 | ### Notes on Changes 123 | 124 | #### Config moved to mycommands.conf 125 | 126 | From Version 1.30 on config for new bots is moved to `mycommands.conf`. 127 | 128 | #### Support for update from pre-1.0 removed 129 | 130 | From Version 1.21 on updating from a pre-1.0 version (_no \*.jssh config_) is no more supported! 131 | You must update to [Version 1.20](https://github.com/topkecleon/telegram-bot-bash/releases/tags/v1.20) first! 132 | 133 | #### [Next Create Bot](1_firstbot.md) 134 | 135 | #### $$VERSION$$ v1.52-1-g0dae2db 136 | 137 | -------------------------------------------------------------------------------- /doc/1_firstbot.md: -------------------------------------------------------------------------------- 1 | #### [Home](../README.md) 2 | ## Create a Telegram Bot with Botfather 3 | **[BotFather is the one bot to rule them all](https://core.telegram.org/bots#3-how-do-i-create-a-bot). It will help you create new bots and change settings for existing ones.** [Commands known by Botfather](https://core.telegram.org/bots#generating-an-authorization-token) 4 | 5 | ### Creating a new Bot 6 | 7 | 1. Message @botfather https://telegram.me/botfather with the following 8 | text: `/newbot` 9 | If you don't know how to message by username, click the search 10 | field on your Telegram app and type `@botfather`, you should be able 11 | to initiate a conversation. Be careful not to send it to the wrong 12 | contact, because there are users with a similar username. 13 | 14 | ![botfather initial conversation](http://i.imgur.com/aI26ixR.png) 15 | 16 | 2. @botfather replies with `Alright, a new bot. How are we going to 17 | call it? Please choose a name for your bot.` 18 | 19 | 3. Type whatever name you want for your bot. 20 | 21 | 4. @botfather replies with `Good. Now let's choose a username for your 22 | bot. It must end in bot. Like this, for example: TetrisBot or 23 | tetris_bot.` 24 | 25 | 5. Type whatever username you want for your bot, minimum 5 characters, 26 | and must end with `bot`. For example: `telesample_bot` 27 | 28 | 6. @botfather replies with: 29 | 30 | Done! Congratulations on your new bot. You will find it at 31 | telegram.me/telesample_bot. You can now add a description, about 32 | section and profile picture for your bot, see /help for a list of 33 | commands. 34 | 35 | Use this token to access the HTTP API: 36 | 123456789:AAG90e14-0f8-40183D-18491dDE 37 | 38 | For a description of the Bot API, see this page: 39 | https://core.telegram.org/bots/api 40 | 41 | 7. Note down the 'token' mentioned above. 42 | 43 | 8. Type `/setprivacy` to @botfather. 44 | 45 | ![botfather later conversation](http://i.imgur.com/tWDVvh4.png) 46 | 47 | 9. @botfather replies with `Choose a bot to change group messages settings.` 48 | 49 | 10. Type `@telesample_bot` (change to the username you set at step 5 50 | above, but start it with `@`) 51 | 52 | 11. @botfather replies with 53 | 54 | 'Enable' - your bot will only receive messages that either start 55 | with the '/' symbol or mention the bot by username. 56 | 'Disable' - your bot will receive all messages that people send to groups. 57 | Current status is: ENABLED 58 | 59 | 12. Type `Disable` to let your bot receive all messages sent to a 60 | group. This step is up to you actually. 61 | 62 | 13. @botfather replies with `Success! The new status is: DISABLED. /help` 63 | 64 | 65 | #### [Prev Installation](0_install.md) 66 | #### [Next Getting started](2_usage.md) 67 | 68 | #### $$VERSION$$ v1.52-1-g0dae2db 69 | 70 | -------------------------------------------------------------------------------- /doc/5_practice.md: -------------------------------------------------------------------------------- 1 | #### [Home](../README.md) 2 | ## Best Practices 3 | 4 | ### New to bot development? 5 | 6 | If you are new to Bot development read [Bots: An introduction for developers](https://core.telegram.org/bots) and consult [Telegram Bot API Documentation](https://core.telegram.org/bots/api/). 7 | 8 | In addition you should know about [BotFather, the one bot to rule them all](https://core.telegram.org/bots#3-how-do-i-create-a-bot). It will help you create new bots and change settings for existing ones. [Commands known by Botfather](https://core.telegram.org/bots#generating-an-authorization-token) 9 | 10 | If you don't have a github account, it may time to [setup a free account now](https://github.com/pricing) 11 | 12 | ### Add commands to mycommands.sh only 13 | Do not change `bashbot.sh` and `commands.sh`, instead place your commands in to `mycommands.sh`. 14 | To start with a clean/minimal bot copy `mycommands.sh.clean` to `mycommands.sh` and start editing 15 | the message strings and place commands in the` case ... esac` block of the function mycommands(): 16 | ```bash 17 | # file: mycommands.sh 18 | # your additional bashbot commands 19 | 20 | # uncomment the following lines to overwrite info and help messages 21 | bashbot_info='This is *MY* variant of _bashbot_, the Telegram bot written entirely in bash. 22 | ' 23 | 24 | bashbot_help='*Available commands*: 25 | /echo message - _echo the given messsage_ 26 | ' 27 | 28 | # NOTE: command can have @botname attached, you must add * in case tests... 29 | mycommands() { 30 | 31 | case "$MESSAGE" in 32 | '/echo'*) # example echo command 33 | send_normal_message "${CHAT[ID]}" "$MESSAGE" 34 | ;; 35 | # ..... 36 | esac 37 | } 38 | ``` 39 | 40 | ### DIsable, replace and extend global commands 41 | 42 | Global bashbot command processing, e.g. /start, /info etc. is disabled if you return a non zero value from `mycommands.sh`, 43 | see /start example below. 44 | 45 | To replace a global bashbot command add the same command to `mycommands.sh` and place `return 1` at the end of 46 | the case block, see /kickme example below. 47 | 48 | If a command is available as a global command and in `mycommands.sh`, plus you return a zero value (nothing or 0) 49 | both command sections are processed. Thus you can extend global commands with additional actions, see /info example below 50 | 51 | **Learn more about [Bot commands](https://core.telegram.org/bots#commands).** 52 | 53 | ```bash 54 | # file: mycommands.sh 55 | 56 | case "$MESSAGE" in 57 | ########## 58 | # disable start command 59 | '/start'*) # disable all commands starting with leave 60 | return 1 61 | ;; 62 | # replace command with your own actions 63 | '/kickme'*) # this will replace the /kickme command 64 | send_markdown_mesage "${CHAT[ID]}" "*This bot will not kick you!*" 65 | return 1 66 | ;; 67 | # extend global command 68 | '/info'*) # output date in front of regular info 69 | send_normal_message "${CHAT[ID]}" "$(date)" 70 | return 0 71 | ;; 72 | esac 73 | ``` 74 | 75 | 76 | ### Separate logic from commands 77 | 78 | If a command need more than 2-3 lines of code, you should use a function to separate logic from command. Place your functions in `mycommands.sh` and call the from your command. Example: 79 | ```bash 80 | # file: mycommands.sh 81 | # your additional bashbot commands 82 | 83 | mycommands() { 84 | 85 | case "$MESSAGE" in 86 | '/doit'*) # logic for /doit is done in process_message 87 | result="$(process_message "$MESSAGE")" 88 | send_normal_message "${CHAT[ID]}" "$result" 89 | ;; 90 | esac 91 | 92 | } 93 | 94 | # place your functions here 95 | 96 | process_message() { 97 | local ARGS="${1#/* }" # remove command 98 | local TEXT OUTPUT="" 99 | 100 | # process every word in MESSAGE, avoid globbing 101 | set -f 102 | for WORD in $ARGS 103 | do 104 | # process links 105 | if [[ "$WORD" == "https://"* ]]; then 106 | REPORT="$(dosomething_with_link "$WORD")" 107 | # no link, add as text 108 | else 109 | TEXT="$(echo "${TEXT} $WORD")" 110 | continue 111 | fi 112 | # compose result 113 | OUTPUT="* ${REPORT} ${WORD} ${TEXT}" 114 | TEXT="" 115 | done 116 | 117 | # return result, reset globbing in case we had no ARGS 118 | echo "${OUTPUT}${TEXT}" 119 | } 120 | 121 | ``` 122 | 123 | ### Test your Bot with shellcheck 124 | Shellcheck is a static linter for shell scripts providing excellent tips and hints for shell coding pittfalls. You can [use it online](https://www.shellcheck.net/) or [install it on your system](https://github.com/koalaman/shellcheck#installing). 125 | All bashbot scripts are linted by shellcheck. 126 | 127 | Shellcheck examples: 128 | ```bash 129 | $ shellcheck -x mybotcommands.inc.sh 130 | 131 | Line 17: 132 | TEXT="$(echo "${TEXT} $WORD")" 133 | ^-- SC2116: Useless echo? Instead of 'cmd $(echo foo)', just use 'cmd foo'. 134 | 135 | ``` 136 | 137 | As you can see my `mybotcommands.inc.sh` contains an useless echo command in 'TEXT=' assignment and can be replaced by `TEXT="${TEXT}${WORD}"` 138 | 139 | ```bash 140 | $ shellcheck -x examples/notify 141 | OK 142 | $ shellcheck -x examples/question 143 | OK 144 | $ shellcheck -x commands.sh 145 | OK 146 | $ shellcheck -x bashbot.sh 147 | 148 | In bashbot.sh line 123: 149 | text="$(echo "$text" | sed 's/ mynewlinestartshere /\r\n/g')" # hack for linebreaks in startproc scripts 150 | ^-- SC2001: See if you can use ${variable//search/replace} instead. 151 | 152 | 153 | In bashbot.sh line 490: 154 | CONTACT[USER_ID]="$(sed -n -e '/\["result",'$PROCESS_NUMBER',"message","contact","user_id"\]/ s/.*\][ \t]"\(.*\)"$/\1/p' <"$TMP")" 155 | ^-- SC2034: CONTACT appears unused. Verify it or export it. 156 | ``` 157 | The example show two warnings in bashbots scripts. The first is a hint you may use shell substitutions instead of sed, this is fixed and much faster as the "echo | sed" solution. 158 | The second warning is about an unused variable, this is true because in our examples CONTACT is not used but assigned in case you want to use it :-) 159 | 160 | #### [Prev Best Practice](5_practice.md) 161 | #### [Next Functions Reference](6_reference.md) 162 | 163 | #### $$VERSION$$ v1.52-1-g0dae2db 164 | 165 | -------------------------------------------------------------------------------- /doc/bashbot.ascii: -------------------------------------------------------------------------------- 1 | 2 | .. 3 | **** 4 | ****oooooo***** 5 | *****ooooooooooooo***** 6 | *****oooooooooooooooooooooo**** 7 | ****oooooooooooooooooooooooooooooooo** 8 | *.*oooooooooooooooooooooooooooooooooooo** 9 | *.ooooooooooooooooooooooooooooooooo**.... 10 | *.oooooooooooooooooooooooooooo**......... 11 | *.oooooooooooooooooooooooo**............. 12 | *.ooooooooooooooooooo**.................. ____ _ _ _ 13 | *.ooooooooooooooooo*.......,............. | _ \ | | | | | | 14 | *.ooooooooooooooooo*.....,***,........... | |_) | __ _ ___ | |__ | |__ ___ | |_ 15 | *.ooooooooooooooooo*....o*............... | _ < / _` |/ __|| '_ \ | '_ \ / _ \ | __| 16 | *.ooooooooooooooooo*....*o***,........... | |_) || (_| |\__ \| | | || |_) || (_) || |_ 17 | *.*oooooooooooooooo*........o*.....oo.... |____/ \__,_||___/|_| |_||_.__/ \___/ \__| 18 | ****ooooooooooooo*....`***....oo.....* 19 | *****oooooooo*......*..oo.....** 20 | ******ooo*.............* 21 | ***o*........** 22 | **...** 23 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | #### [Home](../README.md) 2 | 3 | ## Bashbot examples 4 | 5 | ### bashbot multi 6 | An example wrapper to run multiple instances of bashbot, use ```./bashbot-multi.sh botname command``` 7 | 8 | ### bashbot.cron 9 | An example crontab is provided in ```examples/bashbot.cron```, see [Expert use](../doc/4_expert.md#Scedule-bashbot-from-Cron) 10 | 11 | 12 | ### Interactive chats 13 | Two examples for interactive scripts are provided as **calc.sh** and **question.sh**, see [Advanced use](../doc/3_advanced.md#Interactive-Chats) 14 | 15 | ### Background scripts 16 | 17 | Background jobs are an easy way to provide sceduled messages or alerts if something happens. 18 | **notify.sh** is a simple example on how to send a message every x seonds, e.g. current time. 19 | 20 | **background-scripts** contains a more useful example on how to start and stop different scripts plus some example background scripts. 21 | 22 | ``` 23 | mycommands.sh - /run_xxx and /kill-xxx will start any script named run_xxx.sh 24 | 25 | run_diskusage.sh - shows disk usage every 100 seconds 26 | run_filename.sh - shown the name of new files in a named dir 27 | run_filecontent.sh - shown the content of new files in a named dir 28 | run_notify.sh - same as notify.sh 29 | ``` 30 | **Note:** Output of system commands often contains newlines, each newline results in a telegram message, the function 'send_telegram' in 31 | mycommands.sh avoids this by converting each newline to ' mynewlinestartshere ' before output the string. 32 | 33 | ### System Status 34 | 35 | **send-system-status** contains an example for commands showing status of different subsystems. This example is adapted from 36 | https://github.com/RG72/telegram-bot-bash to current bashbot commands, but not fully tested. This will show how easy you can 37 | convert existing bots. 38 | 39 | ``` 40 | mycommands.sh - commands to show system status 41 | botacl - controls who can show system status 42 | 43 | *Available commands*: 44 | /se *sensors* 45 | /smb *smbstatus* 46 | /free *memory status* 47 | /md *raid status* 48 | /lvm *lvm status* 49 | /lvsd *Datailed lvm status* 50 | /df *disk space* 51 | /ifconfig *ifconfig output* 52 | /smart *sda* _smart status for sda drive_ 53 | ``` 54 | ### jsonDB and Keyboards 55 | 56 | **jsonDB-keybords** contains a stripped down real world example from my bot showing the usage of jsonDB to store and retrieve values 57 | plus use of keyboards in private chats. It's an extended version of mycommands.sh.dist. Messages and help are in german. 58 | 59 | ### Webhook 60 | 61 | **Webhook** contains instructions on how use webhook API to get updates from telegram instead polling Telegram server. 62 | 63 | #### $$VERSION$$ v1.52-1-g0dae2db 64 | 65 | 66 | -------------------------------------------------------------------------------- /examples/background-scripts/mycommands.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # files: mycommands.sh.dist 3 | # copy to mycommands.sh and add all your commands an functions here ... 4 | export res 5 | 6 | # your additional bashbot commands ... 7 | mycommands() { 8 | 9 | case "${MESSAGE}" in 10 | '/run_'*) 11 | myback="run_${MESSAGE#*_}" 12 | if [ -x "./${myback}.sh" ]; then 13 | checkback "${myback}" 14 | if [ "${res}" -gt 0 ] ; then 15 | send_normal_message "${CHAT[ID]}" "Start ${myback}, use /kill${myback} to stop it." 16 | background "./${myback}.sh" "${myback}" 17 | else 18 | send_normal_message "${CHAT[ID]}" "Background job ${myback} already running." 19 | fi 20 | fi 21 | ;; 22 | '/kill_'*) 23 | myback="run_${MESSAGE#*_}" 24 | if [ -x "./${myback}.sh" ]; then 25 | checkback "${myback}" 26 | if [ "${res}" -eq 0 ] ; then 27 | killback "${myback}" 28 | send_normal_message "${CHAT[ID]}" "Stopping ${myback}, use /run_${myback} to start again." 29 | else 30 | send_normal_message "${CHAT[ID]}" "No background job ${myback}." 31 | fi 32 | fi 33 | ;; 34 | esac 35 | } 36 | 37 | # place your additional processing functions here ... 38 | 39 | # inifnite loop for waching a given dir for new files 40 | # $1 dir to wtach for new files 41 | watch_dir_loop() { 42 | local newfile old 43 | [ ! -d "$1" ] && echo "ERROR: no directory $1 found!" >&2 && exit 1 44 | # wait for new files in WATCHDIR 45 | inotifywait -q -m "$1" -e create --format "%f" \ 46 | | while true 47 | do 48 | # read in newfile 49 | read -r newfile 50 | 51 | #skip if not match or same name as last time 52 | [ "${newfile}" = "${old}" ] && continue 53 | sleep 0.2 54 | 55 | # process content and output message 56 | echo "$(date): new file: ${newfile}" >>"$0.log" 57 | # note: loop callback must a function in the calling script! 58 | if _is_function loop_callback ; then 59 | loop_callback "$1/${newfile}" 60 | else 61 | echo "ERROR: loop_callback not found!" >&2 62 | exit 1 63 | fi 64 | done 65 | } # 2>>"$0.log" 66 | 67 | 68 | output_telegram() { 69 | # output to telegram 70 | sed <<< "${1}" -e ':a;N;$!ba;s/\n/ mynewlinestartshere /g' 71 | } # 2>>"$0.log" 72 | 73 | # name and location of the tml file 74 | 75 | # $1 string to output 76 | # $2 file to add file to 77 | output_html_file() { 78 | local date 79 | date="$(date)" 80 | output_file "$(sed <<< "
$1
${date}
" ' 81 | s/ my[a-z]\{3,15}\(start\|ends\)here.*
/
/g 82 | s/ *mynewlinestartshere */
/ 83 | s/\n/
/ 84 | ')" 85 | } # >>"$0.log" 2>&1 86 | 87 | # $1 string to output 88 | # $2 file to add file to 89 | output_file() { 90 | local publish="${2}" 91 | [ ! -w "${publish}" ] && echo "ERROR: file ${publish} is not writeable or does not exist!" && exit 92 | 93 | # output at beginnung of file, add date to message 94 | sed <<< "${1}" ' 95 | s/ *mynewlinestartshere */\n/ 96 | s/ my[a-z]\{3,15}\(start\|ends\)here.*//g 97 | ' >"${publish}$$" 98 | cat "${publish}" >>"${publish}$$" 99 | mv "${publish}$$" "${publish}" 100 | } # >>"$0.log" 2>&1 101 | 102 | -------------------------------------------------------------------------------- /examples/background-scripts/run_diskusage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # file: run_diskusage.sh 3 | # example for an background job display a system value 4 | # 5 | # This file is public domain in the USA and all free countries. 6 | # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) 7 | #### $$VERSION$$ v1.52-1-g0dae2db 8 | 9 | ###### 10 | # parameters 11 | # $1 $2 args as given to starct_proc chat script arg1 arg2 12 | # $3 path to named pipe/log 13 | 14 | 15 | # adjust your language setting here 16 | # https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment 17 | export 'LC_ALL=C.UTF-8' 18 | export 'LANG=C.UTF-8' 19 | export 'LANGUAGE=C.UTF-8' 20 | 21 | unset IFS 22 | # set -f # if you are paranoid use set -f to disable globbing 23 | 24 | # discard STDIN for background jobs! 25 | cat >/dev/null & 26 | 27 | # shellcheck source=examples/background-scripts/mycommands.sh 28 | source "./mycommands.sh" 29 | 30 | # check if $1 is a number 31 | regex='^[0-9]+$' 32 | if [[ $1 =~ ${regex} ]] ; then 33 | SLEEP="$1" 34 | else 35 | SLEEP=100 # time between time notifications 36 | fi 37 | 38 | NEWLINE=$'\n' 39 | 40 | # output disk usage every $1 seconds 41 | WAIT=0 42 | while sleep "${WAIT}" 43 | do 44 | output_telegram "Current Disk usage ${NEWLINE} $(df -h / /tmp /usr /var /home)" 45 | # only for testing, delete echo line for production ... 46 | echo "Current Disk usage ${NEWLINE} $(df -h / /tmp /usr /var /home)" 47 | WAIT="${SLEEP}" 48 | done 49 | 50 | -------------------------------------------------------------------------------- /examples/background-scripts/run_filecontent.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # file: run_filename 3 | # background job to display content of all new files in WATCHDIR 4 | # 5 | #### $$VERSION$$ v1.52-1-g0dae2db 6 | 7 | ###### 8 | # parameters 9 | # $1 $2 args as given to starct_proc chat script arg1 arg2 10 | # $3 path to named pipe/log 11 | 12 | 13 | # adjust your language setting here 14 | # https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment 15 | export 'LC_ALL=C.UTF-8' 16 | export 'LANG=C.UTF-8' 17 | export 'LANGUAGE=C.UTF-8' 18 | 19 | unset IFS 20 | # set -f # if you are paranoid use set -f to disable globbing 21 | 22 | # discard STDIN for background jobs! 23 | cat >/dev/null & 24 | 25 | # watch for new files created by a trusted program 26 | WATCHDIR="/my_trusted/dir_to_watch" 27 | 28 | # shellcheck source=examples/background-scripts/mycommands.sh 29 | source "./mycommands.sh" 30 | 31 | # test your script and the remove ... 32 | WATCHDIR="/tmp/bottest" 33 | 34 | NEWLINE='mynewlinestartshere' 35 | 36 | # this is called by watch dir loop 37 | # $1 is name of the new file 38 | loop_callback() { 39 | # output content of file, you must trust creator because content is sent as message! 40 | output_telegram "Contents of ${1}: ${NEWLINE} $(cat "${1}")" 41 | } 42 | 43 | watch_dir_loop "${WATCHDIR}" 44 | -------------------------------------------------------------------------------- /examples/background-scripts/run_filename.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # file: run_filename 3 | # background job to display all new files in WATCHDIR 4 | # 5 | #### $$VERSION$$ v1.52-1-g0dae2db 6 | 7 | ###### 8 | # parameters 9 | # $1 $2 args as given to starct_proc chat script arg1 arg2 10 | # $3 path to named pipe/log 11 | 12 | 13 | # adjust your language setting here 14 | # https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment 15 | export 'LC_ALL=C.UTF-8' 16 | export 'LANG=C.UTF-8' 17 | export 'LANGUAGE=C.UTF-8' 18 | 19 | unset IFS 20 | # set -f # if you are paranoid use set -f to disable globbing 21 | 22 | # shellcheck source=examples/background-scripts/mycommands.sh 23 | cat >/dev/null & 24 | 25 | # watch for new logfiles 26 | WATCHDIR="/var/log" 27 | 28 | # shellcheck disable=SC1091 29 | source "./mycommands.sh" 30 | 31 | # test your script and the remove ... 32 | WATCHDIR="/tmp/bottest" 33 | 34 | # this is called by watch dir loop 35 | # $1 is name of the new file 36 | loop_callback() { 37 | # output one simple line ... 38 | echo "New file ${1} created in ${WATCHDIR}!" 39 | } 40 | 41 | watch_dir_loop "${WATCHDIR}" 42 | 43 | -------------------------------------------------------------------------------- /examples/background-scripts/run_notify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # file: notify.sh 3 | # example for an background job, run with startback notify.sh 4 | # 5 | # This file is public domain in the USA and all free countries. 6 | # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) 7 | #### $$VERSION$$ v1.52-1-g0dae2db 8 | 9 | ###### 10 | # parameters 11 | # $1 $2 args as given to starct_proc chat script arg1 arg2 12 | # $3 path to named pipe/log 13 | 14 | 15 | # adjust your language setting here 16 | # https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment 17 | export 'LC_ALL=C.UTF-8' 18 | export 'LANG=C.UTF-8' 19 | export 'LANGUAGE=C.UTF-8' 20 | 21 | unset IFS 22 | # set -f # if you are paranoid use set -f to disable globbing 23 | 24 | # discard STDIN for background jobs! 25 | cat >/dev/null & 26 | 27 | # check if $1 is a number 28 | regex='^[0-9]+$' 29 | if [[ "$1" =~ ${regex} ]] ; then 30 | SLEEP="$1" 31 | else 32 | SLEEP=10 # time between time notifications 33 | fi 34 | 35 | # output current time every $1 seconds 36 | while sleep "${SLEEP}" 37 | do 38 | date "+* It's %k:%M:%S o' clock ..." 39 | done 40 | 41 | -------------------------------------------------------------------------------- /examples/bash2env.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # file: bash2env.sh 3 | # simole helper script to convert bash shebang from 4 | # ! /bin/bash TO ! /usr/bin/env bash 5 | 6 | # This file is public domain in the USA and all free countries. 7 | # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) 8 | # shellcheck disable=SC1117 9 | #### $$VERSION$$ v1.52-1-g0dae2db 10 | 11 | # adjust your language setting here 12 | # https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment 13 | export 'LC_ALL=C.UTF-8' 14 | export 'LANG=C.UTF-8' 15 | export 'LANGUAGE=C.UTF-8' 16 | 17 | unset IFS 18 | MYSHEBANG="" 19 | 20 | ################ 21 | # uncomment one of the following lines to make the conversion 22 | # Linux/Unix bash 23 | # MYSHEBANG="#!/bin/bash" 24 | 25 | # BSD bash 26 | # MYSHEBANG="#!/usr/bin/bash" 27 | 28 | # homebrew gnu bash on MacOS 29 | # MYSHEBANG="#!/usr/local/opt/bash" 30 | 31 | # use portable /usr/bin/env 32 | # MYSHEBANG="#!/usr/bin/env bash" 33 | 34 | # bashbot default bash 35 | FROMSHEBANG="#!/bin/bash" 36 | 37 | # uncomment to convert back to bashbot default bash 38 | # FROMSHEBANG="#!/usr/bin/env bash" 39 | # MYSHEBANG="#!/bin/bash" 40 | 41 | if [ "$1" = "" ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then 42 | echo "$0: convert bash shebang to point to your local installation" 43 | echo "usage: $0 script [script ...]" 44 | exit 45 | fi 46 | 47 | # loop tomprocess files 48 | if [ "${MYSHEBANG}" != "" ]; then 49 | echo "Warning, shebang will changed from ${FROMSHEBANG} changed to ${MYSHEBANG}!" 50 | else 51 | echo "Dry run, demonstration only!" 52 | echo "Uncomment one of the MYSHEBANG= lines fitting your environment to make the changes permanent." 53 | 54 | fi 55 | 56 | echo "Press enter to continue ..." 57 | #shellcheck disable=SC2034 58 | read -r CONTINUE 59 | 60 | 61 | for file in "$@" 62 | do 63 | file "${file}" 64 | if [[ "$(file -b "${file}")" =~ Bourne.*script.*text ]]; then 65 | echo "Processing ${file} ..." 66 | if head -n 1 "${file}" | grep -q "^${FROMSHEBANG}"; then 67 | if [ "${MYSHEBANG}" != "" ]; then 68 | sed -i -e '1 s|^'"${FROMSHEBANG}"'|'"${MYSHEBANG}"'|' "${file}" 69 | head -n 1 "${file}" 70 | else 71 | sed -n -e '1 s|^'"${FROMSHEBANG}"'|#!/some/shebang/bash (dry run)|p' "${file}" 72 | fi 73 | else 74 | echo "Found: $(head -n 1 "${file}") - Nothing to convert." 75 | fi 76 | echo -e "... done.\n" 77 | else 78 | echo -e "Not a bash script, skipping ${file} ...\n" 79 | fi 80 | done 81 | -------------------------------------------------------------------------------- /examples/bashbot-multi.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # file. multibot.sh 3 | # description: run multiple telegram bots from one installation 4 | # 5 | #### $$VERSION$$ v1.52-1-g0dae2db 6 | 7 | if [ "$2" = "" ] || [ "$2" = "-h" ]; then 8 | echo "Usage: $0 botname command" 9 | exit 1 10 | fi 11 | 12 | BOT="$1" 13 | [ "${#BOT}" -lt 5 ] && echo "Botname must have a minimum length of 5 characters" && exit 1 14 | 15 | # where should the bots live? 16 | # true in one dir, false in separate dirs 17 | if true; then 18 | # example for all in one bashbot dir 19 | BINDIR="/usr/local/telegram-bot-bash" 20 | ETC="${BINDIR}" 21 | VAR="${BINDIR}" 22 | 23 | else 24 | # alternative Linux-like locations 25 | BINDIR="/usr/local/bin" 26 | ETC="/etc/bashbot" 27 | VAR="/var/bashbot" 28 | export BASHBOT_JSONSH="/usr/local/bin/JSON.sh" 29 | 30 | fi 31 | 32 | # set final ENV 33 | export BASHBOT_ETC="${ETC}/${BOT}" 34 | export BASHBOT_VAR="${VAR}/${BOT}" 35 | 36 | # some checks 37 | [ ! -d "${BINDIR}" ] && echo "Dir ${BINDIR} does not exist" && exit 1 38 | [ ! -d "${BASHBOT_ETC}" ] && echo "Dir ${BASHBOT_ETC} does not exist" && exit 1 39 | [ ! -d "${BASHBOT_VAR}" ] && echo "Dir ${BASHBOT_VAR} does not exist" && exit 1 40 | [ ! -x "${BINDIR}/bashbot.sh" ] && echo "${BINDIR}/bashbot.sh not executable or does not exist" && exit 1 41 | [ ! -r "${BASHBOT_ETC}/commands.sh" ] && echo "${BASHBOT_ETC}/commands.sh not readable or does not exist" && exit 1 42 | [ ! -r "${BASHBOT_ETC}/mycommands.sh" ] && echo "${BASHBOT_ETC}/mycommands.sh not readable or does not exist" && exit 1 43 | 44 | "${BINDIR}/bashbot.sh" "$2" 45 | -------------------------------------------------------------------------------- /examples/bashbot.cron: -------------------------------------------------------------------------------- 1 | # 2 | # this is an example crontab file for telegram-bot-bash 3 | # copy it to /etc/cron.d/bashbot 4 | # 5 | # (c) https://github.com/gnadelwartz 6 | # 7 | # This file is public domain in the USA and all free countries. 8 | # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) 9 | # 10 | #### $$VERSION$$ v1.52-1-g0dae2db 11 | 12 | 13 | SHELL=/bin/sh 14 | PATH=/sbin:/usr/sbin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin: 15 | # place your mailadress here 16 | MAILTO=root 17 | 18 | 19 | # ┌───────────── minute (0 - 59) 20 | # │ ┌───────────── hour (0 - 23) 21 | # │ │ ┌───────────── day of the month (1 - 31) 22 | # │ │ │ ┌───────────── month (1 - 12) 23 | # │ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday; 24 | # │ │ │ │ │ 7 is also Sunday on some systems) 25 | # │ │ │ │ │ 26 | # │ │ │ │ │ ┌───────────── run as user (must be omited in users crontab 27 | # │ │ │ │ │ | 28 | # * * * * * USER command to execute 29 | # * * * * * root echo "run every minute!" 30 | 31 | # run as www every day at 0:00 plus random sleep between 0-3h 32 | 0 0 * * * nobody sleep "$((RANDOM \% 180 ))m" ; /usr/local/telegram-bot-bash/bashbot.rc start # (re)start bot 33 | 0 0 * * * nobody sleep "$((RANDOM \% 180 ))m" ; /usr/local/telegram-bot-bash/bashbot.rc resumeback # (re)start background jobs 34 | 35 | # run as www on 24 of Dec, 12:00 36 | 0 12 24 12 * nobody /usr/local/telegram-bot-bash/bashbot.sh broadcast "X-Mas shopping is over!" # broadcast a message 37 | 38 | -------------------------------------------------------------------------------- /examples/calc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ######################################################################## 3 | # 4 | # File: calc.sh 5 | # 6 | # Description: example for an background job, see mycommands.sh.dist 7 | # 8 | # Usage: runback calc example/calc.sh - or run in terminal 9 | # killback calc - to stop background job 10 | # 11 | # This file is public domain in the USA and all free countries. 12 | # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) 13 | # 14 | #### $$VERSION$$ v1.52-1-g0dae2db 15 | ######################################################################## 16 | 17 | ###### 18 | # parameters 19 | # $1 $2 args as given to starct_proc chat script arg1 arg2 20 | # $3 path to named pipe/log 21 | 22 | INPUT="${3:-/dev/stdin}" 23 | 24 | # adjust your language setting here 25 | # https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment 26 | export 'LC_ALL=C.UTF-8' 27 | export 'LANG=C.UTF-8' 28 | export 'LANGUAGE=C.UTF-8' 29 | 30 | unset IFS 31 | # set -f # if you are paranoid use set -f to disable globbing 32 | 33 | printf 'Starting Calculator ...\n' 34 | printf 'Enter first number.\n' 35 | read -r A <"${INPUT}" 36 | printf 'Enter second number.\n' 37 | read -r B <"${INPUT}" 38 | printf 'Select Operation: mykeyboardstartshere [ "Addition" , "Subtraction" , "Multiplication" , "Division" , "Cancel" ]\n' 39 | read -r opt <"${INPUT}" 40 | printf 'Result: ' 41 | case ${opt,,} in 42 | 'a'*) res="$(( A + B ))" ;; 43 | 's'*) res="$(( A - B ))" ;; 44 | 'm'*) res="$(( A * B ))" ;; 45 | 'd'*) res="$(( A / B ))" ;; 46 | 'c'*) res="abort!" ;; 47 | * ) printf "unknown operator!\n";; 48 | esac 49 | printf "%s\nBye ...\n" "${res}" 50 | 51 | -------------------------------------------------------------------------------- /examples/notify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ######################################################################## 3 | # 4 | # File: notify.sh 5 | # 6 | # Description: example for an background job, see mycommands.sh.dist 7 | # 8 | # Usage: runback notify example/notify.sh [seconds] - or run in terminal 9 | # killback notify - to stop background job 10 | # 11 | # Options: seconds - time to sleep between output, default 10 12 | # 13 | # This file is public domain in the USA and all free countries. 14 | # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) 15 | # 16 | #### $$VERSION$$ v1.52-1-g0dae2db 17 | ######################################################################## 18 | 19 | ###### 20 | # parameters 21 | # $1 $2 args as given to starct_proc chat script arg1 arg2 22 | # $3 path to named pipe/log 23 | 24 | # adjust your language setting here 25 | # https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment 26 | export 'LC_ALL=C.UTF-8' 27 | export 'LANG=C.UTF-8' 28 | export 'LANGUAGE=C.UTF-8' 29 | 30 | unset IFS 31 | # set -f # if you are paranoid use set -f to disable globbing 32 | 33 | # discard STDIN for background jobs! 34 | cat >/dev/null & 35 | 36 | # $1 = time between time notifications 37 | # check if $1 is a valid number 38 | if [[ "$1" =~ ^[0-9]+$ ]] ; then 39 | SLEEP="$1" 40 | else 41 | SLEEP=10 42 | fi 43 | 44 | # output current time every $1 seconds 45 | printf "Output time every %s seconds ...\n" "${SLEEP}" 46 | 47 | while true 48 | do 49 | date "+* It's %k:%M:%S o'clock ..." 50 | sleep "${SLEEP}" 51 | done 52 | 53 | -------------------------------------------------------------------------------- /examples/question.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ######################################################################## 3 | # 4 | # File: question.sh 5 | # 6 | # Usage: runproc example/question.sh - or run in terminal 7 | # 8 | # Description: example for an interactive chat, see mycommands.sh.dist 9 | # 10 | # This file is public domain in the USA and all free countries. 11 | # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) 12 | # 13 | #### $$VERSION$$ v1.52-1-g0dae2db 14 | ######################################################################## 15 | 16 | ###### 17 | # parameters 18 | # $1 $2 args as given to starct_proc chat script arg1 arg2 19 | # $3 path to named pipe 20 | 21 | INPUT="${3:-/dev/stdin}" 22 | 23 | # adjust your language setting here 24 | # https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment 25 | export 'LC_ALL=C.UTF-8' 26 | export 'LANG=C.UTF-8' 27 | export 'LANGUAGE=C.UTF-8' 28 | 29 | unset IFS 30 | # set -f # if you are paranoid use set -f to disable globbing 31 | 32 | # kill interactive script if not finished in time, e.g. user away or error 33 | MAXWAIT="1m" 34 | { sleep "${MAXWAIT}"; printf "Stopping Questionnaire after %s, you need to much time to finish ... BYE\n" "${MAXWAIT}"; kill $$; wait 2>/dev/null ;} & 35 | 36 | # simple yes/no question, defaults to no 37 | printf "Hi, hello there\nWould you like some tea (y/n)?\n" 38 | read -r answer <"${INPUT}" 39 | if [[ ${answer,,} == "y"* ]]; then 40 | printf "OK then, here you go: http://www.rivertea.com/blog/wp-content/uploads/2013/12/Green-Tea.jpg\n" 41 | else 42 | printf "OK then, no tea ...\n" 43 | fi 44 | 45 | # question with Keyboard, repeating until correct answer given 46 | until [ "${SUCCESS}" = "y" ] ;do 47 | printf 'Do you like Music? mykeyboardstartshere "Yass!" , "No"\n' 48 | read -r answer <"${INPUT}" 49 | case ${answer,,} in 50 | '') printf "empty answer! Try again\n";; 51 | 'yass'*) printf "Goody! mykeyboardendshere\n";SUCCESS=y;; 52 | 'no'*) printf "Well that's weird. mykeyboardendshere\n";SUCCESS=y;; 53 | *) SUCCESS=n;; 54 | esac 55 | done 56 | printf "OK, Done!\n" 57 | 58 | -------------------------------------------------------------------------------- /examples/send-system-status/botacl: -------------------------------------------------------------------------------- 1 | # file: botacl 2 | # a user not listed here, will return false from 'user_is_allowed' 3 | # 4 | #### $$VERSION$$ v1.52-1-g0dae2db 5 | # Format: 6 | # user:resource:chat 7 | 8 | # allow user 123456789 access to all resources in all chats 9 | 123456789:*:* 10 | 11 | # allow user 12131415 to request systemstatus in all chats 12 | 12131415:systemstatus:* 13 | 14 | # * are only allowed on the right hand side and not for user! 15 | # the following examples are NOT valid! 16 | *:*:* 17 | *:start:* 18 | *:*:98979695 19 | -------------------------------------------------------------------------------- /examples/send-system-status/mycommands.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # files: mycommands.sh 3 | # 4 | # this example is rendered after https://github.com/RG72/telegram-bot-bash 5 | # to show how you can customize bashbot by only editing mycommands.sh 6 | # NOTE: this is not tested, simply copied from original source and reworked! 7 | # 8 | #### $$VERSION$$ v1.52-1-g0dae2db 9 | # 10 | # shellcheck disable=SC2154 11 | # shellcheck disable=SC2034 12 | 13 | 14 | # uncomment the following lines to overwrite info and help messages 15 | #' 16 | 17 | # returned messages 18 | 19 | bashbot_info='This bot allows you to request status of your system. 20 | To begin using the bot, try with the /help command. 21 | ' 22 | bashbot_help='*Available commands*: 23 | /se *sensors* 24 | /smb *smbstatus* 25 | /free *memory status* 26 | /md *raid status* 27 | /lvm *lvm status* 28 | /lvsd *Datailed lvm status* 29 | /df *disk space* 30 | /ifconfig *ifconfig output* 31 | /smart *-d sda* _smart status for sda drive_ 32 | ' 33 | 34 | 35 | # your additional bashbot commands 36 | # NOTE: command can have @botname attached, you must add * in case tests... 37 | mycommands() { 38 | local msg="" 39 | 40 | if user_is_botadmin "${USER[ID]}" || user_is_allowed "${USER[ID]}" "systemstatus"; then 41 | case "${CMD}" in 42 | '/md'*) msg="$(cat /proc/mdstat)";; 43 | '/smb'*) msg="$(smbstatus)" ;; 44 | '/se'*) msg="$(sensors | sed -r 's/\s|\)+//g' | sed -r 's/\(high=|\(min=/\//' | sed -r 's/\,crit=|\,max=/\//')";; 45 | '/free'*) msg="$(free -h)";; 46 | '/pvs'*) msg="$(pvs)";; 47 | '/ifc'*) msg="$(ifconfig)";; 48 | '/vgs'*) msg="$(vgs)";; 49 | '/lvm'*) msg="$(lvs | sed -r 's/\s+/\n/g')";; 50 | '/lvsd'*) msg="$(lvs -a -o +devices | sed -r 's/\s+/\n/g')";; 51 | '/smart'*) 52 | [ "${CMD[1]}" == "" ] && msg="example \`/smart sda\`" && return 53 | drive="$(echo "${CMD[1]}" | cut -c 1-3)" 54 | echo "smartctl -a /dev/${drive}" 55 | msg="$(smartctl -a "/dev/${drive}")" 56 | ;; 57 | '/df') msg="$(df -h | sed -r 's/^/\n/' | sed -r 's/\s+/\n/g')";; 58 | esac 59 | 60 | if [ "${msg}" != "" ]; then 61 | send_normal_message "${CHAT[ID]}" "${msg}" 62 | fi 63 | else 64 | send_normal_message "${USER[ID]}" "Sorry, you are not allowed to use this bot!" 65 | fi 66 | } 67 | 68 | # place your processing functions here 69 | 70 | -------------------------------------------------------------------------------- /examples/webhook/BASHBOT_HOME: -------------------------------------------------------------------------------- 1 | /usr/local/github/telegram-bot-bash-develop/DIST/telegram-bot-bash 2 | /usr/local/github/telegram-bot-bash-develop/STANDALONE 3 | /usr/local/telegram-bot-bash 4 | -------------------------------------------------------------------------------- /examples/webhook/README.md: -------------------------------------------------------------------------------- 1 | #### [Examples](../README.md) 2 | 3 | ## Bashbot webhook example 4 | 5 | ### Webhook 6 | 7 | Bashbot default mode is to poll Telegram server for updates but Telegram offers webhook as a more efficient method to deliver updates. 8 | If your server is reachable from the Internet its possible to use the method described here. 9 | 10 | Prerequisite for receiving Telegram updates with webhook is a valid SSL certificate, a self signed certificate will not be sufficient. 11 | 12 | Webhook processing require special setup on server and Telegram side, therefore it's implemented as separate scripts and you need at least sudo rights to setup. 13 | 14 | #### Setup Apache webhook 15 | 16 | Prerequisite: An Apache webserver with a valid SLL certificate chain and php enabled.\ 17 | This should work with other webservers also but it's not testet. 18 | 19 | Setup webhook with Apache: 20 | 21 | - install bashbot as described in [Bashbot Installation](../../doc/0_install.md) 22 | - create file `data-bot-bash/webhook-fifo-` (_\ as in `botconfig.jssh`_) 23 | - run `sudo bashbot.sh init` to setup bashbot to run as same user as web server (_e.g. www_) 24 | - create a directory in web root: `telegram/` (_ as `botconfig.jssh`_) 25 | - give web server access to directory (_e.g.`chown www:www -R telegram`_) 26 | - go into the new directory and copy all files from `examples/webhook` to it 27 | - edit file `BASHBOT_HOME` to contain ithe Bashbot installation directory as first line (_other lines are ignored_) 28 | - execute `php index.php` with user id of web server to test write access to `data-bot-bash/webhook-fifo- 29 | 30 | Calling `https:///telegram//` will execute `index.php` 31 | thus append received data to the file `data-bot-bash/webhook-fifo-`. 32 | E.g. `https:///telegram//?json={"test":"me"}` will append `{"test":"me"}`. 33 | 34 | Now your Server is ready to receive updates from Telegram. 35 | 36 | 37 | #### Default webhook processing 38 | 39 | This is the testet and supported default method for processing Telegram updates over webhook. 40 | 41 | To enable update processing delete the file `data-bot-bash/webhook-fifo-` if webhook is working as described above. 42 | Incoming Telegram updates are now forwarded to the script `bin/process_update.sh` for processing. 43 | 44 | On incoming Telegram updates the script is executed, it sources bashbot.sh and forward the update to Bashbot for processing. 45 | Even it seems overhead to source Bashbot for every update, it's more responsive and create less load than Bashbot polling mode. 46 | 47 | Nevertheles there are some limitations compared to polling mode: 48 | - no startup actions 49 | - `addons` and `TIMER_EVENTS` are not working 50 | 51 | Interactive and background jobs are working as of Bashbot Version 1.51. 52 | 53 | #### Full webhook processing 54 | 55 | Full webhook processing use an external script to imitate Bashbot polling mode with webhook. 56 | 57 | 1. Default webook method must work first! 58 | 2. run `bashbot.sh init` to setup bashbot to run with your user id 59 | 2. Create a named pipe: `mkfifo data-bot-bash/webhook-fifo-botname` and give the web server write access to it 60 | 3. execute `php index.php` with user id of web server to test write access to `data-bot-bash/webhook-fifo- 61 | 4. Start script for Bashbot webhook polling mode:\ 62 | `bin/process-batch.sh --startbot --watch data-bot-bash/webhook-fifo-` 63 | 64 | The script read updates from given file line by line and forward updates to Bashbot update processing. `--startbot` will run the startup actions 65 | (_e.g. load addons, start TIMER, trigger first run_) and `--watch` will wait for new updates instead of exit on end of file. 66 | Short form: 'bin/process-batch.sh -s -w' 67 | 68 | If script works as expected, you may run Bashbot webook polling in background by using `./bachbot.rc starthook/stophook`. 69 | 70 | To switch back to default processing delete fifo `data-bot-bash/webhook-fifo-` and stop `bin/process-batch.sh`. 71 | 72 | #### Enable webhook on Telegram side 73 | 74 | To get updates via webhook your server must be reachable from the internet and you must 75 | instruct Telegram where to deliver updates, this is done by calling bashbot function `set_webhook`. 76 | 77 | *Example:* 78 | 79 | ```bash 80 | bin/any_command.sh set_webhook "https://myserver.com/telegram" 81 | ``` 82 | 83 | instruct Telegram to use the URL `https://myserver.com/telegram//` to deliver updates. 84 | After you enable webhook to deliver Telegram updates it's no more possible to poll updates with `bashbot.sh start`. 85 | 86 | To stop delivering of Telegram updates via webhook run `bin/any_command.sh delete_webhook`. 87 | 88 | **Important**: Telegram will refuse to deliver updates if your webhook has no valid SSL certificate chain. 89 | 90 | 91 | #### Bash webhook 92 | 93 | A pure bash webhook implementation is not possible without extra software because Telegram delivers 94 | webhook updates only over secure TLS connections with a valid SSL certificate chain. 95 | 96 | `socat` looks like a tool to listen for Telegram updates from bash scripts, let's see ... 97 | 98 | 99 | #### $$VERSION$$ v1.52-1-g0dae2db 100 | 101 | -------------------------------------------------------------------------------- /examples/webhook/index.php: -------------------------------------------------------------------------------- 1 | = 20 && strpos($tmp, '/.') === false) { 25 | $BASHBOT_HOME=$tmp; 26 | } 27 | } 28 | 29 | // bashbot config file 30 | $CONFIG=$BASHBOT_HOME.'/botconfig.jssh'; 31 | // set botname here or read botname from config file if unknown 32 | $botname="unknown"; 33 | if ($botname == "unknown" && file_exists($CONFIG)) { 34 | $prefix='["botname"] "'; 35 | $len=strlen($prefix); 36 | $arr = file($CONFIG, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); 37 | foreach ($arr as $line) { 38 | if(substr($line, 0, $len) == $prefix) { 39 | $botname=substr($line, $len, strlen($line)-$len-1); 40 | } 41 | } 42 | 43 | } 44 | 45 | // script endpoint 46 | $cmd=$BASHBOT_HOME.'/bin/process_update.sh'; 47 | // default fifo endpoint 48 | $fifo=$BASHBOT_HOME.'/data-bot-bash/webhook-fifo-'.$botname; 49 | 50 | // prepeare read, e.g. run from CLI 51 | $data=''; 52 | $input="php://input"; 53 | $json_file="json.txt"; 54 | if (php_sapi_name() == "cli") { 55 | if(is_readable($json_file)) { 56 | $input=$json_file; 57 | } else { 58 | $input="php://stdin"; 59 | } 60 | } 61 | // read request data 62 | if($json = file_get_contents($input)) { 63 | $data = $json; 64 | } else { 65 | $data = implode(" ",$_POST); 66 | if ($data == '') { $data = implode(" ",$_GET); } 67 | } 68 | // uncomment to save last received JSON 69 | // file_put_contents($json_file, str_replace(array("\n", "\r"), '',$data). PHP_EOL)); 70 | 71 | // prepare for writing 72 | if ($data == '') { 73 | error_response(400, "No data received"); 74 | } 75 | if (! chdir($BASHBOT_HOME)) { 76 | error_response(403, "No route to bot home"); 77 | } 78 | 79 | // fifo or command? 80 | if (! is_writeable($fifo)) { 81 | // pipe to command 82 | if (! file_exists($cmd)) { 83 | error_response(502, "Webhook endpoint not found"); 84 | } 85 | if (! $handle = popen( $cmd.' debug', 'w' )) { 86 | error_response(503, "Can't open webhook command endpoint"); 87 | } 88 | } else { 89 | // write to fifo 90 | if (! $handle = fopen( $fifo, 'a' )) { 91 | error_response(503, "Can't open webhook file endpoint"); 92 | } 93 | flock($handle, LOCK_EX); 94 | } 95 | if (fwrite( $handle, str_replace(array("\n", "\r"), '',$data). PHP_EOL) === false) { 96 | error_response(504, "Write to webhook failed"); 97 | } 98 | flock($handle, LOCK_UN); 99 | pclose($handle); 100 | /**/ 101 | 102 | function error_response($code, $msg) { 103 | $api = substr(php_sapi_name(), 0, 3); 104 | if ($api == 'cgi' || $api == 'fpm') { 105 | header('Status: '.$code.' '.$msg); 106 | } else { 107 | $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0'; 108 | header($protocol.' '.$code.' '.$msg); 109 | } 110 | exit('Error '.$code.': '.$msg. PHP_EOL); 111 | } 112 | ?> 113 | -------------------------------------------------------------------------------- /examples/webhook/json.txt: -------------------------------------------------------------------------------- 1 | {"update_id":665220889,"message":{"message_id":760,"from":{"id":BOTADMIN,"is_bot":false,"first_name":"Kay","last_name":"M","username":"KayM","language_code":"de"},"chat":{"id":BOTADMIN,"first_name":"Kay","last_name":"M","username":"KayM","type":"private"},"date":1612029749,"text":"/info","entities":[{"offset":0,"length":5,"type":"bot_command"}]}} 2 | -------------------------------------------------------------------------------- /modules/aliases.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # file: modules/aliases.sh 3 | # do not edit, this file will be overwritten on update 4 | 5 | # This file is public domain in the USA and all free countries. 6 | # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) 7 | # 8 | #### $$VERSION$$ v1.52-1-g0dae2db 9 | # 10 | # will be automatically sourced from bashbot 11 | 12 | # source once magic, function named like file 13 | eval "$(basename "${BASH_SOURCE[0]}")(){ :; }" 14 | 15 | # easy handling of users: 16 | _is_botadmin() { 17 | user_is_botadmin "${USER[ID]}" 18 | } 19 | _is_admin() { 20 | user_is_admin "${CHAT[ID]}" "${USER[ID]}" 21 | } 22 | _is_creator() { 23 | user_is_creator "${CHAT[ID]}" "${USER[ID]}" 24 | } 25 | _is_allowed() { 26 | user_is_allowed "${USER[ID]}" "$1" "${CHAT[ID]}" 27 | } 28 | _leave() { 29 | leave_chat "${CHAT[ID]}" 30 | } 31 | _kick_user() { 32 | kick_chat_member "${CHAT[ID]}" "$1" 33 | } 34 | _unban_user() { 35 | unban_chat_member "${CHAT[ID]}" "$1" 36 | } 37 | # easy sending of messages of messages 38 | _message() { 39 | send_normal_message "${CHAT[ID]}" "$1" 40 | } 41 | _normal_message() { 42 | send_normal_message "${CHAT[ID]}" "$1" 43 | } 44 | _html_message() { 45 | send_html_message "${CHAT[ID]}" "$1" 46 | } 47 | _markdown_message() { 48 | send_markdown_message "${CHAT[ID]}" "$1" 49 | } 50 | # easy handling of keyboards 51 | _inline_button() { 52 | send_inline_button "${CHAT[ID]}" "" "$1" "$2" 53 | } 54 | _inline_keyboard() { 55 | send_inline_keyboard "${CHAT[ID]}" "" "$1" 56 | } 57 | _keyboard_numpad() { 58 | send_keyboard "${CHAT[ID]}" "" '["1","2","3"],["4","5","6"],["7","8","9"],["-","0","."]' "yes" 59 | } 60 | _keyboard_yesno() { 61 | send_keyboard "${CHAT[ID]}" "" '["yes","no"]' 62 | } 63 | _del_keyboard() { 64 | remove_keyboard "${CHAT[ID]}" "" 65 | } 66 | -------------------------------------------------------------------------------- /modules/answerInline.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # file: modules/inline.sh 3 | # do not edit, this file will be overwritten on update 4 | 5 | # This file is public domain in the USA and all free countries. 6 | # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) 7 | # 8 | #### $$VERSION$$ v1.52-1-g0dae2db 9 | 10 | # will be automatically sourced from bashbot 11 | 12 | # source once magic, function named like file 13 | eval "$(basename "${BASH_SOURCE[0]}")(){ :; }" 14 | 15 | 16 | answer_inline_query() { 17 | answer_inline_multi "$1" "$(shift; inline_query_compose "${RANDOM}" "$@")" 18 | } 19 | answer_inline_multi() { 20 | sendJson "" '"inline_query_id": '"$1"', "results": ['"$2"']' "${URL}/answerInlineQuery" 21 | } 22 | 23 | # $1 unique ID for answer 24 | # $2 type of answer 25 | # remaining arguments are the "must have" arguments in the order as in telegram doc 26 | # followed by the optional arguments: https://core.telegram.org/bots/api#inlinequeryresult 27 | inline_query_compose(){ 28 | local JSON="{}" 29 | local ID="$1" 30 | local fours last 31 | # title2Json title caption description markup inlinekeyboard 32 | case "$2" in 33 | # user provided media 34 | "article"|"message") # article ID title message (markup description) 35 | JSON='{"type":"article","id":"'${ID}'","input_message_content": {"message_text":"'$4'"} '$(title2Json "$3" "" "$5" "$6" "$7")'}' 36 | ;; 37 | "photo") # photo ID photoURL (thumbURL title description caption) 38 | [ -z "$4" ] && tumb="$3" 39 | JSON='{"type":"photo","id":"'${ID}'","photo_url":"'$3'","thumb_url":"'$4${tumb}'"'$(title2Json "$5" "$7" "$6" "$7" "$8")'}' 40 | ;; 41 | "gif") # gif ID photoURL (thumbURL title caption) 42 | [ -z "$4" ] && tumb="$3" 43 | JSON='{"type":"gif","id":"'${ID}'","gif_url":"'$3'", "thumb_url":"'$4${tumb}'"'$(title2Json "$5" "$6" "$7" "$8" "$9")'}' 44 | ;; 45 | "mpeg4_gif") # mpeg4_gif ID mpegURL (thumbURL title caption) 46 | [ -n "$4" ] && tumb='","thumb_url":"'$4'"' 47 | JSON='{"type":"mpeg4_gif","id":"'${ID}'","mpeg4_url":"'$3'"'${tumb}$(title2Json "$5" "$6" "" "$7" "$8")'}' 48 | ;; 49 | "video") # video ID videoURL mime thumbURL title (caption) 50 | JSON='{"type":"video","id":"'${ID}'","video_url":"'$3'","mime_type":"'$4'","thumb_url":"'$5'"'$(title2Json "$6" "$7" "$8" "$9" "${10}")'}' 51 | ;; 52 | "audio") # audio ID audioURL title (caption) 53 | JSON='{"type":"audio","id":"'${ID}'","audio_url":"'$3'"'$(title2Json "$4" "$5" "" "" "$6")'}' 54 | ;; 55 | "voice") # voice ID voiceURL title (caption) 56 | JSON='{"type":"voice","id":"'${ID}'","voice_url":"'$3'"'$(title2Json "$4" "$5" "" "" "$6")'}' 57 | ;; 58 | "document") # document ID title documentURL mimetype (caption description) 59 | JSON='{"type":"document","id":"'${ID}'","document_url":"'$4'","mime_type":"'$5'"'$(title2Json "$3" "$6" "$7" "$8" "$9")'}' 60 | ;; 61 | "location") # location ID lat long title 62 | JSON='{"type":"location","id":"'${ID}'","latitude":"'$3'","longitude":"'$4'","title":"'$5'"}' 63 | ;; 64 | "venue") # venue ID lat long title (address forsquare) 65 | [ -z "$6" ] && addr="$5" 66 | [ -n "$7" ] && fours=',"foursquare_id":"'$7'"' 67 | JSON='{"type":"venue","id":"'${ID}'","latitude":"'$3'","longitude":"'$4'","title":"'$5'","address":"'$6${addr}'"'${fours}'}' 68 | ;; 69 | "contact") # contact ID phone first (last thumb) 70 | [ -n "$5" ] && last=',"last_name":"'$5'"' 71 | [ -n "$6" ] && tumb='","thumb_url":"'$6'"' 72 | JSON='{"type":"contact","id":"'${ID}'","phone_number":"'$3'","first_name":"'$4'"'${last}'"}' 73 | ;; 74 | # title2Json title caption description markup inlinekeyboard 75 | # Cached media stored in Telegram server 76 | "cached_photo") # photo ID file (title description caption) 77 | JSON='{"type":"photo","id":"'${ID}'","photo_file_id":"'$3'"'$(title2Json "$4" "$6" "$5" "$7" "$8")'}' 78 | ;; 79 | "cached_gif") # gif ID file (title caption) 80 | JSON='{"type":"gif","id":"'${ID}'","gif_file_id":"'$3'"'$(title2Json "$4" "$5" "$6" "$7" "$8" )'}' 81 | ;; 82 | "cached_mpeg4_gif") # mpeg ID file (title caption) 83 | JSON='{"type":"mpeg4_gif","id":"'${ID}'","mpeg4_file_id":"'$3'"'$(title2Json "$4" "$5" "" "$6" "$7")'}' 84 | ;; 85 | "cached_sticker") # sticker ID file 86 | JSON='{"type":"sticker","id":"'${ID}'","sticker_file_id":"'$3'"}' 87 | ;; 88 | "cached_document") # document ID title file (description caption) 89 | JSON='{"type":"document","id":"'${ID}'","document_file_id":"'$4'"'$(title2Json "$3" "$6" "$5" "$6" "$7")'}' 90 | ;; 91 | "cached_video") # video ID file title (description caption) 92 | JSON='{"type":"video","id":"'${ID}'","video_file_id":"'$3'"'$(title2Json "$4" "$6" "$5" "$7" "$8")'}' 93 | ;; 94 | "cached_voice") # voice ID file title (caption) 95 | JSON='{"type":"voice","id":"'${ID}'","voice_file_id":"'$3'"'$(title2Json "$4" "$5" "" "" "$6")'}' 96 | ;; 97 | "cached_audio") # audio ID file title (caption) 98 | JSON='{"type":"audio","id":"'${ID}'","audio_file_id":"'$3'"'$(title2Json "$4" "$5" "" "" "$6")'}' 99 | ;; 100 | esac 101 | 102 | printf '%s\n' "${JSON}" 103 | } 104 | 105 | -------------------------------------------------------------------------------- /modules/background.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # file: modules/background.sh 3 | # do not edit, this file will be overwritten on update 4 | 5 | # This file is public domain in the USA and all free countries. 6 | # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) 7 | # 8 | # shellcheck disable=SC1117,SC2059 9 | #### $$VERSION$$ v1.52-1-g0dae2db 10 | 11 | # will be automatically sourced from bashbot 12 | 13 | # source once magic, function named like file 14 | eval "$(basename "${BASH_SOURCE[0]}")(){ :; }" 15 | 16 | ###### 17 | # interactive and background functions 18 | 19 | # old syntax as aliases 20 | background() { 21 | start_back "${CHAT[ID]}" "$1" "$2" 22 | } 23 | startproc() { 24 | start_proc "${CHAT[ID]}" "$1" "$2" 25 | } 26 | checkback() { 27 | check_back "${CHAT[ID]}" "$1" 28 | } 29 | checkproc() { 30 | check_proc "${CHAT[ID]}" "$1" 31 | } 32 | killback() { 33 | kill_back "${CHAT[ID]}" "$1" 34 | } 35 | killproc() { 36 | kill_proc "${CHAT[ID]}" "$1" 37 | } 38 | 39 | # inline and background functions 40 | # $1 chatid 41 | # $2 program 42 | # $3 jobname 43 | # $4 $5 parameters 44 | start_back() { 45 | local cmdfile; cmdfile="${DATADIR:-.}/$(procname "$1")$3-back.cmd" 46 | printf '%s\n' "$1:$3:$2" >"${cmdfile}" 47 | restart_back "$@" 48 | } 49 | # $1 chatid 50 | # $2 program 51 | # $3 jobname 52 | # $4 $5 parameters 53 | restart_back() { 54 | local fifo; fifo="${DATADIR:-.}/$(procname "$1" "back-$3-")" 55 | log_update "Start background job CHAT=$1 JOB=${fifo##*/} CMD=${2##*/} $4 $5" 56 | check_back "$1" "$3" && kill_proc "$1" "back-$3-" 57 | nohup bash -c "{ $2 \"$4\" \"$5\" \"${fifo}\" | \"${SCRIPT}\" outproc \"$1\" \"${fifo}\"; }" &>>"${fifo}.log" & 58 | sleep 0.5 # give bg job some time to init 59 | } 60 | 61 | 62 | # $1 chatid 63 | # $2 program 64 | # $3 $4 parameters 65 | start_proc() { 66 | [ -z "$2" ] && return 67 | [ -x "${2%% *}" ] || return 1 68 | local fifo; fifo="${DATADIR:-.}/$(procname "$1")" 69 | check_proc "$1" && kill_proc "$1" 70 | mkfifo "${fifo}" 71 | log_update "Start interactive script CHAT=$1 JOB=${fifo##*/} CMD=$2 $3 $4" 72 | nohup bash -c "{ $2 \"$4\" \"$5\" \"${fifo}\" | \"${SCRIPT}\" outproc \"$1\" \"${fifo}\" 73 | rm \"${fifo}\"; [ -s \"${fifo}.log\" ] || rm -f \"${fifo}.log\"; }" &>>"${fifo}.log" & 74 | } 75 | 76 | 77 | # $1 chatid 78 | # $2 jobname 79 | check_back() { 80 | check_proc "$1" "back-$2-" 81 | } 82 | 83 | # $1 chatid 84 | # $2 prefix 85 | check_proc() { 86 | [ -n "$(proclist "$(procname "$1" "$2")")" ] 87 | # shellcheck disable=SC2034 88 | res=$?; return $? 89 | } 90 | 91 | # $1 chatid 92 | # $2 jobname 93 | kill_back() { 94 | kill_proc "$1" "back-$2-" 95 | rm -f "${DATADIR:-.}/$(procname "$1")$2-back.cmd" 96 | } 97 | 98 | 99 | # $1 chatid 100 | # $2 prefix 101 | kill_proc() { 102 | local fifo prid 103 | fifo="$(procname "$1" "$2")" 104 | prid="$(proclist "${fifo}")" 105 | fifo="${DATADIR:-.}/${fifo}" 106 | # shellcheck disable=SC2086 107 | if [ -n "${prid}" ]; then 108 | log_update "Stop interactive / background CHAT=$1 JOB=${fifo##*/}" 109 | kill ${prid} 110 | fi 111 | [ -s "${fifo}.log" ] || rm -f "${fifo}.log" 112 | [ -p "${fifo}" ] && rm -f "${fifo}"; 113 | } 114 | 115 | # $1 chatid 116 | # $2 message 117 | send_interactive() { 118 | local fifo; fifo="${DATADIR:-.}/$(procname "$1")" 119 | [ -p "${fifo}" ] && printf '%s\n' "$2" >"${fifo}" & # not blocking! 120 | } 121 | 122 | # old style but may not work because of local checks 123 | inproc() { 124 | send_interactive "${CHAT[ID]}" "${MESSAGE[0]}" 125 | } 126 | 127 | # start stop all jobs 128 | # $1 command # kill suspend resume restart 129 | job_control() { 130 | local BOT ADM content proc CHAT job fifo killall="" 131 | BOT="$(getConfigKey "botname")" 132 | ADM="${BOTADMIN}" 133 | debug_checks "Enter job_control" "$1" 134 | # cleanup on start 135 | [[ "$1" == "re"* ]] && bot_cleanup "startback" 136 | for FILE in "${DATADIR:-.}/"*-back.cmd; do 137 | [ "${FILE}" = "${DATADIR:-.}/*-back.cmd" ] && printf "${RED}No background processes.${NN}" && break 138 | content="$(< "${FILE}")" 139 | CHAT="${content%%:*}" 140 | job="${content#*:}" 141 | proc="${job#*:}" 142 | job="${job%:*}" 143 | fifo="$(procname "${CHAT}" "${job}")" 144 | debug_checks "Execute job_control" "$1" "${FILE##*/}" 145 | case "$1" in 146 | "resume"*|"restart"*) 147 | printf "Restart Job: %s %s\n" "${proc}" " ${fifo##*/}" 148 | restart_back "${CHAT}" "${proc}" "${job}" 149 | # inform botadmin about stop 150 | [ -n "${ADM}" ] && send_normal_message "${ADM}" "Bot ${BOT} restart background jobs ..." & 151 | ;; 152 | "suspend"*) 153 | printf "Suspend Job: %s %s\n" "${proc}" " ${fifo##*/}" 154 | kill_proc "${CHAT}" "${job}" 155 | # inform botadmin about stop 156 | [ -n "${ADM}" ] && send_normal_message "${ADM}" "Bot ${BOT} suspend background jobs ..." & 157 | killall="y" 158 | ;; 159 | "kill"*) 160 | printf "Kill Job: %s %s\n" "${proc}" " ${fifo##*/}" 161 | kill_proc "${CHAT}" "${job}" 162 | rm -f "${FILE}" # remove job 163 | # inform botadmin about stop 164 | [ -n "${ADM}" ] && send_normal_message "${ADM}" "Bot ${BOT} kill background jobs ..." & 165 | killall="y" 166 | ;; 167 | esac 168 | # send message only onnfirst job 169 | ADM="" 170 | done 171 | debug_checks "end job_control" "$1" 172 | # kill all requestet. kill ALL background jobs, even not listed in data-bot-bash 173 | [ "${killall}" = "y" ] && killallproc "back-" 174 | } 175 | -------------------------------------------------------------------------------- /modules/chatMember.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # file: modules/chatMember.sh 3 | # do not edit, this file will be overwritten on update 4 | 5 | # This file is public domain in the USA and all free countries. 6 | # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) 7 | # 8 | #### $$VERSION$$ v1.52-1-g0dae2db 9 | 10 | # will be automatically sourced from bashbot 11 | 12 | # source once magic, function named like file 13 | eval "$(basename "${BASH_SOURCE[0]}")(){ :; }" 14 | 15 | 16 | # manage chat functions ------- 17 | # $1 chat 18 | new_chat_invite() { 19 | sendJson "$1" "" "${URL}/exportChatInviteLink" 20 | [ "${BOTSENT[OK]}" = "true" ] && printf "%s\n" "${BOTSENT[RESULT]}" 21 | } 22 | 23 | # $1 chat, $2 user_id, $3 title 24 | set_chatadmin_title() { 25 | sendJson "$1" '"user_id":'"$2"',"custom_title": "'"$3"'"' "${URL}/setChatAdministratorCustomTitle" 26 | } 27 | # $1 chat, $2 title 28 | set_chat_title() { 29 | sendJson "$1" '"title": "'"$2"'"' "${URL}/setChatTitle" 30 | } 31 | 32 | # $1 chat, $2 title 33 | set_chat_description() { 34 | sendJson "$1" '"description": "'"$2"'"' "${URL}/setChatDescription" 35 | } 36 | 37 | # $1 chat $2 file 38 | set_chat_photo() { 39 | local file; file="$(checkUploadFile "$1" "$2" "set_chat_photo")" 40 | [ -z "${file}" ] && return 1 41 | sendUpload "$1" "photo" "${file}" "${URL}/setChatPhoto" 42 | } 43 | # $1 chat 44 | delete_chat_photo() { 45 | sendJson "$1" "" "${URL}/deleteChatPhoto" 46 | } 47 | 48 | # $1 chat, $2 message_id 49 | pin_chat_message() { 50 | sendJson "$1" '"message_id": "'"$2"'"' "${URL}/pinChatMessage" 51 | } 52 | 53 | # $1 chat, $2 message_id 54 | unpin_chat_message() { 55 | sendJson "$1" '"message_id": "'"$2"'"' "${URL}/unpinChatMessage" 56 | } 57 | 58 | # $1 chat 59 | unpinall_chat_message() { 60 | sendJson "$1" "" "${URL}/unpinAllChatMessages" 61 | } 62 | 63 | # $1 chat 64 | delete_chat_stickers() { 65 | sendJson "$1" "" "${URL}/deleteChatStickerSet" 66 | } 67 | 68 | # manage chat member functions ------- 69 | # $1 chat 70 | chat_member_count() { 71 | sendJson "$1" "" "${URL}/getChatMembersCount" 72 | [ "${BOTSENT[OK]}" = "true" ] && printf "%s\n" "${BOTSENT[RESULT]}" 73 | } 74 | 75 | kick_chat_member() { 76 | sendJson "$1" '"user_id": '"$2"'' "${URL}/kickChatMember" 77 | } 78 | 79 | unban_chat_member() { 80 | sendJson "$1" '"user_id": '"$2"'' "${URL}/unbanChatMember" 81 | } 82 | 83 | leave_chat() { 84 | sendJson "$1" "" "${URL}/leaveChat" 85 | } 86 | 87 | # $1 chat, $2 userid, $3 ... "right[:true]" default false 88 | # right: is_anonymous change_info post_messages edit_messages delete_messages invite_users restrict_members pin_messages promote_member 89 | promote_chat_member() { 90 | local arg bool json chat="$1" user="$2; shift 2" 91 | for arg in "$@" 92 | do 93 | # default false 94 | bool=false; [ "${arg##*:}" = "true" ] && bool="true" 95 | # expand args 96 | case "${arg}" in 97 | *"anon"*) arg="is_anonymous";; 98 | *"change"*) arg="can_change_info";; 99 | *"post"*) arg="can_post_messages";; 100 | *"edit"*) arg="can_edit_messages";; 101 | *"delete"*) arg="can_delete_messages";; 102 | *"pin"*) arg="can_pin_messages";; 103 | *"invite"*) arg="can_invite_users";; 104 | *"restrict"*) arg="can_restrict_members";; 105 | *"promote"*) arg="can_promote_members";; 106 | *) [ -n "${BASHBOTDEBUG}" ] && log_debug "promote_chat_member: unknown promotion CHAT=${chat} USER=${user} PROM=${arg}" 107 | continue;; 108 | esac 109 | # compose json 110 | [ -n "${json}" ] && json+="," 111 | json+='"'"${arg}"'": "'"${bool}"'"' 112 | done 113 | sendJson "${chat}" '"user_id":'"${user}"','"${json}"'' "${URL}/promoteChatMember" 114 | } 115 | 116 | # bashbot specific functions --------- 117 | 118 | # usage: status="$(get_chat_member_status "chat" "user")" 119 | # $1 chat # $2 user 120 | get_chat_member_status() { 121 | sendJson "$1" '"user_id":'"$2"'' "${URL}/getChatMember" 122 | # shellcheck disable=SC2154 123 | printf "%s\n" "${UPD["result,status"]}" 124 | } 125 | 126 | user_is_creator() { 127 | # empty is false ... 128 | [[ "${1:--}" == "${2:-+}" || "$(get_chat_member_status "$1" "$2")" == "creator" ]] && return 0 129 | return 1 130 | } 131 | 132 | # $1 chat 133 | bot_is_admin() { 134 | user_is_admin "$1" "$(getConfigKey "botid")" 135 | } 136 | 137 | # $1 chat # $2 user 138 | user_is_admin() { 139 | [[ -z "$1" || -z "$2" ]] && return 1 140 | [ "${1:--}" == "${2:-+}" ] && return 0 141 | user_is_botadmin "$2" && return 0 142 | local me; me="$(get_chat_member_status "$1" "$2")" 143 | [[ "${me}" =~ ^creator$|^administrator$ ]] && return 0 144 | return 1 145 | } 146 | 147 | # $1 user 148 | user_is_botadmin() { 149 | [ -z "$1" ] && return 1 150 | [ -z "${BOTADMIN}" ] && return 1 151 | [[ "${BOTADMIN}" == "$1" || "${BOTADMIN}" == "$2" ]] && return 0 152 | if [ "${BOTADMIN}" = "?" ]; then setConfigKey "botadmin" "${1:-?}"; BOTADMIN="${1:-?}"; return 0; fi 153 | return 1 154 | } 155 | 156 | # $1 user # $2 key # $3 chat 157 | user_is_allowed() { 158 | [ -z "$1" ] && return 1 159 | user_is_admin "$1" && return 0 160 | # user can do everything 161 | grep -F -xq "$1:*:*" "${BOTACL}" && return 0 162 | [ -z "$2" ] && return 1 163 | # user is allowed todo one action in every chat 164 | grep -F -xq "$1:$2:*" "${BOTACL}" && return 0 165 | # all users are allowed to do one action in every chat 166 | grep -F -xq "ALL:$2:*" "${BOTACL}" && return 0 167 | [ -z "$3" ] && return 1 168 | # user is allowed to do one action in one chat 169 | grep -F -xq "$1:$2:$3" "${BOTACL}" && return 0 170 | # all users are allowed to do one action in one chat 171 | grep -F -xq "ALL:$2:$3" "${BOTACL}" && return 0 172 | return 1 173 | } 174 | -------------------------------------------------------------------------------- /mycommands.conf: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # shellcheck disable=SC2034 3 | ####################################################### 4 | # 5 | # File: mycommands.conf 6 | # 7 | # Description: place your config and messages here 8 | # 9 | # Usage: will be sourced from mycommands.sh 10 | # 11 | # License: WTFPLv2 http://www.wtfpl.net/txt/copying/ 12 | # Author: KayM (gnadelwartz), kay@rrr.de 13 | # Created: 09.01.2021 07:27 14 | # 15 | #### $$VERSION$$ v1.52-1-g0dae2db 16 | ####################################################### 17 | 18 | ########## 19 | # adjust your language setting here, default is C.UTF-8 20 | # https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment 21 | export 'LC_ALL=C.UTF-8' 22 | export 'LANG=C.UTF-8' 23 | export 'LANGUAGE=C.UTF-8' 24 | 25 | ########## 26 | # in UTF-8 äöü etc. are part of [:alnum:] and ranges (e.g. a-z) 27 | # for more information see doc/4_expert.md#Character_classes 28 | # uncomment next line if you want classic ASCII ranges for [a-z] etc. 29 | #export LC_COLLATE=C 30 | 31 | 32 | ########## 33 | # edit the following lines to fit your bot usage 34 | # use ${ME} for current bot name in messages 35 | # Note: you must escape '_' in botname with two \ in markdown messages! 36 | 37 | # output of /info command 38 | export bashbot_info='This is @'"${ME//_/\\\\_}"', the Telegram example bot written entirely in bash. 39 | Edit commands and messages in mycommands.sh! 40 | ' 41 | 42 | # output of /help command (uncomment the next 2 lines 43 | # export bashbot_help='*Available commands*: 44 | # ' 45 | 46 | # Set INLINE to 1 in order to receive inline queries. 47 | # To enable this option in your bot, send the /setinline command to @BotFather. 48 | export INLINE="0" 49 | 50 | # Set CALLBACK to 1 in order to receive callback queries. 51 | # callbacks are sent from inline_keyboards (buttons) attached tp bot messages 52 | export CALLBACK="0" 53 | 54 | # if your bot is group admin it get commands sent to other bots 55 | # Set MEONLY to 1 to ignore commands sent to other bots 56 | export MEONLY="0" 57 | 58 | # Set to .* to allow sending files from all locations 59 | # NOTE: this is a regex, not shell globbing! you must use a valid egex, 60 | # '.' matches any character and '.*' matches all remaining charatcers! 61 | # additionally you must escape special characters with '\', e.g. '\. \? \[ \*" to match them literally 62 | export FILE_REGEX="${BASHBOT_ETC}/.*" 63 | 64 | # set BASHBOT_RETRY to enable retry in case of recoverable errors, e.g. throtteling 65 | # problems with send_xxx message etc are looged to logs/ERROR.log 66 | unset BASHBOT_RETRY 67 | #export BASHBOT_RETRY="yes" 68 | 69 | # set value for adaptive sleeping while waiting for uodates in millisconds 70 | # max slepp between polling updates 10s (default 5s) 71 | # export BASHBOT_SLEEP="10000" 72 | 73 | # max slepp between polling updates 2s (default 5s) 74 | # export BASHBOT_SLEEP="2000" 75 | 76 | # add 0.2s if no update available, up to BASHBOT_SLEEP (default 0.1s) 77 | export BASHBOT_SLEEP_STEP="200" 78 | 79 | # if you want to use timer functions, set BASHBOT_START_TIMER to a not empty value 80 | # default is to not start timer 81 | unset BASHBOT_START_TIMER 82 | #export BASHBOT_START_TIMER="yes" 83 | 84 | # set to "yes" and give your bot admin privilegs to remove service messages from groups 85 | export SILENCER="no" 86 | 87 | # uncomment to remove keyboards sent from your bot 88 | # export REMOVEKEYBOARD="yes" 89 | # export REMOVEKEYBOARD_PRIVATE="yes" 90 | 91 | # uncomment to say welcome to new chat members 92 | # export WELCOME_NEWMEMBER="yes" 93 | WELCOME_MSG="Welcome" 94 | 95 | # uncomment to be informed about new/left chat members 96 | # export REPORT_NEWMEMBER="yes" 97 | # export REPORT_LEFTMEMBER="yes" 98 | 99 | # uncomment to send user blocked by bot a warning if they send commands 100 | # export NOTIFY_BLOCKED_USERS="yes" 101 | 102 | # messages for admin only commands 103 | NOTADMIN="Sorry, this command is allowed for admin or owner only" 104 | NOTBOTADMIN="Sorry, this command is allowed for bot owner only" 105 | 106 | ######## 107 | # special network setup may require additional ARGS to curl 108 | # 109 | # example: run bashbot over TOR or SOCKS proxy 110 | # export BASHBOT_CURL_ARGS="--socks5-hostname 127.0.0.1:9050" # TOR 111 | # export BASHBOT_CURL_ARGS="--socks5-hostname 127.0.0.1" # regular SOCKS 112 | 113 | -------------------------------------------------------------------------------- /mycommands.sh.clean: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ####################################################### 3 | # 4 | # File: mycommands.sh.clean 5 | # 6 | # copy to mycommands.sh and add all your commands and functions here ... 7 | # 8 | # Usage: will be executed when a bot command is received 9 | # 10 | # License: WTFPLv2 http://www.wtfpl.net/txt/copying/ 11 | # Author: KayM (gnadelwartz), kay@rrr.de 12 | # 13 | #### $$VERSION$$ v1.52-1-g0dae2db 14 | ####################################################### 15 | # shellcheck disable=SC1117 16 | 17 | #################### 18 | # Config has moved to bashbot.conf 19 | # shellcheck source=./commands.sh 20 | [ -r "${BASHBOT_ETC:-.}/mycommands.conf" ] && source "${BASHBOT_ETC:-.}/mycommands.conf" "$1" 21 | 22 | 23 | ################## 24 | # lets's go 25 | if [ "$1" = "startbot" ];then 26 | ################### 27 | # this section is processed on startup 28 | 29 | # run once after startup when the first message is received 30 | my_startup(){ 31 | : 32 | } 33 | touch .mystartup 34 | else 35 | # call my_startup on first message after startup 36 | # things to do only once 37 | [ -f .mystartup ] && rm -f .mystartup && _exec_if_function my_startup 38 | 39 | ############################# 40 | # your own bashbot commands 41 | # NOTE: command can have @botname attached, you must add * to case tests... 42 | mycommands() { 43 | 44 | ############## 45 | # a service Message was received 46 | # add your own stuff here 47 | if [ -n "${SERVICE}" ]; then 48 | # example: delete every service message 49 | if [ "${SILENCER}" = "yes" ]; then 50 | delete_message "${CHAT[ID]}" "${MESSAGE[ID]}" 51 | fi 52 | fi 53 | 54 | # remove keyboard if you use keyboards 55 | [ -n "${REMOVEKEYBOARD}" ] && remove_keyboard "${CHAT[ID]}" & 56 | [[ -n "${REMOVEKEYBOARD_PRIVATE}" && "${CHAT[ID]}" == "${USER[ID]}" ]] && remove_keyboard "${CHAT[ID]}" & 57 | 58 | # uncommet to fix first letter upper case because of smartphone auto correction 59 | #[[ "${MESSAGE}" =~ ^/[[:upper:]] ]] && MESSAGE="${MESSAGE:0:1}$(tr '[:upper:]' '[:lower:]' <<<"${MESSAGE:1:1}")${MESSAGE:2}" 60 | case "${MESSAGE}" in 61 | ################## 62 | # example command, replace them by your own 63 | '/echo'*) # example echo command 64 | send_normal_message "${CHAT[ID]}" "${MESSAGE}" 65 | ;; 66 | 67 | ########## 68 | # command overwrite examples 69 | # return 0 -> run default command afterwards 70 | # return 1 -> skip possible default commands 71 | '/info'*) # output date in front of regular info 72 | send_normal_message "${CHAT[ID]}" "$(date)" 73 | return 0 74 | ;; 75 | '/kickme'*) # this will replace the /kickme command 76 | send_markdownv2_mesage "${CHAT[ID]}" "This bot will *not* kick you!" 77 | return 1 78 | ;; 79 | esac 80 | } 81 | 82 | mycallbacks() { 83 | ####################### 84 | # callbacks from buttons attached to messages will be processed here 85 | case "${iBUTTON[USER_ID]}+${iBUTTON[CHAT_ID]}" in 86 | *) # all other callbacks are processed here 87 | local callback_answer 88 | : # your processing here ... 89 | : 90 | # Telegram needs an ack each callback query, default empty 91 | answer_callback_query "${iBUTTON[ID]}" "${callback_answer}" 92 | ;; 93 | esac 94 | } 95 | myinlines() { 96 | ####################### 97 | # this fuinction is called only if you has set INLINE=1 !! 98 | # shellcheck disable=SC2128 99 | iQUERY="${iQUERY,,}" 100 | 101 | 102 | case "${iQUERY}" in 103 | ################## 104 | # example inline command, replace it by your own 105 | "image "*) # search images with yahoo 106 | local search="${iQUERY#* }" 107 | answer_inline_multi "${iQUERY[ID]}" "$(my_image_search "${search}")" 108 | ;; 109 | esac 110 | } 111 | 112 | ##################### 113 | # place your processing functions here 114 | 115 | # example inline processing function, not really useful 116 | # $1 search parameter 117 | my_image_search(){ 118 | local image result sep="" count="1" 119 | result="$(wget --user-agent 'Mozilla/5.0' -qO - "https://images.search.yahoo.com/search/images?p=$1" | sed 's/"test/${TEST}.sh" <"${LOGFILE}" <>"${LOGFILE}" 40 | diff -q "${TESTDIR}/${file}" "${REFDIR}/${file}" >>"${LOGFILE}" || { printf "%s\n" "${NOSUCCESS} Fail diff ${file}!"; FAIL="1"; } 41 | done 42 | [ "${FAIL}" != "0" ] && exit "${FAIL}" 43 | printf "%s\n" "${SUCCESS}" 44 | 45 | trap exit 1 EXIT 46 | cd "${TESTDIR}" || exit 47 | 48 | printf "%s\n" "Test if ${JSONSHFILE} exists ..." 49 | [ ! -x "${JSONSHFILE}" ] && { printf "%s\n" "${NOSUCCESS} json.sh not found"; exit 1; } 50 | 51 | printf "Test Sourcing of bashbot.sh ...\n" 52 | # shellcheck source=./bashbot.sh 53 | source "${TESTDIR}/bashbot.sh" source 54 | 55 | printf "Test Sourcing of commands.sh ...\n" 56 | source "${TESTDIR}/commands.sh" source 57 | 58 | trap '' EXIT 59 | cd "${DIRME}" || exit 1 60 | 61 | printf "%s\n" "${SUCCESS}" 62 | 63 | -------------------------------------------------------------------------------- /test/c-init-test/blocked.jssh: -------------------------------------------------------------------------------- 1 | ["blocked_user_or_chat_id"] "name and reason" 2 | -------------------------------------------------------------------------------- /test/c-init-test/botacl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/c-init-test/botconfig.jssh: -------------------------------------------------------------------------------- 1 | ["bot_config_key"] "config_key_value" 2 | ["bottoken"] "123456789:BASHBOTTESTSCRIPTbashbottestscript_" 3 | ["botadmin"] "?" 4 | -------------------------------------------------------------------------------- /test/c-init-test/count.jssh: -------------------------------------------------------------------------------- 1 | ["counted_user_chat_id"] "num_messages_seen" 2 | -------------------------------------------------------------------------------- /test/c-init-test/count.test: -------------------------------------------------------------------------------- 1 | ["counted_user_id"] "num_messages_seen" 2 | ["712677"] "2" 3 | ["-1001189446"] "29" 4 | ["-1001288661"] "6" 5 | ["-1001433755"] "4" 6 | ["-408138"] "2" 7 | ["1246831"] "7" 8 | ["-1001186489"] "4" 9 | ["-1001259400"] "8" 10 | ["791626"] "18" 11 | ["-1001293952"] "4" 12 | ["-1001435141"] "7" 13 | ["733039"] "2" 14 | ["-1001319011"] "6" 15 | ["-1001220313"] "15" 16 | ["26122"] "3" 17 | ["988411"] "8" 18 | ["908527"] "6" 19 | ["-1001450413"] "58" 20 | ["748933"] "2" 21 | ["-1001425571"] "5" 22 | ["788295"] "3" 23 | ["586928"] "45" 24 | ["-1001359971"] "7" 25 | ["1069707"] "19" 26 | ["-1001189446"] "30" 27 | ["-1001189446"] "31" 28 | -------------------------------------------------------------------------------- /test/c-init-test/stats.out: -------------------------------------------------------------------------------- 1 | A total of 272 messages from 24 users are processed. 2 | -------------------------------------------------------------------------------- /test/d-JSON.sh-test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #### $$VERSION$$ v1.52-1-g0dae2db 3 | 4 | # include common functions and definitions 5 | # shellcheck source=test/ALL-tests.inc.sh 6 | source "./ALL-tests.inc.sh" 7 | 8 | set -e 9 | 10 | # source bashbot.sh functionw 11 | cd "${TESTDIR}" || exit 1 12 | 13 | # run JSON.sh with and without options 14 | cd "test" || exit 1 15 | printf "Check JSON.sh ...\n" 16 | JSON="../JSON.sh/JSON.sh" 17 | 18 | for i in 1 2 19 | do 20 | [ "${i}" = "1" ] && printf " ... JSON.sh -b -n\n" 21 | [ "${i}" = "2" ] && printf " ... JSON.sh\n" 22 | set +f 23 | for jsonfile in "${REFDIR}"/*.in 24 | do 25 | set -f 26 | [ "${i}" = "1" ] && "${JSON}" -b -n <"${jsonfile}" >"${jsonfile}.out-${i}" 27 | [ "${i}" = "2" ] && "${JSON}" <"${jsonfile}" >"${jsonfile}.out-${i}" 28 | 29 | # output processed input 30 | diff -c "${jsonfile%.in}.result-${i}" "${jsonfile}.out-${i}" || exit 1 31 | done 32 | printf "%s\n" "${SUCCESS}" 33 | done 34 | 35 | cd "${DIRME}" || exit 1 36 | -------------------------------------------------------------------------------- /test/d-JSON.sh-test/JSON26783.log.in: -------------------------------------------------------------------------------- 1 | {"ok":true,"result":[{"update_id":146860898, 2 | "message":{"message_id":6620,"from":{"id":123456789,"is_bot":false,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","language_code":"de"},"chat":{"id":123456789,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","type":"private"},"date":1555934213,"location":{"latitude":49.630443,"longitude":8.361698},"venue":{"location":{"latitude":49.630443,"longitude":8.361698},"title":"Vannini","address":"K\u00e4mmererstr. 3","foursquare_id":"4bf94ec05ec320a115f889d3"}}}]} 3 | -------------------------------------------------------------------------------- /test/d-JSON.sh-test/JSON26783.log.result-1: -------------------------------------------------------------------------------- 1 | ["ok"] true 2 | ["result",0,"update_id"] 146860898 3 | ["result",0,"message","message_id"] 6620 4 | ["result",0,"message","from","id"] 123456789 5 | ["result",0,"message","from","is_bot"] false 6 | ["result",0,"message","from","first_name"] "Kay" 7 | ["result",0,"message","from","last_name"] "M" 8 | ["result",0,"message","from","username"] "Gnadelwartz" 9 | ["result",0,"message","from","language_code"] "de" 10 | ["result",0,"message","chat","id"] 123456789 11 | ["result",0,"message","chat","first_name"] "Kay" 12 | ["result",0,"message","chat","last_name"] "M" 13 | ["result",0,"message","chat","username"] "Gnadelwartz" 14 | ["result",0,"message","chat","type"] "private" 15 | ["result",0,"message","date"] 1555934213 16 | ["result",0,"message","location","latitude"] 49.630443 17 | ["result",0,"message","location","longitude"] 8.361698 18 | ["result",0,"message","venue","location","latitude"] 49.630443 19 | ["result",0,"message","venue","location","longitude"] 8.361698 20 | ["result",0,"message","venue","title"] "Vannini" 21 | ["result",0,"message","venue","address"] "K\u00e4mmererstr. 3" 22 | ["result",0,"message","venue","foursquare_id"] "4bf94ec05ec320a115f889d3" 23 | -------------------------------------------------------------------------------- /test/d-JSON.sh-test/JSON26783.log.result-2: -------------------------------------------------------------------------------- 1 | ["ok"] true 2 | ["result",0,"update_id"] 146860898 3 | ["result",0,"message","message_id"] 6620 4 | ["result",0,"message","from","id"] 123456789 5 | ["result",0,"message","from","is_bot"] false 6 | ["result",0,"message","from","first_name"] "Kay" 7 | ["result",0,"message","from","last_name"] "M" 8 | ["result",0,"message","from","username"] "Gnadelwartz" 9 | ["result",0,"message","from","language_code"] "de" 10 | ["result",0,"message","from"] {"id":123456789,"is_bot":false,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","language_code":"de"} 11 | ["result",0,"message","chat","id"] 123456789 12 | ["result",0,"message","chat","first_name"] "Kay" 13 | ["result",0,"message","chat","last_name"] "M" 14 | ["result",0,"message","chat","username"] "Gnadelwartz" 15 | ["result",0,"message","chat","type"] "private" 16 | ["result",0,"message","chat"] {"id":123456789,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","type":"private"} 17 | ["result",0,"message","date"] 1555934213 18 | ["result",0,"message","location","latitude"] 49.630443 19 | ["result",0,"message","location","longitude"] 8.361698 20 | ["result",0,"message","location"] {"latitude":49.630443,"longitude":8.361698} 21 | ["result",0,"message","venue","location","latitude"] 49.630443 22 | ["result",0,"message","venue","location","longitude"] 8.361698 23 | ["result",0,"message","venue","location"] {"latitude":49.630443,"longitude":8.361698} 24 | ["result",0,"message","venue","title"] "Vannini" 25 | ["result",0,"message","venue","address"] "K\u00e4mmererstr. 3" 26 | ["result",0,"message","venue","foursquare_id"] "4bf94ec05ec320a115f889d3" 27 | ["result",0,"message","venue"] {"location":{"latitude":49.630443,"longitude":8.361698},"title":"Vannini","address":"K\u00e4mmererstr. 3","foursquare_id":"4bf94ec05ec320a115f889d3"} 28 | ["result",0,"message"] {"message_id":6620,"from":{"id":123456789,"is_bot":false,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","language_code":"de"},"chat":{"id":123456789,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","type":"private"},"date":1555934213,"location":{"latitude":49.630443,"longitude":8.361698},"venue":{"location":{"latitude":49.630443,"longitude":8.361698},"title":"Vannini","address":"K\u00e4mmererstr. 3","foursquare_id":"4bf94ec05ec320a115f889d3"}} 29 | ["result",0] {"update_id":146860898,"message":{"message_id":6620,"from":{"id":123456789,"is_bot":false,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","language_code":"de"},"chat":{"id":123456789,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","type":"private"},"date":1555934213,"location":{"latitude":49.630443,"longitude":8.361698},"venue":{"location":{"latitude":49.630443,"longitude":8.361698},"title":"Vannini","address":"K\u00e4mmererstr. 3","foursquare_id":"4bf94ec05ec320a115f889d3"}}} 30 | ["result"] [{"update_id":146860898,"message":{"message_id":6620,"from":{"id":123456789,"is_bot":false,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","language_code":"de"},"chat":{"id":123456789,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","type":"private"},"date":1555934213,"location":{"latitude":49.630443,"longitude":8.361698},"venue":{"location":{"latitude":49.630443,"longitude":8.361698},"title":"Vannini","address":"K\u00e4mmererstr. 3","foursquare_id":"4bf94ec05ec320a115f889d3"}}}] 31 | [] {"ok":true,"result":[{"update_id":146860898,"message":{"message_id":6620,"from":{"id":123456789,"is_bot":false,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","language_code":"de"},"chat":{"id":123456789,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","type":"private"},"date":1555934213,"location":{"latitude":49.630443,"longitude":8.361698},"venue":{"location":{"latitude":49.630443,"longitude":8.361698},"title":"Vannini","address":"K\u00e4mmererstr. 3","foursquare_id":"4bf94ec05ec320a115f889d3"}}}]} 32 | -------------------------------------------------------------------------------- /test/d-JSON.sh-test/JSON30458.log.in: -------------------------------------------------------------------------------- 1 | {"ok":true,"result":[{"update_id":146860896, 2 | "message":{"message_id":6618,"from":{"id":123456789,"is_bot":false,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","language_code":"de"},"chat":{"id":123456789,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","type":"private"},"date":1555934195,"voice":{"duration":1,"mime_type":"audio/ogg","file_id":"AwADAgADKQMAAh638UnbhHGzIMozZgI","file_size":3963}}}]} 3 | -------------------------------------------------------------------------------- /test/d-JSON.sh-test/JSON30458.log.result-1: -------------------------------------------------------------------------------- 1 | ["ok"] true 2 | ["result",0,"update_id"] 146860896 3 | ["result",0,"message","message_id"] 6618 4 | ["result",0,"message","from","id"] 123456789 5 | ["result",0,"message","from","is_bot"] false 6 | ["result",0,"message","from","first_name"] "Kay" 7 | ["result",0,"message","from","last_name"] "M" 8 | ["result",0,"message","from","username"] "Gnadelwartz" 9 | ["result",0,"message","from","language_code"] "de" 10 | ["result",0,"message","chat","id"] 123456789 11 | ["result",0,"message","chat","first_name"] "Kay" 12 | ["result",0,"message","chat","last_name"] "M" 13 | ["result",0,"message","chat","username"] "Gnadelwartz" 14 | ["result",0,"message","chat","type"] "private" 15 | ["result",0,"message","date"] 1555934195 16 | ["result",0,"message","voice","duration"] 1 17 | ["result",0,"message","voice","mime_type"] "audio/ogg" 18 | ["result",0,"message","voice","file_id"] "AwADAgADKQMAAh638UnbhHGzIMozZgI" 19 | ["result",0,"message","voice","file_size"] 3963 20 | -------------------------------------------------------------------------------- /test/d-JSON.sh-test/JSON30458.log.result-2: -------------------------------------------------------------------------------- 1 | ["ok"] true 2 | ["result",0,"update_id"] 146860896 3 | ["result",0,"message","message_id"] 6618 4 | ["result",0,"message","from","id"] 123456789 5 | ["result",0,"message","from","is_bot"] false 6 | ["result",0,"message","from","first_name"] "Kay" 7 | ["result",0,"message","from","last_name"] "M" 8 | ["result",0,"message","from","username"] "Gnadelwartz" 9 | ["result",0,"message","from","language_code"] "de" 10 | ["result",0,"message","from"] {"id":123456789,"is_bot":false,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","language_code":"de"} 11 | ["result",0,"message","chat","id"] 123456789 12 | ["result",0,"message","chat","first_name"] "Kay" 13 | ["result",0,"message","chat","last_name"] "M" 14 | ["result",0,"message","chat","username"] "Gnadelwartz" 15 | ["result",0,"message","chat","type"] "private" 16 | ["result",0,"message","chat"] {"id":123456789,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","type":"private"} 17 | ["result",0,"message","date"] 1555934195 18 | ["result",0,"message","voice","duration"] 1 19 | ["result",0,"message","voice","mime_type"] "audio/ogg" 20 | ["result",0,"message","voice","file_id"] "AwADAgADKQMAAh638UnbhHGzIMozZgI" 21 | ["result",0,"message","voice","file_size"] 3963 22 | ["result",0,"message","voice"] {"duration":1,"mime_type":"audio/ogg","file_id":"AwADAgADKQMAAh638UnbhHGzIMozZgI","file_size":3963} 23 | ["result",0,"message"] {"message_id":6618,"from":{"id":123456789,"is_bot":false,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","language_code":"de"},"chat":{"id":123456789,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","type":"private"},"date":1555934195,"voice":{"duration":1,"mime_type":"audio/ogg","file_id":"AwADAgADKQMAAh638UnbhHGzIMozZgI","file_size":3963}} 24 | ["result",0] {"update_id":146860896,"message":{"message_id":6618,"from":{"id":123456789,"is_bot":false,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","language_code":"de"},"chat":{"id":123456789,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","type":"private"},"date":1555934195,"voice":{"duration":1,"mime_type":"audio/ogg","file_id":"AwADAgADKQMAAh638UnbhHGzIMozZgI","file_size":3963}}} 25 | ["result"] [{"update_id":146860896,"message":{"message_id":6618,"from":{"id":123456789,"is_bot":false,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","language_code":"de"},"chat":{"id":123456789,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","type":"private"},"date":1555934195,"voice":{"duration":1,"mime_type":"audio/ogg","file_id":"AwADAgADKQMAAh638UnbhHGzIMozZgI","file_size":3963}}}] 26 | [] {"ok":true,"result":[{"update_id":146860896,"message":{"message_id":6618,"from":{"id":123456789,"is_bot":false,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","language_code":"de"},"chat":{"id":123456789,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","type":"private"},"date":1555934195,"voice":{"duration":1,"mime_type":"audio/ogg","file_id":"AwADAgADKQMAAh638UnbhHGzIMozZgI","file_size":3963}}}]} 27 | -------------------------------------------------------------------------------- /test/d-JSON.sh-test/JSON32034.log.in: -------------------------------------------------------------------------------- 1 | {"ok":true,"result":[{"update_id":146860897, 2 | "message":{"message_id":6619,"from":{"id":123456789,"is_bot":false,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","language_code":"de"},"chat":{"id":586928566,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","type":"private"},"date":1555934204,"contact":{"phone_number":"222222","first_name":"ADAC Pannenhilfe","vcard":"BEGIN:VCARD\nVERSION:2.1\nN:Pannenhilfe;ADAC;;;\nFN:ADAC Pannenhilfe\nTEL;CELL;PREF:+49179222222\nTEL;X-Mobil:222222\nEND:VCARD"}}}]} 3 | -------------------------------------------------------------------------------- /test/d-JSON.sh-test/JSON32034.log.result-1: -------------------------------------------------------------------------------- 1 | ["ok"] true 2 | ["result",0,"update_id"] 146860897 3 | ["result",0,"message","message_id"] 6619 4 | ["result",0,"message","from","id"] 123456789 5 | ["result",0,"message","from","is_bot"] false 6 | ["result",0,"message","from","first_name"] "Kay" 7 | ["result",0,"message","from","last_name"] "M" 8 | ["result",0,"message","from","username"] "Gnadelwartz" 9 | ["result",0,"message","from","language_code"] "de" 10 | ["result",0,"message","chat","id"] 586928566 11 | ["result",0,"message","chat","first_name"] "Kay" 12 | ["result",0,"message","chat","last_name"] "M" 13 | ["result",0,"message","chat","username"] "Gnadelwartz" 14 | ["result",0,"message","chat","type"] "private" 15 | ["result",0,"message","date"] 1555934204 16 | ["result",0,"message","contact","phone_number"] "222222" 17 | ["result",0,"message","contact","first_name"] "ADAC Pannenhilfe" 18 | ["result",0,"message","contact","vcard"] "BEGIN:VCARD\nVERSION:2.1\nN:Pannenhilfe;ADAC;;;\nFN:ADAC Pannenhilfe\nTEL;CELL;PREF:+49179222222\nTEL;X-Mobil:222222\nEND:VCARD" 19 | -------------------------------------------------------------------------------- /test/d-JSON.sh-test/JSON32034.log.result-2: -------------------------------------------------------------------------------- 1 | ["ok"] true 2 | ["result",0,"update_id"] 146860897 3 | ["result",0,"message","message_id"] 6619 4 | ["result",0,"message","from","id"] 123456789 5 | ["result",0,"message","from","is_bot"] false 6 | ["result",0,"message","from","first_name"] "Kay" 7 | ["result",0,"message","from","last_name"] "M" 8 | ["result",0,"message","from","username"] "Gnadelwartz" 9 | ["result",0,"message","from","language_code"] "de" 10 | ["result",0,"message","from"] {"id":123456789,"is_bot":false,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","language_code":"de"} 11 | ["result",0,"message","chat","id"] 586928566 12 | ["result",0,"message","chat","first_name"] "Kay" 13 | ["result",0,"message","chat","last_name"] "M" 14 | ["result",0,"message","chat","username"] "Gnadelwartz" 15 | ["result",0,"message","chat","type"] "private" 16 | ["result",0,"message","chat"] {"id":586928566,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","type":"private"} 17 | ["result",0,"message","date"] 1555934204 18 | ["result",0,"message","contact","phone_number"] "222222" 19 | ["result",0,"message","contact","first_name"] "ADAC Pannenhilfe" 20 | ["result",0,"message","contact","vcard"] "BEGIN:VCARD\nVERSION:2.1\nN:Pannenhilfe;ADAC;;;\nFN:ADAC Pannenhilfe\nTEL;CELL;PREF:+49179222222\nTEL;X-Mobil:222222\nEND:VCARD" 21 | ["result",0,"message","contact"] {"phone_number":"222222","first_name":"ADAC Pannenhilfe","vcard":"BEGIN:VCARD\nVERSION:2.1\nN:Pannenhilfe;ADAC;;;\nFN:ADAC Pannenhilfe\nTEL;CELL;PREF:+49179222222\nTEL;X-Mobil:222222\nEND:VCARD"} 22 | ["result",0,"message"] {"message_id":6619,"from":{"id":123456789,"is_bot":false,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","language_code":"de"},"chat":{"id":586928566,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","type":"private"},"date":1555934204,"contact":{"phone_number":"222222","first_name":"ADAC Pannenhilfe","vcard":"BEGIN:VCARD\nVERSION:2.1\nN:Pannenhilfe;ADAC;;;\nFN:ADAC Pannenhilfe\nTEL;CELL;PREF:+49179222222\nTEL;X-Mobil:222222\nEND:VCARD"}} 23 | ["result",0] {"update_id":146860897,"message":{"message_id":6619,"from":{"id":123456789,"is_bot":false,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","language_code":"de"},"chat":{"id":586928566,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","type":"private"},"date":1555934204,"contact":{"phone_number":"222222","first_name":"ADAC Pannenhilfe","vcard":"BEGIN:VCARD\nVERSION:2.1\nN:Pannenhilfe;ADAC;;;\nFN:ADAC Pannenhilfe\nTEL;CELL;PREF:+49179222222\nTEL;X-Mobil:222222\nEND:VCARD"}}} 24 | ["result"] [{"update_id":146860897,"message":{"message_id":6619,"from":{"id":123456789,"is_bot":false,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","language_code":"de"},"chat":{"id":586928566,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","type":"private"},"date":1555934204,"contact":{"phone_number":"222222","first_name":"ADAC Pannenhilfe","vcard":"BEGIN:VCARD\nVERSION:2.1\nN:Pannenhilfe;ADAC;;;\nFN:ADAC Pannenhilfe\nTEL;CELL;PREF:+49179222222\nTEL;X-Mobil:222222\nEND:VCARD"}}}] 25 | [] {"ok":true,"result":[{"update_id":146860897,"message":{"message_id":6619,"from":{"id":123456789,"is_bot":false,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","language_code":"de"},"chat":{"id":586928566,"first_name":"Kay","last_name":"M","username":"Gnadelwartz","type":"private"},"date":1555934204,"contact":{"phone_number":"222222","first_name":"ADAC Pannenhilfe","vcard":"BEGIN:VCARD\nVERSION:2.1\nN:Pannenhilfe;ADAC;;;\nFN:ADAC Pannenhilfe\nTEL;CELL;PREF:+49179222222\nTEL;X-Mobil:222222\nEND:VCARD"}}}]} 26 | -------------------------------------------------------------------------------- /test/d-process_inline-test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #=============================================================================== 3 | # 4 | # FILE: d-process_inline-test.sh 5 | # 6 | # USAGE: must run only from dev/all-tests.sh 7 | # 8 | # DESCRIPTION: test response to inline messages 9 | # 10 | # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ 11 | # AUTHOR: KayM (gnadelwartz), kay@rrr.de 12 | # 13 | #### $$VERSION$$ v1.52-1-g0dae2db 14 | #=============================================================================== 15 | 16 | # include common functions and definitions 17 | # shellcheck source=test/ALL-tests.inc.sh 18 | source "./ALL-tests.inc.sh" 19 | 20 | set -e 21 | 22 | # source bashbot.sh functionw 23 | cd "${TESTDIR}" || exit 1 24 | # shellcheck source=./bashbot.sh 25 | source "${TESTDIR}/bashbot.sh" source 26 | # shellcheck source=./bashbot.sh 27 | source "${TESTDIR}/modules/answerInline.sh" source 28 | 29 | # overwrite get_file for test 30 | get_file() { 31 | printf "%s\n" "$1" 32 | } 33 | 34 | # get telegram input from file 35 | export UPDATE UPD 36 | UPDATE="$(cat "${INPUTFILE}")" 37 | declare -A UPD 38 | source <( printf 'UPD=( %s )' "$(sed <<<"${UPDATE}" -E -e 's/\t/=/g' -e 's/=(true|false)/="\1"/')" ) 39 | 40 | # run process_message with and without python 41 | printf "Check process_inline ...\n" 42 | printf " ... with JsonDecode Bash\n" 43 | set -x 44 | { process_inline_query "0"; set +x; } >>"${LOGFILE}" 2>&1; 45 | 46 | # output processed input 47 | print_array "iQUERY" >"${OUTPUTFILE}" 48 | compare_sorted "${REFFILE}" "${OUTPUTFILE}" || exit 1 49 | 50 | printf "%s\n" "${SUCCESS}" 51 | 52 | cd "${DIRME}" || exit 1 53 | -------------------------------------------------------------------------------- /test/d-process_inline-test/d-process_inline-test.input: -------------------------------------------------------------------------------- 1 | ["ok"] true 2 | ["result",0,"update_id"] 1234567890 3 | ["result",0,"inline_query","id"] "987654321" 4 | ["result",0,"inline_query","query"] "message" 5 | ["result",0,"inline_query","from","id"] 123456789 6 | ["result",0,"inline_query","from","is_bot"] false 7 | ["result",0,"inline_query","from","first_name"] "Kay" 8 | ["result",0,"inline_query","from","last_name"] "M" 9 | ["result",0,"inline_query","from","username"] "Gnadelwartz" 10 | ["result",0,"inline_query","from","language_code"] "de" 11 | 12 | -------------------------------------------------------------------------------- /test/d-process_inline-test/d-process_inline-test.result: -------------------------------------------------------------------------------- 1 | iQUERY: 0 message 2 | iQUERY: FIRST_NAME Kay 3 | iQUERY: LAST_NAME M 4 | iQUERY: USER_ID 123456789 5 | iQUERY: USERNAME Gnadelwartz 6 | -------------------------------------------------------------------------------- /test/d-process_message-test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #=============================================================================== 3 | # 4 | # FILE: d-process_message-test.sh 5 | # 6 | # USAGE: must run only from dev/all-tests.sh 7 | # 8 | # DESCRIPTION: test receiving messages 9 | # 10 | # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ 11 | # AUTHOR: KayM (gnadelwartz), kay@rrr.de 12 | # 13 | #### $$VERSION$$ v1.52-1-g0dae2db 14 | #=============================================================================== 15 | 16 | # include common functions and definitions 17 | # shellcheck source=test/ALL-tests.inc.sh 18 | source "./ALL-tests.inc.sh" 19 | 20 | set -e 21 | 22 | # source bashbot.sh functionw 23 | cd "${TESTDIR}" || exit 1 24 | # shellcheck source=./bashbot.sh 25 | source "${TESTDIR}/bashbot.sh" source 26 | # shellcheck source=./bashbot.sh 27 | source "${TESTDIR}/commands.sh" source 28 | 29 | # overwrite get_file for test 30 | get_file() { 31 | printf "%s\n" "$1" 32 | } 33 | 34 | # get telegram input from file 35 | export UPDATE 36 | declare -Ax UPD 37 | 38 | # run process_message -------------- 39 | ARRAYS="USER CHAT REPLYTO FORWARD URLS CONTACT CAPTION LOCATION MESSAGE VENUE SERVICE NEWMEMBER LEFTMEMBER PINNED" 40 | 41 | printf "Check process_message ...\n" 42 | 43 | for testfile in ${INPUTFILELIST} 44 | do 45 | printf " ... %s\n" "${testfile##*/}" 46 | testref="${testfile%.input}.result" 47 | UPDATE="$(< "${testfile}")" 48 | Json2Array 'UPD' <"${testfile}" 49 | set -x 50 | { pre_process_message "0"; process_message "0"; set +x; } >>"${LOGFILE}" 2>&1; 51 | USER[ID]="123456789"; CHAT[ID]="123456789" 52 | 53 | # output processed input 54 | # shellcheck disable=SC2086 55 | print_array ${ARRAYS} >"${OUTPUTFILE}" 56 | compare_sorted "${testref}" "${OUTPUTFILE}" || exit 1 57 | printf "%s\n" "${SUCCESS}" 58 | 59 | done 60 | 61 | cd "${DIRME}" || exit 1 62 | -------------------------------------------------------------------------------- /test/d-process_message-test/d-process_message-test-left_chat_member.input: -------------------------------------------------------------------------------- 1 | ["ok"] true 2 | ["result",0,"update_id"] 123456789 3 | ["result",0,"message","message_id"] 123456789 4 | ["result",0,"message","from","id"] 123456789 5 | ["result",0,"message","from","is_bot"] false 6 | ["result",0,"message","from","first_name"] "Kay" 7 | ["result",0,"message","from","last_name"] "M" 8 | ["result",0,"message","from","username"] "Gnadelwartz" 9 | ["result",0,"message","from","language_code"] "de" 10 | ["result",0,"message","chat","id"] -123456789 11 | ["result",0,"message","chat","title"] "Testgruppe bot only test" 12 | ["result",0,"message","chat","type"] "group" 13 | ["result",0,"message","chat","all_members_are_administrators"] true 14 | ["result",0,"message","date"] 1592372719 15 | 16 | ["result",0,"message","left_chat_participant","id"] 123456789 17 | ["result",0,"message","left_chat_participant","is_bot"] false 18 | ["result",0,"message","left_chat_participant","first_name"] "Kay" 19 | ["result",0,"message","left_chat_participant","last_name"] "M" 20 | ["result",0,"message","left_chat_participant","username"] "Gnadelwartz" 21 | ["result",0,"message","left_chat_member","id"] 123456789 22 | ["result",0,"message","left_chat_member","is_bot"] false 23 | ["result",0,"message","left_chat_member","first_name"] "Kay" 24 | ["result",0,"message","left_chat_member","last_name"] "M" 25 | ["result",0,"message","left_chat_member","username"] "Gnadelwartz" 26 | -------------------------------------------------------------------------------- /test/d-process_message-test/d-process_message-test-left_chat_member.result: -------------------------------------------------------------------------------- 1 | USER: FIRST_NAME Kay 2 | USER: ID 123456789 3 | USER: LAST_NAME M 4 | USER: USERNAME Gnadelwartz 5 | CHAT: ALL_ADMIN true 6 | CHAT: FIRST_NAME 7 | CHAT: ID 123456789 8 | CHAT: LAST_NAME 9 | CHAT: TITLE Testgruppe bot only test 10 | CHAT: TYPE group 11 | CHAT: USERNAME 12 | CAPTION: 0 13 | LOCATION: LATITUDE 14 | LOCATION: LONGITUDE 15 | MESSAGE: 0 /_left_chat_member Kay M 16 | MESSAGE: CAPTION 17 | MESSAGE: DICE 18 | MESSAGE: ID 123456789 19 | SERVICE: 0 yes 20 | SERVICE: LEFTMEMBER 123456789 21 | LEFTMEMBER: FIRST_NAME Kay 22 | LEFTMEMBER: ID 23 | LEFTMEMBER: ISBOT false 24 | LEFTMEMBER: LAST_NAME M 25 | LEFTMEMBER: USERNAME Kay M 26 | -------------------------------------------------------------------------------- /test/d-process_message-test/d-process_message-test-mesage.result: -------------------------------------------------------------------------------- 1 | USER: FIRST_NAME Kay 2 | USER: ID 123456789 3 | USER: LAST_NAME M 4 | USER: USERNAME Gnadelwartz 5 | CHAT: ALL_ADMIN 6 | CHAT: FIRST_NAME Test 7 | CHAT: ID 123456789 8 | CHAT: LAST_NAME Bot 9 | CHAT: TITLE BotTestTitle 10 | CHAT: TYPE private 11 | CHAT: USERNAME BotTest 12 | REPLYTO: 0 Ich bin der Deal-O-Mat Bot. Für eine Liste der Befehle sende /help 13 | REPLYTO: FIRST_NAME dealzbot 14 | REPLYTO: ID 6542 15 | REPLYTO: LAST_NAME 16 | REPLYTO: UID 987654321 17 | REPLYTO: USERNAME Deal_O_Mat_bot 18 | FORWARD: FIRST_NAME Kay 19 | FORWARD: ID 6541 20 | FORWARD: LAST_NAME M 21 | FORWARD: UID 123456789 22 | FORWARD: USERNAME Gnadelwartz 23 | URLS: AUDIO audio-AgADAgADL6oxG-Gw4EndCWGl2WUfUo1pXw8ABOusSilDGzAYa 24 | URLS: DOCUMENT document-AgADAgADL6oxG-Gw4EndCWGl2WUfUo1pXw8ABOusSilDGzAYa 25 | URLS: PHOTO photo-AgADAgADL6oxG-Gw4EndCWGl2WUfUo1pXw8ABOusSilDGzAYa 26 | URLS: STICKER sticker-AgADAgADL6oxG-Gw4EndCWGl2WUfUo1pXw8ABOusSilDGzAYa 27 | URLS: VIDEO video-AgADAgADL6oxG-Gw4EndCWGl2WUfUo1pXw8ABOusSilDGzAYa 28 | URLS: VOICE voice-AgADAgADL6oxG-Gw4EndCWGl2WUfUo1pXw8ABOusSilDGzAYa 29 | CONTACT: FIRST_NAME ADAC 30 | CONTACT: LAST_NAME Pannenhilfe 31 | CONTACT: NUMBER 222222 32 | CONTACT: USER_ID 33 | CONTACT: VCARD BEGIN:VCARD\nVERSION:2.1\nN:Pannenhilfe;ADAC;;;\nFN:ADAC Pannenhilfe\nTEL;CELL;PREF:+49179222222\nTEL;X-Mobil:222222\nEND:VCARD 34 | CAPTION: 0 Myproteine kein spell check 35 | LOCATION: LATITUDE 49.631824 36 | LOCATION: LONGITUDE 8.377072 37 | MESSAGE: 0 😂😝👌☺❤😕😈#⃣🌏🎉🙊🙉☕🚀✈🚂💯✔〽🔚 38 | MESSAGE: ID 6541 39 | MESSAGE: CAPTION Myproteine kein spell check 40 | MESSAGE: DICE 41 | VENUE: ADDRESS Am Rhein 1 42 | VENUE: FOURSQUARE 4c4321afce54e21eee980d1a 43 | VENUE: LATITUDE 49.631824 44 | VENUE: LONGITUDE 8.377072 45 | VENUE: TITLE Kolb's Biergarten 46 | -------------------------------------------------------------------------------- /test/d-process_message-test/d-process_message-test-message.result: -------------------------------------------------------------------------------- 1 | USER: FIRST_NAME Kay 2 | USER: ID 123456789 3 | USER: LAST_NAME M 4 | USER: USERNAME Gnadelwartz 5 | CHAT: ALL_ADMIN 6 | CHAT: FIRST_NAME Test 7 | CHAT: ID 123456789 8 | CHAT: LAST_NAME Bot 9 | CHAT: TITLE BotTestTitle 10 | CHAT: TYPE private 11 | CHAT: USERNAME BotTest 12 | REPLYTO: 0 Ich bin der Deal-O-Mat Bot. Für eine Liste der Befehle sende /help 13 | REPLYTO: FIRST_NAME dealzbot 14 | REPLYTO: ID 6542 15 | REPLYTO: LAST_NAME 16 | REPLYTO: UID 987654321 17 | REPLYTO: USERNAME Deal_O_Mat_bot 18 | FORWARD: FIRST_NAME Kay 19 | FORWARD: ID 6541 20 | FORWARD: LAST_NAME M 21 | FORWARD: UID 123456789 22 | FORWARD: USERNAME Gnadelwartz 23 | URLS: AUDIO audio-AgADAgADL6oxG-Gw4EndCWGl2WUfUo1pXw8ABOusSilDGzAYa 24 | URLS: DOCUMENT document-AgADAgADL6oxG-Gw4EndCWGl2WUfUo1pXw8ABOusSilDGzAYa 25 | URLS: PHOTO photo-AgADAgADL6oxG-Gw4EndCWGl2WUfUo1pXw8ABOusSilDGzAYa 26 | URLS: STICKER sticker-AgADAgADL6oxG-Gw4EndCWGl2WUfUo1pXw8ABOusSilDGzAYa 27 | URLS: VIDEO video-AgADAgADL6oxG-Gw4EndCWGl2WUfUo1pXw8ABOusSilDGzAYa 28 | URLS: VOICE voice-AgADAgADL6oxG-Gw4EndCWGl2WUfUo1pXw8ABOusSilDGzAYa 29 | CONTACT: FIRST_NAME ADAC 30 | CONTACT: LAST_NAME Pannenhilfe 31 | CONTACT: NUMBER 222222 32 | CONTACT: USER_ID 33 | CONTACT: VCARD BEGIN:VCARD\nVERSION:2.1\nN:Pannenhilfe;ADAC;;;\nFN:ADAC Pannenhilfe\nTEL;CELL;PREF:+49179222222\nTEL;X-Mobil:222222\nEND:VCARD 34 | CAPTION: 0 Myproteine kein spell check 35 | LOCATION: LATITUDE 49.631824 36 | LOCATION: LONGITUDE 8.377072 37 | MESSAGE: 0 😂😝👌☺❤😕😈#⃣🌏🎉🙊🙉☕🚀✈🚂💯✔〽🔚 38 | MESSAGE: CAPTION Myproteine kein spell check 39 | MESSAGE: DICE 40 | MESSAGE: ID 6541 41 | VENUE: ADDRESS Am Rhein 1 42 | VENUE: FOURSQUARE 4c4321afce54e21eee980d1a 43 | VENUE: LATITUDE 49.631824 44 | VENUE: LONGITUDE 8.377072 45 | VENUE: TITLE Kolb's Biergarten 46 | -------------------------------------------------------------------------------- /test/d-process_message-test/d-process_message-test-new_chat_member.input: -------------------------------------------------------------------------------- 1 | ["ok"] true 2 | ["result",0,"update_id"] 123456789 3 | ["result",0,"message","message_id"] 123456789 4 | ["result",0,"message","from","id"] 123456789 5 | ["result",0,"message","from","is_bot"] false 6 | ["result",0,"message","from","first_name"] "Kay" 7 | ["result",0,"message","from","last_name"] "M" 8 | ["result",0,"message","from","username"] "Gnadelwartz" 9 | ["result",0,"message","from","language_code"] "de" 10 | ["result",0,"message","chat","id"] -123456789 11 | ["result",0,"message","chat","title"] "Testgruppe bot only test" 12 | ["result",0,"message","chat","type"] "group" 13 | ["result",0,"message","chat","all_members_are_administrators"] true 14 | ["result",0,"message","date"] 1592372719 15 | 16 | ["result",0,"message","new_chat_participant","id"] 123456789 17 | ["result",0,"message","new_chat_participant","is_bot"] false 18 | ["result",0,"message","new_chat_participant","first_name"] "Kay" 19 | ["result",0,"message","new_chat_participant","last_name"] "M" 20 | ["result",0,"message","new_chat_participant","username"] "Gnadelwartz" 21 | ["result",0,"message","new_chat_member","id"] 123456789 22 | ["result",0,"message","new_chat_member","is_bot"] false 23 | ["result",0,"message","new_chat_member","first_name"] "Kay" 24 | ["result",0,"message","new_chat_member","last_name"] "M" 25 | ["result",0,"message","new_chat_member","username"] "Gnadelwartz" 26 | -------------------------------------------------------------------------------- /test/d-process_message-test/d-process_message-test-new_chat_member.result: -------------------------------------------------------------------------------- 1 | USER: FIRST_NAME Kay 2 | USER: ID 123456789 3 | USER: LAST_NAME M 4 | USER: USERNAME Gnadelwartz 5 | CHAT: ALL_ADMIN true 6 | CHAT: FIRST_NAME 7 | CHAT: ID 123456789 8 | CHAT: LAST_NAME 9 | CHAT: TITLE Testgruppe bot only test 10 | CHAT: TYPE group 11 | CHAT: USERNAME 12 | CAPTION: 0 13 | LOCATION: LATITUDE 14 | LOCATION: LONGITUDE 15 | MESSAGE: 0 /_new_chat_member 123456789 Gnadelwartz 16 | MESSAGE: CAPTION 17 | MESSAGE: DICE 18 | MESSAGE: ID 123456789 19 | SERVICE: 0 yes 20 | SERVICE: NEWMEMBER 123456789 21 | SERVICE: NEWPHOTO 22 | SERVICE: NEWTITLE 23 | NEWMEMBER: FIRST_NAME Kay 24 | NEWMEMBER: ID 123456789 25 | NEWMEMBER: ISBOT false 26 | NEWMEMBER: LAST_NAME M 27 | NEWMEMBER: USERNAME Gnadelwartz 28 | -------------------------------------------------------------------------------- /test/d-process_message-test/d-process_message-test-new_chat_picture.input: -------------------------------------------------------------------------------- 1 | ["ok"] true 2 | ["result",0,"update_id"] 123456789 3 | ["result",0,"message","message_id"] 123456789 4 | ["result",0,"message","from","id"] 123456789 5 | ["result",0,"message","from","is_bot"] false 6 | ["result",0,"message","from","first_name"] "Kay" 7 | ["result",0,"message","from","last_name"] "M" 8 | ["result",0,"message","from","username"] "Gnadelwartz" 9 | ["result",0,"message","from","language_code"] "de" 10 | ["result",0,"message","chat","id"] -123456789 11 | ["result",0,"message","chat","title"] "Testgruppe bot only test" 12 | ["result",0,"message","chat","type"] "group" 13 | ["result",0,"message","chat","all_members_are_administrators"] true 14 | ["result",0,"message","date"] 1592372719 15 | 16 | ["result",0,"message","new_chat_photo",0,"file_id"] "AgACAgIAAxkBAAEBFute6a3vIpB99vim811hxeu2tyQWfwACrKwxG0TMUUtDBH10RqlzGCukupIuAAMBAAMCAANhAAM3SAMAARoE" 17 | ["result",0,"message","new_chat_photo",0,"file_unique_id"] "AQADK6S6ki4AAzdIAwAB" 18 | ["result",0,"message","new_chat_photo",0,"file_size"] 5939 19 | ["result",0,"message","new_chat_photo",0,"width"] 160 20 | ["result",0,"message","new_chat_photo",0,"height"] 160 21 | ["result",0,"message","new_chat_photo",1,"file_id"] "AgACAgIAAxkBAAEBFute6a3vIpB99vim811hxeu2tyQWfwACrKwxG0TMUUtDBH10RqlzGCukupIuAAMBAAMCAANiAAM4SAMAARoE" 22 | ["result",0,"message","new_chat_photo",1,"file_unique_id"] "AQADK6S6ki4AAzhIAwAB" 23 | ["result",0,"message","new_chat_photo",1,"file_size"] 14124 24 | ["result",0,"message","new_chat_photo",1,"width"] 320 25 | ["result",0,"message","new_chat_photo",1,"height"] 320 26 | ["result",0,"message","new_chat_photo",2,"file_id"] "AgACAgIAAxkBAAEBFute6a3vIpB99vim811hxeu2tyQWfwACrKwxG0TMUUtDBH10RqlzGCukupIuAAMBAAMCAANjAAM5SAMAARoE" 27 | ["result",0,"message","new_chat_photo",2,"file_unique_id"] "AQADK6S6ki4AAzlIAwAB" 28 | ["result",0,"message","new_chat_photo",2,"file_size"] 34052 29 | ["result",0,"message","new_chat_photo",2,"width"] 640 30 | ["result",0,"message","new_chat_photo",2,"height"] 640 31 | -------------------------------------------------------------------------------- /test/d-process_message-test/d-process_message-test-new_chat_picture.result: -------------------------------------------------------------------------------- 1 | USER: FIRST_NAME Kay 2 | USER: ID 123456789 3 | USER: LAST_NAME M 4 | USER: USERNAME Gnadelwartz 5 | CHAT: ALL_ADMIN true 6 | CHAT: FIRST_NAME 7 | CHAT: ID 123456789 8 | CHAT: LAST_NAME 9 | CHAT: TITLE Testgruppe bot only test 10 | CHAT: TYPE group 11 | CHAT: USERNAME 12 | CAPTION: 0 13 | LOCATION: LATITUDE 14 | LOCATION: LONGITUDE 15 | MESSAGE: 0 /_new_chat_photo 123456789 AgACAgIAAxkBAAEBFute6a3vIpB99vim811hxeu2tyQWfwACrKwxG0TMUUtDBH10RqlzGCukupIuAAMBAAMCAANhAAM3SAMAARoE 16 | MESSAGE: CAPTION 17 | MESSAGE: DICE 18 | MESSAGE: ID 123456789 19 | SERVICE: 0 yes 20 | SERVICE: NEWPHOTO AgACAgIAAxkBAAEBFute6a3vIpB99vim811hxeu2tyQWfwACrKwxG0TMUUtDBH10RqlzGCukupIuAAMBAAMCAANhAAM3SAMAARoE 21 | SERVICE: NEWTITLE 22 | -------------------------------------------------------------------------------- /test/d-process_message-test/d-process_message-test-new_chat_title.input: -------------------------------------------------------------------------------- 1 | ["ok"] true 2 | ["result",0,"update_id"] 123456789 3 | ["result",0,"message","message_id"] 123456789 4 | ["result",0,"message","from","id"] 123456789 5 | ["result",0,"message","from","is_bot"] false 6 | ["result",0,"message","from","first_name"] "Kay" 7 | ["result",0,"message","from","last_name"] "M" 8 | ["result",0,"message","from","username"] "Gnadelwartz" 9 | ["result",0,"message","from","language_code"] "de" 10 | ["result",0,"message","chat","id"] -123456789 11 | ["result",0,"message","chat","title"] "Testgruppe bot only test" 12 | ["result",0,"message","chat","type"] "group" 13 | ["result",0,"message","chat","all_members_are_administrators"] true 14 | ["result",0,"message","date"] 1592372719 15 | 16 | ["result",0,"message","new_chat_title"] "new Testgruppe bot only" 17 | -------------------------------------------------------------------------------- /test/d-process_message-test/d-process_message-test-new_chat_title.result: -------------------------------------------------------------------------------- 1 | USER: FIRST_NAME Kay 2 | USER: ID 123456789 3 | USER: LAST_NAME M 4 | USER: USERNAME Gnadelwartz 5 | CHAT: ALL_ADMIN true 6 | CHAT: FIRST_NAME 7 | CHAT: ID 123456789 8 | CHAT: LAST_NAME 9 | CHAT: TITLE Testgruppe bot only test 10 | CHAT: TYPE group 11 | CHAT: USERNAME 12 | CAPTION: 0 13 | LOCATION: LATITUDE 14 | LOCATION: LONGITUDE 15 | MESSAGE: 0 /_new_chat_title 123456789 new Testgruppe bot only 16 | MESSAGE: CAPTION 17 | MESSAGE: DICE 18 | MESSAGE: ID 123456789 19 | SERVICE: 0 yes 20 | SERVICE: NEWPHOTO 21 | SERVICE: NEWTITLE new Testgruppe bot only 22 | -------------------------------------------------------------------------------- /test/d-process_message-test/d-process_message-test-pinned_message.input: -------------------------------------------------------------------------------- 1 | ["ok"] true 2 | ["result",0,"update_id"] 123456789 3 | ["result",0,"message","message_id"] 123456789 4 | ["result",0,"message","from","id"] 123456789 5 | ["result",0,"message","from","is_bot"] false 6 | ["result",0,"message","from","first_name"] "Kay" 7 | ["result",0,"message","from","last_name"] "M" 8 | ["result",0,"message","from","username"] "Gnadelwartz" 9 | ["result",0,"message","from","language_code"] "de" 10 | ["result",0,"message","chat","id"] -123456789 11 | ["result",0,"message","chat","title"] "Testgruppe bot only test" 12 | ["result",0,"message","chat","type"] "group" 13 | ["result",0,"message","chat","all_members_are_administrators"] true 14 | ["result",0,"message","date"] 1592372719 15 | 16 | ["result",0,"message","pinned_message","message_id"] 3022 17 | ["result",0,"message","pinned_message","from","id"] 796814662 18 | ["result",0,"message","pinned_message","from","is_bot"] true 19 | ["result",0,"message","pinned_message","from","first_name"] "DealOMat" 20 | ["result",0,"message","pinned_message","from","username"] "Deal_O_Mat_bot" 21 | ["result",0,"message","pinned_message","chat","id"] -1001220313778 22 | ["result",0,"message","pinned_message","chat","title"] "Testgruppe bot only test" 23 | ["result",0,"message","pinned_message","chat","type"] "supergroup" 24 | ["result",0,"message","pinned_message","date"] 1593121152 25 | ["result",0,"message","pinned_message","text"] "new pinned Message" 26 | 27 | ["result",0,"message","new_chat_title"] "new Testgruppe bot only" 28 | -------------------------------------------------------------------------------- /test/d-process_message-test/d-process_message-test-pinned_message.result: -------------------------------------------------------------------------------- 1 | USER: FIRST_NAME Kay 2 | USER: ID 123456789 3 | USER: LAST_NAME M 4 | USER: USERNAME Gnadelwartz 5 | CHAT: ALL_ADMIN true 6 | CHAT: FIRST_NAME 7 | CHAT: ID 123456789 8 | CHAT: LAST_NAME 9 | CHAT: TITLE Testgruppe bot only test 10 | CHAT: TYPE group 11 | CHAT: USERNAME 12 | CAPTION: 0 13 | LOCATION: LATITUDE 14 | LOCATION: LONGITUDE 15 | MESSAGE: 0 /_new_pinned_message 123456789 3022 new pinned Message 16 | MESSAGE: CAPTION 17 | MESSAGE: DICE 18 | MESSAGE: ID 123456789 19 | SERVICE: 0 yes 20 | SERVICE: NEWPHOTO 21 | SERVICE: NEWTITLE new Testgruppe bot only 22 | SERVICE: PINNED 3022 23 | PINNED: ID 3022 24 | PINNED: MESSAGE new pinned Message 25 | -------------------------------------------------------------------------------- /test/d-send_message-test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #=============================================================================== 3 | # 4 | # FILE: d-send_message-test.sh 5 | # 6 | # USAGE: must run only from dev/all-tests.sh 7 | # 8 | # DESCRIPTION: test sending messages 9 | # 10 | # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ 11 | # AUTHOR: KayM (gnadelwartz), kay@rrr.de 12 | # 13 | #### $$VERSION$$ v1.52-1-g0dae2db 14 | #=============================================================================== 15 | 16 | # include common functions and definitions 17 | # shellcheck source=test/ALL-tests.inc.sh 18 | source "./ALL-tests.inc.sh" 19 | 20 | set -e 21 | set +f 22 | 23 | cd "${TESTDIR}" || exit 1 24 | 25 | # source bashbot.sh function, uncomment if you want to test functions 26 | # shellcheck source=./bashbot.sh 27 | source "${TESTDIR}/bashbot.sh" source 28 | # shellcheck source=./bashbot.sh 29 | source "${TESTDIR}/commands.sh" source 30 | 31 | _is_function send_message || printf "Send Message not found!\n" 32 | 33 | # start writing your tests here ... 34 | 35 | # over write sendJson to output parameter only 36 | sendEmpty() { 37 | printf 'chat:%s\tJSON:%s\nURL:%s\n\n' "$1" "$2" "$3" 38 | } 39 | 40 | sendJson() { 41 | printf 'chat:%s\tJSON:%s\nURL:%s\n\n' "$1" "$2" "$3" 42 | } 43 | sendUpload() { 44 | #JSON:"document":"/tmp/allowed/this_is_my.doc","caption":"Text plus absolute file will appear in chat"" 45 | printf 'chat:%s\tJSON:"%s":"%s","caption":"%s"\nURL:%s\n\n' "$1" "$2" "$3" "$5" "$4" 46 | } 47 | 48 | # send text input to send_message 49 | 50 | printf " Send line ..." 51 | 52 | # create dummy files for upload 53 | ALLOW='/tmp/allowed' 54 | FILE_REGEX="${ALLOW}/.*" 55 | [ -d "${ALLOW}" ] || mkdir "${ALLOW}" 56 | touch "${ALLOW}/this_is_my.gif" "${ALLOW}/this_is_my.doc" 57 | touch "${DATADIR}/this_is_my.gif" "${DATADIR}/this_is_my.doc" 58 | 59 | while read -r line ; do 60 | set -x; set +e 61 | send_message "123456" "${line}" >>"${OUTPUTFILE}" 62 | set +x; set -e 63 | printf "." 64 | done < "${INPUTFILE}" 2>>"${LOGFILE}" 65 | [ -d "${ALLOW}" ] && rm -rf "${ALLOW}" 66 | 67 | printf " done.\n" 68 | 69 | { compare_sorted "${REFFILE}" "${OUTPUTFILE}" || exit 1; } | cat -v 70 | rm -f "${REFFILE}.sort" 71 | 72 | printf " ... all \"send_message\" functions seems to work as expected.\n" 73 | 74 | printf "%s\n" "${SUCCESS}" 75 | 76 | 77 | -------------------------------------------------------------------------------- /test/d-send_message-test/d-send_message-test.input: -------------------------------------------------------------------------------- 1 | # test for text only output 2 | This is a normal text 3 | This is a normal text mynewlinestartshere with a line break 4 | html_parse_mode This is a HTML text 5 | html_parse_mode This is a HTML text mynewlinestartshere with a line break 6 | markdown_parse_mode This is a *MARKDOWN* text 7 | markdown_parse_mode This is a *MARKDOWN* text mynewlinestartshere with a line break 8 | 9 | # test for keyboard, file, venue output 10 | Text plus keyboard will appear in chat mykeyboardstartshere [ "Yep, sure" , "No, highly unlikely" ] 11 | Text plus location will appear in chat mylatstartshere la10 mylongstartshere lo20 12 | Text plus vuene will appear in chat mylatstartshere la10 mylongstartshere lo20 mytitlestartshere my home myaddressstartshere Diagon Alley N. 37 13 | 14 | # test for new inline button 15 | Text plus keyboard will appear in chat mybtextstartshere Button Text myburlstartshere https://www... 16 | STABILO 88/240 Fineliner point 88 mynewlinestartshere mynewlinestartshere [https://images-na.ssl-images-amazon.com/images/I/41oypA3kmHL.l_SX300.jpg] mynewlinestartshere mybtextstartshere Bei Amazon ansehen ... myburlstartshere https://www.amazon.de/dp/B014TN3JYW mytextstartshere second part of text mynewlinestartshere plus newline. 17 | 18 | # test for sendfile 19 | Text plus absolute file will appear in chat myfilelocationstartshere /tmp/allowed/this_is_my.gif 20 | Text plus absolute file will appear in chat myfilelocationstartshere /tmp/allowed/this_is_my.doc 21 | Text plus relative file will appear in chat myfilelocationstartshere this_is_my.gif 22 | Text plus relative file will appear in chat myfilelocationstartshere this_is_my.doc 23 | THIS IS OUTSIDE allowed myfilelocationstartshere /home/user/NOTallowed/this_is_my.dif 24 | THIS DOES NOT EXIST myfilelocationstartshere /tmp/allowed/this_does_not_exist.gif 25 | THIS DOES NOT EXIST myfilelocationstartshere this_does_not_exist.gif 26 | 27 | -------------------------------------------------------------------------------- /test/d-send_message-test/d-send_message-test.result: -------------------------------------------------------------------------------- 1 | chat:123456 JSON:"text":"\# test for text only output" 2 | URL:https://my-json-server.typicode.com/topkecleon/telegram-bot-bash/getMe?123456789:BASHBOTTESTSCRIPTbashbottestscript_/sendMessage 3 | 4 | chat:123456 JSON:"text":"This is a normal text" 5 | URL:https://my-json-server.typicode.com/topkecleon/telegram-bot-bash/getMe?123456789:BASHBOTTESTSCRIPTbashbottestscript_/sendMessage 6 | 7 | chat:123456 JSON:"text":"This is a normal text\nwith a line break" 8 | URL:https://my-json-server.typicode.com/topkecleon/telegram-bot-bash/getMe?123456789:BASHBOTTESTSCRIPTbashbottestscript_/sendMessage 9 | 10 | chat:123456 JSON:"text":" This is a HTML<\/b> text","parse_mode":"html" 11 | URL:https://my-json-server.typicode.com/topkecleon/telegram-bot-bash/getMe?123456789:BASHBOTTESTSCRIPTbashbottestscript_/sendMessage 12 | 13 | chat:123456 JSON:"text":" This is a HTML<\/b> text\nwith a line break","parse_mode":"html" 14 | URL:https://my-json-server.typicode.com/topkecleon/telegram-bot-bash/getMe?123456789:BASHBOTTESTSCRIPTbashbottestscript_/sendMessage 15 | 16 | chat:123456 JSON:"text":" This is a \*MARKDOWN\* text","parse_mode":"markdown" 17 | URL:https://my-json-server.typicode.com/topkecleon/telegram-bot-bash/getMe?123456789:BASHBOTTESTSCRIPTbashbottestscript_/sendMessage 18 | 19 | chat:123456 JSON:"text":" This is a \*MARKDOWN\* text\nwith a line break","parse_mode":"markdown" 20 | URL:https://my-json-server.typicode.com/topkecleon/telegram-bot-bash/getMe?123456789:BASHBOTTESTSCRIPTbashbottestscript_/sendMessage 21 | 22 | chat:123456 JSON:"text":"\# test for keyboard\, file\, venue output" 23 | URL:https://my-json-server.typicode.com/topkecleon/telegram-bot-bash/getMe?123456789:BASHBOTTESTSCRIPTbashbottestscript_/sendMessage 24 | 25 | chat:123456 JSON:"text":"Text plus keyboard will appear in chat", "reply_markup": {"keyboard": [ [ "Yep, sure" , "No, highly unlikely" ] ] , "one_time_keyboard":true} 26 | URL:https://my-json-server.typicode.com/topkecleon/telegram-bot-bash/getMe?123456789:BASHBOTTESTSCRIPTbashbottestscript_/sendMessage 27 | 28 | chat:123456 JSON:"latitude": la10, "longitude": lo20 29 | URL:https://my-json-server.typicode.com/topkecleon/telegram-bot-bash/getMe?123456789:BASHBOTTESTSCRIPTbashbottestscript_/sendLocation 30 | 31 | chat:123456 JSON:"latitude": la10, "longitude": lo20, "address": "Diagon Alley N. 37", "title": "my home" 32 | URL:https://my-json-server.typicode.com/topkecleon/telegram-bot-bash/getMe?123456789:BASHBOTTESTSCRIPTbashbottestscript_/sendVenue 33 | 34 | chat:123456 JSON:"text":"\# test for new inline button" 35 | URL:https://my-json-server.typicode.com/topkecleon/telegram-bot-bash/getMe?123456789:BASHBOTTESTSCRIPTbashbottestscript_/sendMessage 36 | 37 | chat:123456 JSON:"text":"Text plus keyboard will appear in chat", "reply_markup": {"inline_keyboard": [ [{"text":"Button Text", "url":"https://www..."}] ]} 38 | URL:https://my-json-server.typicode.com/topkecleon/telegram-bot-bash/getMe?123456789:BASHBOTTESTSCRIPTbashbottestscript_/sendMessage 39 | 40 | chat:123456 JSON:"text":"STABILO 88\/240 Fineliner point 88\n\n[https:\/\/images\-na\.ssl\-images\-amazon\.com\/images\/I\/41oypA3kmHL\.l_SX300\.jpg]\nsecond part of text\nplus newline\.", "reply_markup": {"inline_keyboard": [ [{"text":"Bei Amazon ansehen \.\.\.", "url":"https://www.amazon.de/dp/B014TN3JYW"}] ]} 41 | URL:https://my-json-server.typicode.com/topkecleon/telegram-bot-bash/getMe?123456789:BASHBOTTESTSCRIPTbashbottestscript_/sendMessage 42 | 43 | chat:123456 JSON:"text":"\# test for sendfile" 44 | URL:https://my-json-server.typicode.com/topkecleon/telegram-bot-bash/getMe?123456789:BASHBOTTESTSCRIPTbashbottestscript_/sendMessage 45 | 46 | chat:123456 JSON:"photo":"/tmp/allowed/this_is_my.gif","caption":"Text plus absolute file will appear in chat" 47 | URL:https://my-json-server.typicode.com/topkecleon/telegram-bot-bash/getMe?123456789:BASHBOTTESTSCRIPTbashbottestscript_/sendPhoto 48 | 49 | chat:123456 JSON:"action": "upload_photo" 50 | URL:https://my-json-server.typicode.com/topkecleon/telegram-bot-bash/getMe?123456789:BASHBOTTESTSCRIPTbashbottestscript_/sendChatAction 51 | 52 | chat:123456 JSON:"document":"/tmp/allowed/this_is_my.doc","caption":"Text plus absolute file will appear in chat" 53 | URL:https://my-json-server.typicode.com/topkecleon/telegram-bot-bash/getMe?123456789:BASHBOTTESTSCRIPTbashbottestscript_/sendDocument 54 | 55 | chat:123456 JSON:"action": "upload_document" 56 | URL:https://my-json-server.typicode.com/topkecleon/telegram-bot-bash/getMe?123456789:BASHBOTTESTSCRIPTbashbottestscript_/sendChatAction 57 | 58 | -------------------------------------------------------------------------------- /test/d-user_is-test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #=============================================================================== 3 | # 4 | # FILE: d-user_is-test.sh 5 | # 6 | # USAGE: must run only from dev/all-tests.sh 7 | # 8 | # DESCRIPTION: test user ACLs 9 | # 10 | # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ 11 | # AUTHOR: KayM (gnadelwartz), kay@rrr.de 12 | # 13 | #### $$VERSION$$ v1.52-1-g0dae2db 14 | #=============================================================================== 15 | 16 | # include common functions and definitions 17 | # shellcheck source=test/ALL-tests.inc.sh 18 | source "./ALL-tests.inc.sh" 19 | 20 | set -e 21 | set +f 22 | 23 | cd "${TESTDIR}" || exit 1 24 | 25 | # reset BOTADMIN 26 | printf '["botadmin"] "?"\n' >>"${ADMINFILE}" # auto mode 27 | 28 | # source bashbot.sh function, uncomment if you want to test functions 29 | # shellcheck source=./bashbot.sh 30 | source "${TESTDIR}/bashbot.sh" source 31 | # shellcheck source=./bashbot.sh 32 | source "${TESTDIR}/commands.sh" source 33 | 34 | # start writing your tests here ... 35 | 36 | # first user asking for botadmin will botadmin 37 | printf "Check \"user_is_botadmin\" ...\n" 38 | 39 | printf "BOTADMIN ...\n" 40 | user_is_botadmin "BOTADMIN" || exit 1 # should never fail 41 | printf "NOBOTADMIN ...\n" 42 | user_is_botadmin "NOBOTADMIN" && exit 1 # should fail 43 | printf "BOTADMIN ...\n" 44 | user_is_botadmin "BOTADMIN" || exit 1 # same name as first one, should work 45 | 46 | printf "Check config file ...\n" 47 | if [ "$(getConfigKey "botadmin")" = "BOTADMIN" ]; then 48 | printf " ... \"user_is_botadmin\" seems to work as expected.\n" 49 | else 50 | exit 1 51 | fi 52 | printf "%s\n" "${SUCCESS}" 53 | 54 | # lets see If UAC works ... 55 | printf "Check \"user_is_allowed\" ...\n" 56 | 57 | printf " ... with not rules\n" 58 | user_is_allowed "NOBOTADMIN" "ANYTHING" && exit 1 # should always fail because no rules exist 59 | user_is_allowed "BOTADMIN" "ANYTHING" && exit 1 # should fail even is BOTADMIN 60 | printf "%s\n" "${SUCCESS}" 61 | 62 | printf " ... with BOTADMIN:*:*\n" 63 | printf 'BOTADMIN:*:*\n' >"${ACLFILE}" # RULE allow BOTADMIN everything 64 | 65 | user_is_allowed "BOTADMIN" "ANYTHING" || exit 1 # should work now 66 | user_is_allowed "NOBOTADMIN" "ANYTHING" && exit 1 # should fail because user is not listed 67 | printf "%s\n" "${SUCCESS}" 68 | 69 | printf " ... with NOBOTAMIN:SOMETHING:*\n" 70 | printf 'NOBOTADMIN:SOMETHING:*\n' >>"${ACLFILE}" # RULE allow NOBOTADMIN something 71 | 72 | user_is_allowed "BOTADMIN" "ANYTHING" || exit 1 # should work 73 | user_is_allowed "BOTADMIN" "SOMETHING" || exit 1 # should work 74 | user_is_allowed "NOBOTADMIN" "SOMETHING" || exit 1 # should work now 75 | user_is_allowed "NOBOTADMIN" "ANYTHING" && exit 1 # should fail because only SOMETHING is listed 76 | 77 | printf "%s\n" "${SUCCESS}" 78 | 79 | printf " ... \"user_is_allowed\" seems to work as expected.\n" 80 | 81 | -------------------------------------------------------------------------------- /test/e-env-test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #=============================================================================== 3 | # 4 | # FILE: e-env-test.sh 5 | # 6 | # USAGE: must run only from dev/all-tests.sh 7 | # 8 | # DESCRIPTION: test BASHBOT_xxx variables working as expected 9 | # 10 | # LICENSE: WTFPLv2 http://www.wtfpl.net/txt/copying/ 11 | # AUTHOR: KayM (gnadelwartz), kay@rrr.de 12 | # 13 | #### $$VERSION$$ v1.52-1-g0dae2db 14 | #=============================================================================== 15 | 16 | # include common functions and definitions 17 | # shellcheck source=test/ALL-tests.inc.sh 18 | source "./ALL-tests.inc.sh" 19 | 20 | set -e 21 | 22 | #cd "${TESTDIR}" || exit 1 23 | 24 | # source bashbot.sh function, uncomment if you want to test functions 25 | # shellcheck source=./bashbot.sh 26 | # source "\/bashbot.sh" source 27 | 28 | # start writing your tests here ... 29 | # test setting of env variables to different locations 30 | 31 | export BASHBOT_ETC="${TESTDIR}/env/etc/bashbot" 32 | export BASHBOT_VAR="${TESTDIR}/env/var/bashbot" 33 | export BASHBOT_JSONSH="${TESTDIR}/env/local/bin/JSON.sh" 34 | BASHBOT_BIN="${TESTDIR}/env/local/bin" 35 | 36 | # create dirs 37 | mkdir -p "${BASHBOT_ETC}" || exit 1 38 | mkdir -p "${BASHBOT_VAR}" || exit 1 39 | mkdir -p "${BASHBOT_BIN}" || exit 1 40 | 41 | # cp bashbot files to new locations 42 | set +f 43 | # shellcheck disable=SC2086 44 | cp ${TESTDIR}/*commands.sh "${BASHBOT_ETC}" || exit 1 45 | set -f 46 | cp -r "${TESTDIR}/bashbot.sh" "${TESTDIR}/modules" "${TESTDIR}/JSON.sh/JSON.sh" "${BASHBOT_BIN}" || exit 1 47 | 48 | TESTFILES="${TOKENFILE} ${ACLFILE}" 49 | 50 | 51 | printf "Check first run in ENVIRONMENT ...\n" 52 | mkdir "${BASHBOT_VAR}/${DATADIR}" 53 | 54 | # run bashbot first time with init 55 | "${BASHBOT_BIN}/bashbot.sh" init >"${LOGFILE}" <>"${LOGFILE}" 85 | if ! diff -q "${BASHBOT_ETC}/${file}" "${REFDIR}/${file}" >>"${LOGFILE}"; then printf "%s\n" "${NOSUCCESS} Fail diff ${file}!"; FAIL="1"; fi 86 | 87 | done 88 | 89 | printf " ... BASHBOT_ETC seems to work!\n" 90 | printf "%s\n" "${SUCCESS}" 91 | -------------------------------------------------------------------------------- /test/e-env-test/blocked.jssh: -------------------------------------------------------------------------------- 1 | ["blocked_user_or_chat_id"] "name and reason" 2 | -------------------------------------------------------------------------------- /test/e-env-test/botacl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/e-env-test/botconfig.jssh: -------------------------------------------------------------------------------- 1 | ["bot_config_key"] "config_key_value" 2 | ["bottoken"] "123456789:BASHBOTTESTSCRIPTbashbottestscript_" 3 | ["botadmin"] "?" 4 | -------------------------------------------------------------------------------- /test/e-env-test/count.jssh: -------------------------------------------------------------------------------- 1 | ["counted_user_chat_id"] "num_messages_seen" 2 | --------------------------------------------------------------------------------