diff --git a/bashbot.sh b/bashbot.sh index 8c5040d..c6f674e 100755 --- a/bashbot.sh +++ b/bashbot.sh @@ -12,7 +12,7 @@ # This file is public domain in the USA and all free countries. # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) # -#### $$VERSION$$ v0.80-dev2-4-gb7df57a +#### $$VERSION$$ v0.80-dev2-6-g5b10e75 # # Exit Codes: # - 0 sucess (hopefully) @@ -122,30 +122,14 @@ fi BOTTOKEN="$(cat "${TOKENFILE}")" URL='https://api.telegram.org/bot'$BOTTOKEN -MSG_URL=$URL'/sendMessage' -LEAVE_URL=$URL'/leaveChat' -KICK_URL=$URL'/kickChatMember' -UNBAN_URL=$URL'/unbanChatMember' -PHO_URL=$URL'/sendPhoto' -AUDIO_URL=$URL'/sendAudio' -DOCUMENT_URL=$URL'/sendDocument' -STICKER_URL=$URL'/sendSticker' -VIDEO_URL=$URL'/sendVideo' -VOICE_URL=$URL'/sendVoice' -LOCATION_URL=$URL'/sendLocation' -VENUE_URL=$URL'/sendVenue' -ACTION_URL=$URL'/sendChatAction' -FORWARD_URL=$URL'/forwardMessage' ME_URL=$URL'/getMe' -DELETE_URL=$URL'/deleteMessage' -GETMEMBER_URL=$URL'/getChatMember' UPD_URL=$URL'/getUpdates?offset=' GETFILE_URL=$URL'/getFile' unset USER declare -A BOTSENT USER MESSAGE URLS CONTACT LOCATION CHAT FORWARD REPLYTO VENUE iQUERY -export BOTSENT USER MESSAGE URLS CONTACT LOCATION CHAT FORWARD REPLYTO VENUE iQUERY +export res BOTSENT USER MESSAGE URLS CONTACT LOCATION CHAT FORWARD REPLYTO VENUE iQUERY COMMANDS="${BASHBOT_ETC:-.}/commands.sh" if [ "$1" != "source" ]; then @@ -160,116 +144,11 @@ if [ "$1" != "source" ]; then fi -send_normal_message() { - local text="${2}" - until [ -z "${text}" ]; do - sendJson "${1}" '"text":"'"${text:0:4096}"'"' "${MSG_URL}" - text="${text:4096}" - done -} - -send_markdown_message() { - local text="${2}" - until [ -z "${text}" ]; do - sendJson "${1}" '"text":"'"${text:0:4096}"'","parse_mode":"markdown"' "${MSG_URL}" - text="${text:4096}" - done -} - -send_html_message() { - local text="${2}" - until [ -z "${text}" ]; do - sendJson "${1}" '"text":"'"${text:0:4096}"'","parse_mode":"html"' "${MSG_URL}" - text="${text:4096}" - done -} - +DELETE_URL=$URL'/deleteMessage' delete_message() { sendJson "${1}" 'message_id: '"${2}"'' "${DELETE_URL}" } -# usage: status="$(get_chat_member_status "chat" "user")" -get_chat_member_status() { - sendJson "$1" 'user_id: '"$2"'' "$GETMEMBER_URL" - JsonGetString '"result","status"' <<< "$res" -} - -kick_chat_member() { - sendJson "$1" 'user_id: '"$2"'' "$KICK_URL" -} - -unban_chat_member() { - sendJson "$1" 'user_id: '"$2"'' "$UNBAN_URL" -} - -leave_chat() { - sendJson "$1" "" "$LEAVE_URL" -} - -user_is_creator() { - if [ "${1:--}" = "${2:-+}" ] || [ "$(get_chat_member_status "$1" "$2")" = "creator" ]; then return 0; fi - return 1 -} - -user_is_admin() { - local me; me="$(get_chat_member_status "$1" "$2")" - if [ "${me}" = "creator" ] || [ "${me}" = "administrator" ]; then return 0; fi - return 1 -} - -user_is_botadmin() { - local admin; admin="$(head -n 1 "${BOTADMIN}")" - [ "${admin}" = "${1}" ] && return 0 - [[ "${admin}" = "@*" ]] && [[ "${admin}" = "${2}" ]] && return 0 - if [ "${admin}" = "?" ]; then echo "${1:-?}" >"${BOTADMIN}"; return 0; fi - return 1 -} - -user_is_allowed() { - local acl="$1" - [ "$1" = "" ] && return 1 - grep -F -xq "${acl}:*:*" <"${BOTACL}" && return 0 - [ "$2" != "" ] && acl="${acl}:$2" - grep -F -xq "${acl}:*" <"${BOTACL}" && return 0 - [ "$3" != "" ] && acl="${acl}:$3" - grep -F -xq "${acl}" <"${BOTACL}" -} - -old_send_keyboard() { - local text='"text":"'"${2}"'"' - shift 2 - local keyboard=init - OLDIFS=$IFS - IFS=$(echo -en "\"") - for f in "$@" ;do [ "$f" != " " ] && keyboard="$keyboard, [\"$f\"]";done - IFS=$OLDIFS - keyboard=${keyboard/init, /} - sendJson "${1}" "${text}"', "reply_markup": {"keyboard": [ '"${keyboard}"' ],"one_time_keyboard": true}' "$MSG_URL" -} - -ISEMPTY="ThisTextIsEmptyAndWillBeDeleted" -send_keyboard() { - if [[ "$3" != *'['* ]]; then old_send_keyboard "$@"; return; fi - local text='"text":"'"${2}"'"'; [ "${2}" = "" ] && text='"text":"'"${ISEMPTY}"'"' - local one_time=', "one_time_keyboard":true' && [ "$4" != "" ] && one_time="" - sendJson "${1}" "${text}"', "reply_markup": {"keyboard": [ '"${3}"' ] '"${one_time}"'}' "$MSG_URL" - # '"text":"$2", "reply_markup": {"keyboard": [ ${3} ], "one_time_keyboard": true}' -} - -remove_keyboard() { - local text='"text":"'"${2}"'"'; [ "${2}" = "" ] && text='"text":"'"${ISEMPTY}"'"' - sendJson "${1}" "${text}"', "reply_markup": {"remove_keyboard":true}' "$MSG_URL" - #JSON='"text":"$2", "reply_markup": {"remove_keyboard":true}' -} -send_inline_keyboard() { - local text='"text":"'"${2}"'"'; [ "${2}" = "" ] && text='"text":"'"${ISEMPTY}"'"' - sendJson "${1}" "${text}"', "reply_markup": {"inline_keyboard": [ '"${3}"' ]}' "$MSG_URL" - # JSON='"text":"$2", "reply_markup": {"inline_keyboard": [ $3->[{"text":"text", "url":"url"}]<- ]}' -} -send_button() { - send_inline_keyboard "${1}" "${2}" '[ {"text":"'"${3}"'", "url":"'"${4}"'"}]' -} - # usage: sendJson "chat" "JSON" "URL" sendJson(){ local chat=""; @@ -278,7 +157,6 @@ sendJson(){ -H "Content-Type: application/json" | "${JSONSHFILE}" -s -b -n )" BOTSENT[OK]="$(JsonGetLine '"ok"' <<< "$res")" BOTSENT[ID]="$(JsonGetValue '"result","message_id"' <<< "$res")" - [[ "${2}" = *"${ISEMPTY}"* ]] && delete_message "${1}" "${BOTSENT[ID]}" } # convert common telegram entities to JSON @@ -300,82 +178,6 @@ get_file() { echo "${URL}/$(echo "${res}" | jsonGetString '"result","file_path"')" } -send_file() { - [ "$2" = "" ] && return - local CAPTION - local chat_id=$1 - local file=$2 - echo "$file" | grep -qE "$FILE_REGEX" || return - local ext="${file##*.}" - case $ext in - mp3|flac) - CUR_URL=$AUDIO_URL - WHAT=audio - STATUS=upload_audio - CAPTION="$3" - ;; - png|jpg|jpeg|gif) - CUR_URL=$PHO_URL - WHAT=photo - STATUS=upload_photo - CAPTION="$3" - ;; - webp) - CUR_URL=$STICKER_URL - WHAT=sticker - STATUS= - ;; - mp4) - CUR_URL=$VIDEO_URL - WHAT=video - STATUS=upload_video - CAPTION="$3" - ;; - - ogg) - CUR_URL=$VOICE_URL - WHAT=voice - STATUS= - ;; - *) - CUR_URL=$DOCUMENT_URL - WHAT=document - STATUS=upload_document - CAPTION="$3" - ;; - esac - send_action "$chat_id" "$STATUS" - res="$(curl -s "$CUR_URL" -F "chat_id=$chat_id" -F "$WHAT=@$file" -F "caption=$CAPTION")" -} - -# typing for text messages, upload_photo for photos, record_video or upload_video for videos, record_audio or upload_audio for audio files, upload_document for general files, find_location for location - -send_action() { - [ "$2" = "" ] && return - sendJson "${1}" '"action": "'"${2}"'"' "$ACTION_URL" -} - -send_location() { - [ "$3" = "" ] && return - sendJson "${1}" '"latitude": '"${2}"', "longitude": '"${3}"'' "$LOCATION_URL" -} - -send_venue() { - local add="" - [ "$5" = "" ] && return - [ "$6" != "" ] && add=', "foursquare_id": '"$6"'' - sendJson "${1}" '"latitude": '"${2}"', "longitude": '"${3}"', "address": "'"${5}"'", "title": "'"${4}"'"'"${add}" "$VENUE_URL" -} - - -forward_message() { - [ "$3" = "" ] && return - sendJson "${1}" '"from_chat_id": '"${2}"', "message_id": '"${3}"'' "$FORWARD_URL" -} -forward() { # backward compatibility - forward_message "$@" || return -} - # returns true if function exist _is_function() { @@ -398,7 +200,9 @@ process_client() { fi # Tmux copname="$ME"_"${CHAT[ID]}" - source commands.sh + # shellcheck source=./commands.sh + source "${COMMANDS}" "$1" + tmpcount="COUNT${CHAT[ID]}" grep -q "$tmpcount" <"${COUNTFILE}" >/dev/null 2>&1 || echo "$tmpcount">>"${COUNTFILE}" # To get user count execute bash bashbot.sh count diff --git a/commands.sh b/commands.sh index be5fe65..e86ad8f 100644 --- a/commands.sh +++ b/commands.sh @@ -5,10 +5,8 @@ # This file is public domain in the USA and all free countries. # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) # -#### $$VERSION$$ v0.80-dev2-4-gb7df57a +#### $$VERSION$$ v0.80-dev2-6-g5b10e75 # -# shellcheck disable=SC2154 -# shellcheck disable=SC2034 # adjust your language setting here, e.g.when run from other user or cron. # https://github.com/topkecleon/telegram-bot-bash#setting-up-your-environment @@ -38,43 +36,50 @@ Written by Drew (@topkecleon), Daniil Gentili (@danogentili) and KayM(@gnadelwar Get the code in my [GitHub](http://github.com/topkecleon/telegram-bot-bash) ' -if [ "${1}" != "source" ]; then - # shellcheck source=./modules/aliases.sh - [ -r "${MODULEDIR:-.}/aliases.sh" ] && source "${MODULEDIR:-.}/aliases.sh" - # shellcheck source=./modules/background.sh - [ -r "${MODULEDIR:-.}/background.sh" ] && source "${MODULEDIR:-.}/background.sh" - # shellcheck source=./modules/background.sh - [ -r "${MODULEDIR:-.}/inline.sh" ] && source "${MODULEDIR:-.}/inline.sh" -else - # defaults to no inline and nonsense home dir - INLINE="0" - FILE_REGEX='/home/user/allowed/.*' +# load modues on startup and always on on debug +if [ "${1}" = "source" ] || [[ "${1}" = *"debug"* ]] ; then + # load all readable modules + for modules in ${MODULEDIR:-.}/*.sh ; do + # shellcheck source=./modules/aliases.sh + [ -r "${modules}" ] && source "${modules}" "${1}" + done fi +# defaults to no inline and nonsense home dir +export INLINE="0" +export FILE_REGEX='/home/user/allowed/.*' + + # load mycommands # shellcheck source=./commands.sh [ -r "${BASHBOT_ETC:-.}/mycommands.sh" ] && source "${BASHBOT_ETC:-.}/mycommands.sh" "${1}" if [ "${1}" != "source" ];then + # this was here from beginning, can some tell me what this is for? + # I GUESS it was used to auto send files and locations?? + # this will be removed!!! if ! tmux ls 2>/dev/null | grep -v send | grep -q "$copname"; then - # interactive running? [ ! -z "${URLS[*]}" ] && { curl -s "${URLS[*]}" -o "$NAME" send_file "${CHAT[ID]}" "$NAME" "$CAPTION" rm -f "$NAME" } [ ! -z "${LOCATION[*]}" ] && send_location "${CHAT[ID]}" "${LOCATION[LATITUDE]}" "${LOCATION[LONGITUDE]}" - fi + # detect inline commands.... + # no default commands, all processing is done in myinlines() if [ "$INLINE" != "0" ] && [ "${iQUERY[ID]}" != "" ]; then if _is_function process_inline; then # forward iinline query to optional dispatcher _is_function myinlines && myinlines fi + + # regular (gobal) commands ... + # your commands are in mycommands() else - + case "${MESSAGE}" in ################################################ # GLOBAL commands start here, edit messages only diff --git a/modules/answerInline.sh b/modules/answerInline.sh new file mode 100644 index 0000000..5ad0edc --- /dev/null +++ b/modules/answerInline.sh @@ -0,0 +1,102 @@ +#!/bin/bash +# file: modules/inline.sh +# do not edit, this file will be overwritten on update + +# This file is public domain in the USA and all free countries. +# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) +# +#### $$VERSION$$ v0.80-dev2-4-gb7df57a + +# source from commands.sh to use the inline functions + +INLINE_QUERY=$URL'/answerInlineQuery' + +answer_inline_query() { + answer_inline_multi "${1}" "$(shift; inline_query_compose "$RANDOM" "$@")" +} +answer_inline_multi() { + sendJson "" '"inline_query_id": '"${1}"', "results": ['"${2}"']' "${INLINE_QUERY}" +} + +# $1 unique ID for answer +# $2 type of answer +# remaining arguments are the "must have" arguments in the order as in telegram doc +# followed by the optional arguments: https://core.telegram.org/bots/api#inlinequeryresult +inline_query_compose(){ + local JSON="{}" + local ID="${1}" + local fours last + # title2Json title caption description markup inlinekeyboard + case "${2}" in + # user provided media + "article"|"message") # article ID title message (markup decription) + JSON='{"type":"article","id":"'$ID'","input_message_content": {"message_text":"'$4'"} '$(title2Json "$3" "" "$5" "$6")'}' + ;; + "photo") # photo ID photoURL (thumbURL title description caption) + [ "$4" = "" ] && tumb="$3" + JSON='{"type":"photo","id":"'$ID'","photo_url":"'$3'","thumb_url":"'$4${tumb}'"'$(title2Json "$5" "$7" "$6")'}' + ;; + "gif") # gif ID photoURL (thumbURL title caption) + [ "$4" = "" ] && tumb="$3" + JSON='{"type":"gif","id":"'$ID'","gif_url":"'$3'", "thumb_url":"'$4${tumb}'"'$(title2Json "$5" "$6")'}' + ;; + "mpeg4_gif") # mpeg4_gif ID mpegURL (thumbURL title caption) + [ "$4" != "" ] && tumb='","thumb_url":"'$4'"' + JSON='{"type":"mpeg4_gif","id":"'$ID'","mpeg4_url":"'$3'"'${tumb}$(title2Json "$5" "$6")'}' + ;; + "video") # video ID videoURL mime thumbURL title (caption) + JSON='{"type":"video","id":"'$ID'","video_url":"'$3'","mime_type":"'$4'","thumb_url":"'$5'"'$(title2Json "$6" "$7")'}' + ;; + "audio") # audio ID audioURL title (caption) + JSON='{"type":"audio","id":"'$ID'","audio_url":"'$3'"'$(title2Json "$4" "$5")'}' + ;; + "voice") # voice ID voiceURL title (caption) + JSON='{"type":"voice","id":"'$ID'","voice_url":"'$3'"'$(title2Json "$4" "$5")'}' + ;; + "document") # document ID title documentURL mimetype (caption description) + JSON='{"type":"document","id":"'$ID'","document_url":"'$4'","mime_type":"'$5'"'$(title2Json "$3" "$6" "$7")'}' + ;; + "location") # location ID lat long title + JSON='{"type":"location","id":"'$ID'","latitude":"'$3'","longitude":"'$4'","title":"'$5'"}' + ;; + "venue") # venue ID lat long title (adress forsquare) + [ "$6" = "" ] && addr="$5" + [ "$7" != "" ] && fours=',"foursquare_id":"'$7'"' + JSON='{"type":"venue","id":"'$ID'","latitude":"'$3'","longitude":"'$4'","title":"'$5'","address":"'$6${addr}'"'${fours}'}' + ;; + "contact") # contact ID phone first (last thumb) + [ "$5" != "" ] && last=',"last_name":"'$5'"' + [ "$6" != "" ] && tumb='","thumb_url":"'$6'"' + JSON='{"type":"contact","id":"'$ID'","phone_number":"'$3'","first_name":"'$4'"'${last}'"}' + ;; + # title2Json title caption description markup inlinekeyboard + # Cached media stored in Telegram server + "cached_photo") # photo ID file (title description caption) + JSON='{"type":"photo","id":"'$ID'","photo_file_id":"'$3'"'$(title2Json "$4" "$6" "$5")'}' + ;; + "cached_gif") # gif ID file (title caption) + JSON='{"type":"gif","id":"'$ID'","gif_file_id":"'$3'"'$(title2Json "$4" "$5")'}' + ;; + "cached_mpeg4_gif") # mpeg ID file (title caption) + JSON='{"type":"mpeg4_gif","id":"'$ID'","mpeg4_file_id":"'$3'"'$(title2Json "$4" "$5")'}' + ;; + "cached_sticker") # sticker ID file + JSON='{"type":"sticker","id":"'$ID'","sticker_file_id":"'$3'"}' + ;; + "cached_document") # document ID title file (description caption) + JSON='{"type":"document","id":"'$ID'","document_file_id":"'$4'"'$(title2Json "$3" "$6" "$5")'}' + ;; + "cached_video") # video ID file title (description caption) + JSON='{"type":"video","id":"'$ID'","video_file_id":"'$3'"'$(title2Json "$4" "$6" "$5")'}' + ;; + "cached_voice") # voice ID file title (caption) + JSON='{"type":"voice","id":"'$ID'","voice_file_id":"'$3'"'$(title2Json "$4" "$5")'}' + ;; + "cached_audio") # audio ID file title (caption) + JSON='{"type":"audio","id":"'$ID'","audio_file_id":"'$3'"'$(title2Json "$4" "$5")'}' + ;; + esac + + echo "${JSON}" +} + diff --git a/modules/background.sh b/modules/background.sh index 94109ce..946c59b 100644 --- a/modules/background.sh +++ b/modules/background.sh @@ -5,78 +5,10 @@ # This file is public domain in the USA and all free countries. # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) # -#### $$VERSION$$ v0.80-dev2-1-g0b36bc5 +#### $$VERSION$$ v0.80-dev2-6-g5b10e75 # source from commands.sh if you want ro use interactive or background jobs -## to statisfy shellcheck -export res - -#### -# I placed send_message here because main use case is interactive chats and background jobs -send_message() { - [ "$2" = "" ] && return - local text keyboard btext burl no_keyboard file lat long title address sent - text="$(sed <<< "${2}" 's/ mykeyboardend.*//;s/ *my[kfltab][a-z]\{2,13\}startshere.*//')$(sed <<< "${2}" -n '/mytextstartshere/ s/.*mytextstartshere//p')" - text="$(sed <<< "${text}" 's/ *mynewlinestartshere */\r\n/g')" - [ "$3" != "safe" ] && { - no_keyboard="$(sed <<< "${2}" '/mykeyboardendshere/!d;s/.*mykeyboardendshere.*/mykeyboardendshere/')" - keyboard="$(sed <<< "${2}" '/mykeyboardstartshere /!d;s/.*mykeyboardstartshere *//;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')" - btext="$(sed <<< "${2}" '/mybtextstartshere /!d;s/.*mybtextstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')" - burl="$(sed <<< "${2}" '/myburlstartshere /!d;s/.*myburlstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//g;s/ *mykeyboardendshere.*//g')" - file="$(sed <<< "${2}" '/myfilelocationstartshere /!d;s/.*myfilelocationstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')" - lat="$(sed <<< "${2}" '/mylatstartshere /!d;s/.*mylatstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')" - long="$(sed <<< "${2}" '/mylongstartshere /!d;s/.*mylongstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')" - title="$(sed <<< "${2}" '/mytitlestartshere /!d;s/.*mytitlestartshere //;s/ *my[kfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')" - address="$(sed <<< "${2}" '/myaddressstartshere /!d;s/.*myaddressstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')" - } - if [ "$no_keyboard" != "" ]; then - remove_keyboard "$1" "$text" - sent=y - fi - if [ "$keyboard" != "" ]; then - if [[ "$keyboard" != *"["* ]]; then # pre 0.60 style - keyboard="[ ${keyboard//\" \"/\" \] , \[ \"} ]" - fi - send_keyboard "$1" "$text" "$keyboard" - sent=y - fi - if [ "$btext" != "" ] && [ "$burl" != "" ]; then - send_button "$1" "$text" "$btext" "$burl" - sent=y - fi - if [ "$file" != "" ]; then - send_file "$1" "$file" "$text" - sent=y - fi - if [ "$lat" != "" ] && [ "$long" != "" ]; then - if [ "$address" != "" ] && [ "$title" != "" ]; then - send_venue "$1" "$lat" "$long" "$title" "$address" - else - send_location "$1" "$lat" "$long" - fi - sent=y - fi - if [ "$sent" != "y" ];then - send_text "$1" "$text" - fi - -} - -send_text() { - case "$2" in - html_parse_mode*) - send_html_message "$1" "${2//html_parse_mode}" - ;; - markdown_parse_mode*) - send_markdown_message "$1" "${2//markdown_parse_mode}" - ;; - *) - send_normal_message "$1" "$2" - ;; - esac -} - ###### # interactive and background functions @@ -99,7 +31,9 @@ checkback() { } checkproc() { - tmux ls | grep -q "$1${copname}"; res=$?; return $? + tmux ls | grep -q "$1${copname}" + # shellcheck disable=SC2034 + res=$?; return $? } killback() { diff --git a/modules/chatMember.sh b/modules/chatMember.sh new file mode 100644 index 0000000..9f19534 --- /dev/null +++ b/modules/chatMember.sh @@ -0,0 +1,63 @@ +#!/bin/bash +# file: modules/chatMember.sh +# do not edit, this file will be overwritten on update + +# This file is public domain in the USA and all free countries. +# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) +# +#### $$VERSION$$ v0.80-dev2-6-g5b10e75 + +# source from commands.sh to use the member functions + +LEAVE_URL=$URL'/leaveChat' +KICK_URL=$URL'/kickChatMember' +UNBAN_URL=$URL'/unbanChatMember' +GETMEMBER_URL=$URL'/getChatMember' + +# usage: status="$(get_chat_member_status "chat" "user")" +get_chat_member_status() { + sendJson "$1" 'user_id: '"$2"'' "$GETMEMBER_URL" + # shellcheck disable=SC2154 + JsonGetString '"result","status"' <<< "$res" +} + +kick_chat_member() { + sendJson "$1" 'user_id: '"$2"'' "$KICK_URL" +} + +unban_chat_member() { + sendJson "$1" 'user_id: '"$2"'' "$UNBAN_URL" +} + +leave_chat() { + sendJson "$1" "" "$LEAVE_URL" +} + +user_is_creator() { + if [ "${1:--}" = "${2:-+}" ] || [ "$(get_chat_member_status "$1" "$2")" = "creator" ]; then return 0; fi + return 1 +} + +user_is_admin() { + local me; me="$(get_chat_member_status "$1" "$2")" + if [ "${me}" = "creator" ] || [ "${me}" = "administrator" ]; then return 0; fi + return 1 +} + +user_is_botadmin() { + local admin; admin="$(head -n 1 "${BOTADMIN}")" + [ "${admin}" = "${1}" ] && return 0 + [[ "${admin}" = "@*" ]] && [[ "${admin}" = "${2}" ]] && return 0 + if [ "${admin}" = "?" ]; then echo "${1:-?}" >"${BOTADMIN}"; return 0; fi + return 1 +} + +user_is_allowed() { + local acl="$1" + [ "$1" = "" ] && return 1 + grep -F -xq "${acl}:*:*" <"${BOTACL}" && return 0 + [ "$2" != "" ] && acl="${acl}:$2" + grep -F -xq "${acl}:*" <"${BOTACL}" && return 0 + [ "$3" != "" ] && acl="${acl}:$3" + grep -F -xq "${acl}" <"${BOTACL}" +} diff --git a/modules/inline.sh b/modules/inline.sh index 5ad0edc..601d1e5 100644 --- a/modules/inline.sh +++ b/modules/inline.sh @@ -1,102 +1,2 @@ #!/bin/bash -# file: modules/inline.sh -# do not edit, this file will be overwritten on update - -# This file is public domain in the USA and all free countries. -# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) -# -#### $$VERSION$$ v0.80-dev2-4-gb7df57a - -# source from commands.sh to use the inline functions - -INLINE_QUERY=$URL'/answerInlineQuery' - -answer_inline_query() { - answer_inline_multi "${1}" "$(shift; inline_query_compose "$RANDOM" "$@")" -} -answer_inline_multi() { - sendJson "" '"inline_query_id": '"${1}"', "results": ['"${2}"']' "${INLINE_QUERY}" -} - -# $1 unique ID for answer -# $2 type of answer -# remaining arguments are the "must have" arguments in the order as in telegram doc -# followed by the optional arguments: https://core.telegram.org/bots/api#inlinequeryresult -inline_query_compose(){ - local JSON="{}" - local ID="${1}" - local fours last - # title2Json title caption description markup inlinekeyboard - case "${2}" in - # user provided media - "article"|"message") # article ID title message (markup decription) - JSON='{"type":"article","id":"'$ID'","input_message_content": {"message_text":"'$4'"} '$(title2Json "$3" "" "$5" "$6")'}' - ;; - "photo") # photo ID photoURL (thumbURL title description caption) - [ "$4" = "" ] && tumb="$3" - JSON='{"type":"photo","id":"'$ID'","photo_url":"'$3'","thumb_url":"'$4${tumb}'"'$(title2Json "$5" "$7" "$6")'}' - ;; - "gif") # gif ID photoURL (thumbURL title caption) - [ "$4" = "" ] && tumb="$3" - JSON='{"type":"gif","id":"'$ID'","gif_url":"'$3'", "thumb_url":"'$4${tumb}'"'$(title2Json "$5" "$6")'}' - ;; - "mpeg4_gif") # mpeg4_gif ID mpegURL (thumbURL title caption) - [ "$4" != "" ] && tumb='","thumb_url":"'$4'"' - JSON='{"type":"mpeg4_gif","id":"'$ID'","mpeg4_url":"'$3'"'${tumb}$(title2Json "$5" "$6")'}' - ;; - "video") # video ID videoURL mime thumbURL title (caption) - JSON='{"type":"video","id":"'$ID'","video_url":"'$3'","mime_type":"'$4'","thumb_url":"'$5'"'$(title2Json "$6" "$7")'}' - ;; - "audio") # audio ID audioURL title (caption) - JSON='{"type":"audio","id":"'$ID'","audio_url":"'$3'"'$(title2Json "$4" "$5")'}' - ;; - "voice") # voice ID voiceURL title (caption) - JSON='{"type":"voice","id":"'$ID'","voice_url":"'$3'"'$(title2Json "$4" "$5")'}' - ;; - "document") # document ID title documentURL mimetype (caption description) - JSON='{"type":"document","id":"'$ID'","document_url":"'$4'","mime_type":"'$5'"'$(title2Json "$3" "$6" "$7")'}' - ;; - "location") # location ID lat long title - JSON='{"type":"location","id":"'$ID'","latitude":"'$3'","longitude":"'$4'","title":"'$5'"}' - ;; - "venue") # venue ID lat long title (adress forsquare) - [ "$6" = "" ] && addr="$5" - [ "$7" != "" ] && fours=',"foursquare_id":"'$7'"' - JSON='{"type":"venue","id":"'$ID'","latitude":"'$3'","longitude":"'$4'","title":"'$5'","address":"'$6${addr}'"'${fours}'}' - ;; - "contact") # contact ID phone first (last thumb) - [ "$5" != "" ] && last=',"last_name":"'$5'"' - [ "$6" != "" ] && tumb='","thumb_url":"'$6'"' - JSON='{"type":"contact","id":"'$ID'","phone_number":"'$3'","first_name":"'$4'"'${last}'"}' - ;; - # title2Json title caption description markup inlinekeyboard - # Cached media stored in Telegram server - "cached_photo") # photo ID file (title description caption) - JSON='{"type":"photo","id":"'$ID'","photo_file_id":"'$3'"'$(title2Json "$4" "$6" "$5")'}' - ;; - "cached_gif") # gif ID file (title caption) - JSON='{"type":"gif","id":"'$ID'","gif_file_id":"'$3'"'$(title2Json "$4" "$5")'}' - ;; - "cached_mpeg4_gif") # mpeg ID file (title caption) - JSON='{"type":"mpeg4_gif","id":"'$ID'","mpeg4_file_id":"'$3'"'$(title2Json "$4" "$5")'}' - ;; - "cached_sticker") # sticker ID file - JSON='{"type":"sticker","id":"'$ID'","sticker_file_id":"'$3'"}' - ;; - "cached_document") # document ID title file (description caption) - JSON='{"type":"document","id":"'$ID'","document_file_id":"'$4'"'$(title2Json "$3" "$6" "$5")'}' - ;; - "cached_video") # video ID file title (description caption) - JSON='{"type":"video","id":"'$ID'","video_file_id":"'$3'"'$(title2Json "$4" "$6" "$5")'}' - ;; - "cached_voice") # voice ID file title (caption) - JSON='{"type":"voice","id":"'$ID'","voice_file_id":"'$3'"'$(title2Json "$4" "$5")'}' - ;; - "cached_audio") # audio ID file title (caption) - JSON='{"type":"audio","id":"'$ID'","audio_file_id":"'$3'"'$(title2Json "$4" "$5")'}' - ;; - esac - - echo "${JSON}" -} - +echo "use answerInline.sh" >&2 diff --git a/modules/sendMessage.sh b/modules/sendMessage.sh new file mode 100644 index 0000000..92e1f50 --- /dev/null +++ b/modules/sendMessage.sh @@ -0,0 +1,228 @@ +#!/bin/bash +# file: modules/message.sh +# do not edit, this file will be overwritten on update + +# This file is public domain in the USA and all free countries. +# Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) +# +#### $$VERSION$$ v0.80-dev2-6-g5b10e75 + +# source from commands.sh to use the sendMessage functions + +MSG_URL=$URL'/sendMessage' +PHO_URL=$URL'/sendPhoto' +AUDIO_URL=$URL'/sendAudio' +DOCUMENT_URL=$URL'/sendDocument' +STICKER_URL=$URL'/sendSticker' +VIDEO_URL=$URL'/sendVideo' +VOICE_URL=$URL'/sendVoice' +LOCATION_URL=$URL'/sendLocation' +VENUE_URL=$URL'/sendVenue' +ACTION_URL=$URL'/sendChatAction' +FORWARD_URL=$URL'/forwardMessage' + +send_normal_message() { + local text="${2}" + until [ -z "${text}" ]; do + sendJson "${1}" '"text":"'"${text:0:4096}"'"' "${MSG_URL}" + text="${text:4096}" + done +} + +send_markdown_message() { + local text="${2}" + until [ -z "${text}" ]; do + sendJson "${1}" '"text":"'"${text:0:4096}"'","parse_mode":"markdown"' "${MSG_URL}" + text="${text:4096}" + done +} + +send_html_message() { + local text="${2}" + until [ -z "${text}" ]; do + sendJson "${1}" '"text":"'"${text:0:4096}"'","parse_mode":"html"' "${MSG_URL}" + text="${text:4096}" + done +} + +old_send_keyboard() { + local text='"text":"'"${2}"'"' + shift 2 + local keyboard=init + OLDIFS=$IFS + IFS=$(echo -en "\"") + for f in "$@" ;do [ "$f" != " " ] && keyboard="$keyboard, [\"$f\"]";done + IFS=$OLDIFS + keyboard=${keyboard/init, /} + sendJson "${1}" "${text}"', "reply_markup": {"keyboard": [ '"${keyboard}"' ],"one_time_keyboard": true}' "$MSG_URL" +} + +ISEMPTY="ThisTextIsEmptyAndWillBeDeleted" +sendEmpty() { + sendJson "${@}" + [[ "${2}" = *"${ISEMPTY}"* ]] && delete_message "${1}" "${BOTSENT[ID]}" +} +send_keyboard() { + if [[ "$3" != *'['* ]]; then old_send_keyboard "${@}"; return; fi + local text='"text":"'"${2}"'"'; [ "${2}" = "" ] && text='"text":"'"${ISEMPTY}"'"' + local one_time=', "one_time_keyboard":true' && [ "$4" != "" ] && one_time="" + sendEmpty "${1}" "${text}"', "reply_markup": {"keyboard": [ '"${3}"' ] '"${one_time}"'}' "$MSG_URL" + # '"text":"$2", "reply_markup": {"keyboard": [ ${3} ], "one_time_keyboard": true}' +} + +remove_keyboard() { + local text='"text":"'"${2}"'"'; [ "${2}" = "" ] && text='"text":"'"${ISEMPTY}"'"' + sendEmpty "${1}" "${text}"', "reply_markup": {"remove_keyboard":true}' "$MSG_URL" + #JSON='"text":"$2", "reply_markup": {"remove_keyboard":true}' +} +send_inline_keyboard() { + local text='"text":"'"${2}"'"'; [ "${2}" = "" ] && text='"text":"'"${ISEMPTY}"'"' + sendEmpty "${1}" "${text}"', "reply_markup": {"inline_keyboard": [ '"${3}"' ]}' "$MSG_URL" + # JSON='"text":"$2", "reply_markup": {"inline_keyboard": [ $3->[{"text":"text", "url":"url"}]<- ]}' +} +send_button() { + send_inline_keyboard "${1}" "${2}" '[ {"text":"'"${3}"'", "url":"'"${4}"'"}]' +} + + +send_file() { + [ "$2" = "" ] && return + local CAPTION + local chat_id=$1 + local file=$2 + echo "$file" | grep -qE "$FILE_REGEX" || return + local ext="${file##*.}" + case $ext in + mp3|flac) + CUR_URL=$AUDIO_URL + WHAT=audio + STATUS=upload_audio + CAPTION="$3" + ;; + png|jpg|jpeg|gif) + CUR_URL=$PHO_URL + WHAT=photo + STATUS=upload_photo + CAPTION="$3" + ;; + webp) + CUR_URL=$STICKER_URL + WHAT=sticker + STATUS= + ;; + mp4) + CUR_URL=$VIDEO_URL + WHAT=video + STATUS=upload_video + CAPTION="$3" + ;; + + ogg) + CUR_URL=$VOICE_URL + WHAT=voice + STATUS= + ;; + *) + CUR_URL=$DOCUMENT_URL + WHAT=document + STATUS=upload_document + CAPTION="$3" + ;; + esac + send_action "$chat_id" "$STATUS" + # convert over to sendJson!! + # shellcheck disable=SC2034 + res="$(curl -s "$CUR_URL" -F "chat_id=$chat_id" -F "$WHAT=@$file" -F "caption=$CAPTION")" +} + +# typing for text messages, upload_photo for photos, record_video or upload_video for videos, record_audio or upload_audio for audio files, upload_document for general files, find_location for location + +send_action() { + [ "$2" = "" ] && return + sendJson "${1}" '"action": "'"${2}"'"' "$ACTION_URL" +} + +send_location() { + [ "$3" = "" ] && return + sendJson "${1}" '"latitude": '"${2}"', "longitude": '"${3}"'' "$LOCATION_URL" +} + +send_venue() { + local add="" + [ "$5" = "" ] && return + [ "$6" != "" ] && add=', "foursquare_id": '"$6"'' + sendJson "${1}" '"latitude": '"${2}"', "longitude": '"${3}"', "address": "'"${5}"'", "title": "'"${4}"'"'"${add}" "$VENUE_URL" +} + + +forward_message() { + [ "$3" = "" ] && return + sendJson "${1}" '"from_chat_id": '"${2}"', "message_id": '"${3}"'' "$FORWARD_URL" +} +forward() { # backward compatibility + forward_message "$@" || return +} + +send_message() { + [ "$2" = "" ] && return + local text keyboard btext burl no_keyboard file lat long title address sent + text="$(sed <<< "${2}" 's/ mykeyboardend.*//;s/ *my[kfltab][a-z]\{2,13\}startshere.*//')$(sed <<< "${2}" -n '/mytextstartshere/ s/.*mytextstartshere//p')" + text="$(sed <<< "${text}" 's/ *mynewlinestartshere */\r\n/g')" + [ "$3" != "safe" ] && { + no_keyboard="$(sed <<< "${2}" '/mykeyboardendshere/!d;s/.*mykeyboardendshere.*/mykeyboardendshere/')" + keyboard="$(sed <<< "${2}" '/mykeyboardstartshere /!d;s/.*mykeyboardstartshere *//;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')" + btext="$(sed <<< "${2}" '/mybtextstartshere /!d;s/.*mybtextstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')" + burl="$(sed <<< "${2}" '/myburlstartshere /!d;s/.*myburlstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//g;s/ *mykeyboardendshere.*//g')" + file="$(sed <<< "${2}" '/myfilelocationstartshere /!d;s/.*myfilelocationstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')" + lat="$(sed <<< "${2}" '/mylatstartshere /!d;s/.*mylatstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')" + long="$(sed <<< "${2}" '/mylongstartshere /!d;s/.*mylongstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')" + title="$(sed <<< "${2}" '/mytitlestartshere /!d;s/.*mytitlestartshere //;s/ *my[kfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')" + address="$(sed <<< "${2}" '/myaddressstartshere /!d;s/.*myaddressstartshere //;s/ *my[nkfltab][a-z]\{2,13\}startshere.*//;s/ *mykeyboardendshere.*//')" + } + if [ "$no_keyboard" != "" ]; then + remove_keyboard "$1" "$text" + sent=y + fi + if [ "$keyboard" != "" ]; then + if [[ "$keyboard" != *"["* ]]; then # pre 0.60 style + keyboard="[ ${keyboard//\" \"/\" \] , \[ \"} ]" + fi + send_keyboard "$1" "$text" "$keyboard" + sent=y + fi + if [ "$btext" != "" ] && [ "$burl" != "" ]; then + send_button "$1" "$text" "$btext" "$burl" + sent=y + fi + if [ "$file" != "" ]; then + send_file "$1" "$file" "$text" + sent=y + fi + if [ "$lat" != "" ] && [ "$long" != "" ]; then + if [ "$address" != "" ] && [ "$title" != "" ]; then + send_venue "$1" "$lat" "$long" "$title" "$address" + else + send_location "$1" "$lat" "$long" + fi + sent=y + fi + if [ "$sent" != "y" ];then + send_text "$1" "$text" + fi + +} + +send_text() { + case "$2" in + html_parse_mode*) + send_html_message "$1" "${2//html_parse_mode}" + ;; + markdown_parse_mode*) + send_markdown_message "$1" "${2//markdown_parse_mode}" + ;; + *) + send_normal_message "$1" "$2" + ;; + esac +} + diff --git a/mycommands.sh b/mycommands.sh index cad65c3..808aee7 100644 --- a/mycommands.sh +++ b/mycommands.sh @@ -2,24 +2,22 @@ # files: mycommands.sh.dist # copy to mycommands.sh and add all your commands and functions here ... # -#### $$VERSION$$ v0.80-dev2-2-g0c5e3dd +#### $$VERSION$$ v0.80-dev2-6-g5b10e75 # -# shellcheck disable=SC2154 -# shellcheck disable=SC2034 - # uncomment the following lines to overwrite info and help messages # bashbot_info='This is bashbot, the Telegram bot written entirely in bash. #' # bashbot_help='*Available commands*: #' +res="" if [ "$1" = "source" ];then # Set INLINE to 1 in order to receive inline queries. # To enable this option in your bot, send the /setinline command to @BotFather. - INLINE="0" + export INLINE="0" # Set to .* to allow sending files from all locations - FILE_REGEX='/home/user/allowed/.*' + export FILE_REGEX='/home/user/allowed/.*' else # your additional bahsbot commands