Community discussions

MikroTik App
 
zivtal
Frequent Visitor
Frequent Visitor
Topic Author
Posts: 57
Joined: Sun Feb 05, 2017 6:22 pm

Telegram BlackVS modified script V2

Thu Jan 10, 2019 12:21 am

configuration script (call it "telegram.cfg" and put it in scripts)
# command should be the name of the script (default: telegram)
# botapi - telegram botapi
# reply - default message to (telegram id)
# trusted - telegram id(s) accepted
# refresh_active - change scheduler to check telegram for updates every X time after sending or receiving telegram message.
# refresh_standby - after 3 min(s) without updates change scheduler to check telegram for updates every Y time.

:local config {
	"command"="telegram";
	"botapi"="";
	"reply"="";
	"trusted"="XXXXXXXXX,BBBBBBBB";
	"storage"="";
	"timeout"=1;
	"refresh_active"=20s;
	"refresh_standby"=1h;
	"start"="";
}
return $config

telegram script (call it "telegram" and put it in scripts)
:local fconfig [:parse [/system script get telegram.cfg source]]
:local cfg [$fconfig]
:local scriptname ($cfg->"command")
:local onactive ($cfg->"refresh_active")
:local onstandby ($cfg->"refresh_standby")
#convert W D XX:XX:XX time to secounds
:local timeConvert do={
	:local time [:tostr $1]
	:local result
	:local daypos
	:set daypos (0);
	:for pos from=0 to=([:len $time]-8) do={
		# Find "w" and the weeks
		:if ([:pick $time $pos] = "w") do={
			:set result ([:tonum [:pick $time 0 ($pos)]]*7*24*60*60)
			:set daypos ($pos+1)
		}
		# Find "d" and days
		:if ([:pick $time $pos] = "d") do={
			:set result ($result+([:tonum [:pick $time ($daypos) ($pos)]]*24*60*60))
		}
	}
	# Recalculate hours and add :min:sec
	:set result ($result+([:tonum [:pick $time ([:len $time]-8) ([:len $time]-6)]]*60*60))
	:set result ($result+([:tonum [:pick $time ([:len $time]-5) ([:len $time]-3)]]*60))
	:set result ($result+([:tonum [:pick $time ([:len $time]-2) ([:len $time])]]))
	:return $result
}
# check last time received message
:local timeCompare do={
	:local date1 [:tostr $1];
	:local date2 [:tostr $2];

	:local date1month [:pick $date1 0 3]
	:local date1day [:pick $date1 4 6]
	:local date1year [:pick $date1 7 11]
	:local date1hours [:pick $date1 12 14]
	:local date1minutes [:pick $date1 15 17]
	:local date1seconds [:pick $date1 18 20]

	:local date2month [:pick $date2 0 3]
	:local date2day [:pick $date2 4 6]
	:local date2year [:pick $date2 7 11]
	:local date2hours [:pick $date2 12 14]
	:local date2minutes [:pick $date2 15 17]
	:local date2seconds [:pick $date2 18 20]

	# month to decimal converter - https://forum.mikrotik.com/viewtopic.php?t=58674
	:local months ("jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec");
	:set date1month ([:find $months $date1month -1 ] + 1)
	:set date2month ([:find $months $date2month -1 ] + 1)

	:local yearDiff ($date2year - $date1year)
	:local monthDiff ($date2month - $date1month)
	:local dayDiff ($date2day - $date1day) 
	:local hoursDiff ($date2hours - $date1hours)
	:local minutesDiff ($date2minutes - $date1minutes)
	:local secondsDiff ($date2seconds - $date1seconds)

	:local secondsGlobalDiff
	:set secondsGlobalDiff (($dayDiff * 86400) + ($hoursDiff * 3600) + ($minutesDiff *60) + $secondsDiff)
	:set dayDiff ($secondsGlobalDiff / 86400)
	:set secondsGlobalDiff ($secondsGlobalDiff - ($dayDiff * 86400))
	:set hoursDiff ($secondsGlobalDiff / 3600)
	:set secondsGlobalDiff ($secondsGlobalDiff - ($hoursDiff * 3600))
	:set minutesDiff ($secondsGlobalDiff / 60)
	:set secondsGlobalDiff ($secondsGlobalDiff - ($minutesDiff * 60))
	:set secondsDiff $secondsGlobalDiff

	# check if leap years - https://wiki.mikrotik.com/wiki/AutomatedBilling/MonthEndScript
	:local isYear1Leap 0
	:local isYear2Leap 0
	if ((($date1year / 4) * 4) = $date1year) do={
		:set isYear1Leap 1
	}
	if ((($date2year / 4) * 4) = $date2year) do={
		:set isYear2Leap 1
	}

	# find the right amount of days between 2 months
	:local daysInEachMonth ("31","28","31","30","31","30","31","31","30","31","30","31");
	:local daysInEachMonthLeapYear ("31","29","31","30","31","30","31","31","30","31","30","31");
	:local totalDaysBetweenMonths

	# same year; yearDiff = 0 so year1 = year2
	if ($yearDiff = 0 and $monthDiff >= 1) do={
	    if ($isYear1Leap = 0) do={  
			for month from=($date1month - 1) to=($date2month - 1) step=1 do={
				:set totalDaysBetweenMonths ($totalDaysBetweenMonths + [:pick $daysInEachMonth $month])
 			}
    	}
    	if ($isYear1Leap = 1) do={
 			for month from=($date1month - 1) to=(($date2month - 1) - 1) step=1 do={
     			:set totalDaysBetweenMonths ($totalDaysBetweenMonths + [:pick $daysInEachMonthLeapYear $month])
 			}
    	}
	}

	# different year, make concatenation of daysInEachMonth arrays first
	:local daysInEachMonthConcatenatedYears
	if ($yearDiff >= 1) do={
    	for year from=$date1year to=$date2year step=1 do={
		 # if leap year, concatenate the right daysInEachMonth array
			 if ((($year / 4) * 4) = $year) do={
				:set daysInEachMonthConcatenatedYears ($daysInEachMonthConcatenatedYears, $daysInEachMonthLeapYear)
			} else={
				:set daysInEachMonthConcatenatedYears ($daysInEachMonthConcatenatedYears, $daysInEachMonth)
 			}
    	}
    	# must add years count 
		for month from=($date1month - 1) to=(($date2month - 1)  + (($yearDiff * 12) - 1)) step=1 do={
			:set totalDaysBetweenMonths ($totalDaysBetweenMonths + [:pick $daysInEachMonthConcatenatedYears $month])
    	}
	}

	:local globalDaysDiff ($totalDaysBetweenMonths + $dayDiff)

	# add leading zeros if necessary
	:if ($hoursDiff < 10) do={
    	:set hoursDiff ("0" . $hoursDiff)
	}
	:if ($minutesDiff < 10) do={
    	:set minutesDiff ("0" . $minutesDiff)
	}
	:if ($secondsDiff < 10) do={
    	:set secondsDiff ("0" . $secondsDiff)
	}

	:local inMinutes ($globalDaysDiff*24*60+$hoursDiff*60+$minutesDiff);
	return $inMinutes;
}
#send message
:global tgSendMessage do={
	:local fconfig [:parse [/system script get telegram.cfg source]]
	:local cfg [$fconfig]
	:local api ($cfg->"botapi")
	:local storage ($cfg->"storage")
	:local reply ($cfg->"reply")

	:if ([:len $chat]>0) do={
		:set reply $chat
	} else={
		:local upreply
		:local getTelegramID do={
			:if ([:type [:find $input "="]]!="nil") do={
				:return [:pick $input 0 [:find $input "="]]
			} else={
				:return $input
			}
		}
		:local getTelegramMAC do={
			:if ([:type [:find $input "="]]!="nil") do={
				:return [:pick $input ([:find $input "="]+1) [:len $input]]
			} else={
				:return false
			}
		}
		:foreach tg in=[:toarray $reply] do={
			:if (([$getTelegramMAC input=$tg]=false) or ([:len [/ip dhcp-server lease find mac-address=[$getTelegramMAC input=$tg]]]>0)) do={
				:set upreply ([$getTelegramID input=$tg].",".$upreply)
			}
		}
		:set reply $upreply
	}

	:foreach chatID in=[:toarray $reply] do={
		:local fail true
		:local retry 0
		:local attempt 3
		:local url "https://api.telegram.org/bot$api/sendmessage\?chat_id=$chatID&text=$text"
		:if ($markdown!="false") do={
			:set url ($url."&parse_mode=Markdown")
		}
		:while (($fail=true) and ($retry<$attempt)) do={
			:do {
				/tool fetch url=$url keep-result=no
				:set fail false
			} on-error={
				:set fail true
				:delay 3s
			}
			:set retry ($retry+1)
		}
		:if ($fail=true) do={
			:log error "failed to send telegram message ('$[:pick [$text] 0 96] ...') to '$chatID'"
		}
	}
}
#receive message
:global tgReceiveMessage do={
	:global tgSendMessage
	:global tgReceiveID
	:global tgReceiveUPDID
	:global tgReceiveTIME

	:local fconfig [:parse [/system script get telegram.cfg source]]
	:local cfg [$fconfig]
	:local trustedid [:toarray ($cfg->"trusted")]
	:local api ($cfg->"botapi")
	:local storage ($cfg->"storage")
	:local rtimeout ($cfg->"timeout")
	:local startmsg ($cfg->"start")

	:local tgGetkey do={
		:local cur 0
		:local lkey [:len $key]
		:local res ""
		:local p

		:if ([:len $block]>0) do={
	 		:set p [:find $text $block $cur]
	 		:if ([:type $p]="nil") do={
	  			:return $res
	 		}
	 		:set cur ($p+[:len $block]+2)
		}

		:set p [:find $text $key $cur]
		:if ([:type $p]!="nil") do={
	 		:set cur ($p+lkey+2)
	 		:set p [:find $text "," $cur]
	 		:if ([:type $p]!="nil") do={
	   			:if ([:pick $text $cur]="\"") do={
	    			:set res [:pick $text ($cur+1) ($p-1)]
	   			} else={
	    			:set res [:pick $text $cur $p]
   				}
			}
		}
		:return $res	
	}

	:local http do={
		:local res ($storage.$file.".fetch.txt")
		:if ([:len $resfile]>0) do={:set res $resfile}
		#:put $res

		:local cmd "/tool fetch"
		:if ([:len $mode]>0) do={:set cmd "$cmd mode=$mode"}
		:if ([:len $upload]>0) do={:set cmd "$cmd upload=$upload"}
		:if ([:len $user]>0) do={:set cmd "$cmd user=\"$user\""}
		:if ([:len $password]>0) do={:set cmd "$cmd password=\"$password\""}
		:if ([:len $address]>0) do={:set cmd "$cmd address=\"$address\""}
		:if ([:len $host]>0) do={:set cmd "$cmd host=\"$host\""}
		:if ([:len $"http-data"]>0) do={:set cmd "$cmd http-data=\"$"http-data"\""}
		:if ([:len $"http-method"]>0) do={:set cmd "$cmd http-method=\"$"http-method"\""}
		:if ([:len $"check-certificate"]>0) do={:set cmd "$cmd check-certificate=\"$"check-certificate"\""}
		:if ([:len $"src-path"]>0) do={:set cmd "$cmd src-path=\"$"src-path"\""}
		:if ([:len $"dst-path"]>0) do={:set cmd "$cmd dst-path=\"$"dst-path"\""}
		:if ([:len $ascii]>0) do={:set cmd "$cmd ascii=\"$ascii\""}
		:if ([:len $url]>0) do={:set cmd "$cmd url=\"$url\""}

		:put ">> $cmd"

		:global tgReceiveFETCH
		:set tgReceiveFETCH "none"

		:local script "\
	 	:global tgReceiveFETCH;\
	 	:do {\
	   		$cmd;\
	   		:set tgReceiveFETCH \"success\";\
	 	} on-error={\
	  		:set tgReceiveFETCH \"failed\";\
	 	}\
		"
		:execute script=$script file=$res
		:local cnt 0
		#:put "$cnt -> $tgReceiveFETCH"
		:while ($cnt<100 and $tgReceiveFETCH="none") do={ 
	 		:delay 1s
	 		:set $cnt ($cnt+1)
	 		#:put "$cnt -> $tgReceiveFETCH"
		}
		:local content [/file get [find name=$res] content]
		#:put $content
		if ($content~"finished") do={:return "success"}
		:return $tgReceiveFETCH
	}

	:put "trusted=$trustedid"
	:put "botID=$api"
	:put "storage=$storage"
	:put "timeout=$rtimeout"

	:local noupdate false;

	#loop start
	while (!$noupdate) do={
		:local url ("https://api.telegram.org/bot".$api."/getUpdates?timeout=$rtimeout&limit=1")
		:if ([:len $tgReceiveUPDID]>0) do={
			:set url "$url&offset=$($tgReceiveUPDID+1)"
		}

		#:log info "telegram receiving updates..."
		:local res [$http dst-path=($storage.$file.".receive.txt") url=$url resfile=($storage.$file.".fetch.txt")]
		:if ($res!="success") do={
			:log error "telegram receive updates failed"
			:return "Failed get updates"
			:set noupdate true;
		}
		#:log info "telegram receiving updates complete"

		:local content [/file get [/file find name=($storage.$file.".receive.txt")] contents]

		:local msgid [$tgGetkey key="message_id" text=$content]
		:if ($msgid="") do={ 
			#:log info "telegram has no new messages"
			:set noupdate true;
			:return 0 
		} else={
			:set tgReceiveID $msgid
			:local updid [$tgGetkey key="update_id" text=$content]
			:set tgReceiveUPDID $updid

			:local tgFromID [$tgGetkey block="from" key="id" text=$content]
			:local tgUsername [$tgGetkey block="from" key="username" text=$content]
			:local tgFirstName [$tgGetkey block="from" key="first_name" text=$content]
			:local tgLastName [$tgGetkey block="from" key="last_name" text=$content]
			:local tgID [$tgGetkey block="chat" key="id" text=$content]
			:local tgMessage [$tgGetkey block="chat" key="text" text=$content]
			:local tgName "$tgFirstName $tgLastName"

			:put "message id=$msgid"
			:put "update id=$updid"
			:put "from id=$tgFromID"
			:put "first name=$tgFirstName"
			:put "last name=$tgLastName"
			:put "username=$tgUsername"
			:if ([:len $tgName]<2) do {
				:if  ([:len $tgUsername]>0) do={
					:set tgName $tgUsername
				} else={
					:set tgName "Unknown"
				}
			}
			:put "name=$tgName"
			:put "in chat=$tgID"
			:put "command=$tgMessage"

			:local allowed ([:type [:find $trustedid $tgFromID]]!="nil" or [:type [:find $trustedid $tgID]]!="nil")
			:if (!$allowed) do={
				:log warning "telegram received content from $tgUsername ($tgFromID) has been ignored"
				:if ($tgMessage="/start") do={
					$tgSendMessage text=("Telegram message has been received from $tgUsername ($tgFromID), Content has been ignored, Telegram ID not allowed.") markdown=$markdown
				}
				:return -1
			} else={
				:set tgReceiveTIME ([/system clock get date]." ".[/system clock get time])
				:local cmd ""
				:local params ""
				:local ltext [:len $tgMessage]

				:local pos [:find $tgMessage " "]
				:if ([:type $pos]="nil") do={
					:set cmd [:pick $tgMessage 1 $ltext]
				} else={
					:set cmd [:pick $tgMessage 1 $pos]
					:set params [:pick $tgMessage ($pos+1) $ltext]
				}

				:local pos [:find $cmd "@"]
				:if ([:type $pos]!="nil") do={
					:set cmd [:pick $cmd 0 $pos]
				}

				:put "cmd=<$cmd>"
				:put "params=<$params>"

				:if ([:len [/system script find name=$cmd]]>0) do={
					:log warning "$tgName: /$cmd $params"
					:global tgReceiveCMD [:parse [/system script get $cmd source]]
					:execute "\$tgReceiveCMD $params tgchatid=$tgID tgname=\"$tgName\""
				} else={
					:if ($cmd="start") do={
						:log warning ("$tgFirstName $tgLastName ($tgID) has been connected to $[/system identity get name]'s bot")
						$tgSendMessage text=("*Wellcome to $[/system identity get name]'s bot*.%0A%0A$startmsg") markdown=true
					}
					:if ($cmd="system") do={
						:if ($params="reboot") do={
							/system reboot
						}
					}
				}
			}
		}
	}
}
:local months ("jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec");
:local tgfile ("tg.".[:pick [/system clock get date] 7 11].([:find $months [/system clock get date] -1 ] + 1).[:pick [/system clock get date] 4 6].[:pick [/system clock get time] 0 2].[:pick [/system clock get time] 3 5].[:pick [/system clock get time] 6 8])
#set/add scheduler
:if ([:len [/system scheduler find name=$scriptname]]=0) do={
	:log warning "creating telegram scheduler"
	/system scheduler add name=$scriptname interval=$onstandby on-event=":execute [/system script get telegram source]" start-time=00:00:00 comment="'telegram' checking for messages"
}
:local action [:tostr $1]
#run script
:if (([:len $action]=0) or ($action="receive")) do={
	$tgReceiveMessage file=$tgfile
} else={
	:if ($action="send") do={
		:global tgCheckTIME
		$tgSendMessage chat=$chat text=$text markdown=$markdown
		:if (([:len $tgCheckTIME]=0) or ([$timeCompare $tgCheckTIME ([/system clock get date]." ".[/system clock get time])]>3)) do={
			:set tgCheckTIME ([/system clock get date]." ".[/system clock get time])
			$tgReceiveMessage file=$tgfile
		}
	}
	:if ($action="last") do={
		/put [$timeCompare $tgReceiveTIME ([/system clock get date]." ".[/system clock get time])]
	}
}
:if ([/system scheduler get $scriptname disabled]=false) do={
	#set last time was online
	:global tgReceiveTIME
	:if (([:len $tgReceiveTIME]>0) and ([$timeCompare $tgReceiveTIME ([/system clock get date]." ".[/system clock get time])]<3)) do={
		:if ([$timeConvert [/system scheduler get value-name=interval [/system scheduler find name=$scriptname]]]!=$onactive) do={
			/system scheduler set interval=$onactive [/system scheduler find name=$scriptname]
		}
	} else={
		:if ([$timeConvert [/system scheduler get value-name=interval [/system scheduler find name=$scriptname]]]!=$onstandby) do={
			/system scheduler set interval=$onstandby [/system scheduler find name=$scriptname]
			/system script environment remove [find name~"tg"]
			/file remove [find name~"tg."]
		}
	}
}
/file remove [find name~$tgfile]
 
Gesuino
just joined
Posts: 14
Joined: Mon Jan 21, 2019 5:28 pm

Re: Telegram BlackVS modified script V2

Mon Feb 03, 2020 2:05 pm

Hi, great script i use or globally on my chr.
Someone know a way to send a variable trough command $tgSendMessage text="test $variable"
It give me a syntax error if I try to insert.
 
User avatar
ifibra
just joined
Posts: 5
Joined: Wed Dec 20, 2017 7:42 pm
Location: Cyprus

Re: Telegram BlackVS modified script V2

Wed Aug 11, 2021 7:32 pm

and? any documentation of it? how to work with it?

Who is online

Users browsing this forum: drpioneer, own3r1138 and 24 guests