# `7MMM. ,MMF'`7MMM. ,MMF' `7MMM. ,MMF' `7MM
# MMMb dPMM MMMb dPMM MMMb dPMM MM
# M YM ,M MM M YM ,M MM M YM ,M MM ,pW"Wq. ,M""bMM ,pP"Ybd
# M Mb M' MM M Mb M' MM M Mb M' MM 6W' `Wb ,AP MM 8I `"
# M YM.P' MM M YM.P' MM mmmmm M YM.P' MM 8M M8 8MI MM `YMMMa.
# M `YM' MM M `YM' MM M `YM' MM YA. ,A9 `Mb MM L. I8
# .JML. `' .JMML..JML. `' .JMML. .JML. `' .JMML.`Ybmd9' `Wbmd"MML.M9mmmP'
#
# (c) 2023 — licensed under Apache 2.0 — https://www.apache.org/licenses/LICENSE-2.0
# meta developer: @mm_mods
# meta pic: https://img.icons8.com/stickers/256/qr-code.png
from .. import loader, utils
from telethon.tl.patched import Message
import requests
import urllib.parse
import logging
from telethon.tl.types import InputMediaGeoPoint, InputGeoPoint
logger = logging.getLogger(__name__)
async def check_photo(reply_message: Message):
if reply_message and reply_message.media:
if reply_message.photo:
return reply_message.photo
else:
return False
else:
return False
class Parsers:
@staticmethod
def parse_mecard(data: str):
if not data.startswith("MECARD:"):
return False
data = data.replace("MECARD:", "")
data = data.split(";")
result = {}
for item in data:
try:
datatype, value = item.split(":")
except ValueError:
continue
if datatype == "N":
result["name"] = value
elif datatype == "TEL":
result["phone"] = value
elif datatype == "EMAIL":
result["email"] = value
elif datatype == "ADR":
result["address"] = value
elif datatype == "URL":
result["url"] = value
elif datatype == "ORG":
result["organisation"] = value
elif datatype == "NOTE":
result["note"] = value
else:
continue
return result
@staticmethod
def parse_wifi(data: str):
if not data.startswith("WIFI:"):
return False
data = data.replace("WIFI:", "")
data = data.split(";")
result = {}
for item in data:
try:
datatype, value = item.split(":")
except ValueError:
continue
if datatype == "S":
result["ssid"] = value
elif datatype == "P":
result["password"] = value
elif datatype == "T":
result["encryption"] = value
else:
continue
if "ssid" not in result:
return False
if "password" not in result:
result["password"] = "[none]"
if "encryption" not in result:
result["encryption"] = "[none]"
return result
@staticmethod
def parse_geo(data: str):
if not data.startswith("geo:"):
return False
data = data.replace("geo:", "")
lat, lon = data.split(",")
result = {
"lat": lat,
"lon": lon
}
return [result, InputMediaGeoPoint(InputGeoPoint(lat, lon))]
@staticmethod
def parse_sms(data: str):
if not data.startswith("smsto:"):
return False
data = data.replace("smsto:", "")
data = data.split(":")
phone = data[0]
try:
message = data[1]
except IndexError:
message = "[none]"
result = {
"phone": phone,
"message": message
}
return result
@staticmethod
def parse_phone(data: str):
if not data.startswith("tel:"):
return False
data = data.replace("tel:", "")
result = {
"phone": data
}
return result
@staticmethod
def parse_email(data: str):
if (not data.startswith("mailto:")) and (not data.startswith("MATMSG:")):
return False
if_expanded = True if data.startswith("MATMSG:TO:") else False
if if_expanded:
result = {}
data = data.replace("MATMSG:", "")
data = data.split(";")
for item in data:
try:
datatype, value = item.split(":")
except ValueError:
continue
if datatype == "TO":
result["email"] = value
elif datatype == "SUB":
result["subject"] = value
elif datatype == "BODY":
result["body"] = value
else:
continue
if "email" not in result:
return False
if "subject" not in result:
result["subject"] = "[none]"
if "body" not in result:
result["body"] = "[none]"
else:
data = data.replace("mailto:", "")
result = {
"email": data
}
return result
@staticmethod
def parse_vevent(data: str):
if not data.startswith("BEGIN:VEVENT"):
return False
data = data.split("\n")
result = {}
for item in data:
try:
datatype, value = item.split(":")
except ValueError:
continue
if datatype == "SUMMARY":
result["summary"] = value
elif datatype == "LOCATION":
result["location"] = value
elif datatype == "DESCRIPTION":
result["description"] = value
elif datatype == "DTSTART":
result["start"] = f'{value.split("T")[0][:4]}.{value.split("T")[0][4:6]}.{value.split("T")[0][6:8]} ' \
f'{value.split("T")[1][:2]}:{value.split("T")[1][2:4]}:{value.split("1")[0][4:]}' \
if "T" in value else f'{value[:4]}.{value[4:6]}.{value[6:8]}'
elif datatype == "DTEND":
result["end"] = f'{value.split("T")[0][:4]}.{value.split("T")[0][4:6]}.{value.split("T")[0][6:8]} ' \
f'{value.split("T")[1][:2]}:{value.split("T")[1][2:4]}:{value.split("1")[0][4:]}' \
if "T" in value else f'{value[:4]}.{value[4:6]}.{value[6:8]}'
else:
continue
if "summary" not in result:
return False
if "location" not in result:
result["location"] = "[none]"
if "description" not in result:
result["description"] = "[none]"
if "start" not in result:
result["start"] = "[none]"
if "end" not in result:
result["end"] = "[none]"
return result
class EntziffererMod(loader.Module):
"""Decoding QR codes."""
strings = {
"name": "Entzifferer",
"media?": "🖼 Reply to a message, containing code to scan.",
"qr?!": "❌ There's no code to scan.",
"decoding": "🔍 Decoding…",
"uploading": "📤 Uploading your file…",
"processing": "📊 Processing result…",
"error": "❌ Something went wrong.\nError: {}",
"result": "📄 Result:",
"qr": "🔍 QR code:",
"data": "Data: {}",
"contact": "Contact:\n{}",
"phone": "Phone: {}",
"sms": "SMS: {} to {}",
"geolocation": "Geolocation: latitude: {}, longitude: {}",
"email": "Email: {}",
"email_exp": "Email: {} (subject: {}, body: {})",
"wifi": "Wi-Fi:\nSSID: {} | Password: {} | Encryption: {}",
"url": "URL: {}",
"calendar": "Event: {}",
"MC-name": "👤 Name: {}",
"MC-phone": "☎ Phone: {}",
"MC-email": "📮 Email: {}",
"MC-address": "🏡 Address: {}",
"MC-note": "📝 Note: {}",
"MC-url": "🔗 URL: {}",
"MC-organisation": "💼 Organisation: {}",
"VE-summary": "🎯 Summary: {}",
"VE-location": "🗺 Location: {}",
"VE-description": "📜 Description: {}",
"VE-start": "➡ Start: {}",
"VE-end": "⬅ End: {}"
}
strings_ru = {
"name": "Entzifferer",
"media?": "🖼 Ответьте на сообщение, содержащее код, для сканирования.",
"qr?!": "❌ Нет кода для сканирования.",
"decoding": "🔍 Сканирую…",
"uploading": "📤 Загружаю…",
"processing": "📊 Обрабатываю результат…",
"error": "❌ Что-то пошло не так.\nОшибка: {}",
"result": "📄 Результат:",
"qr": "🔍 QR-код:",
"data": "Данные: {}",
"contact": "Контакт:\n{}",
"phone": "Телефон: {}",
"sms": "SMS: {} на номер {}",
"geolocation": "Геолокация: широта: {}, долгота: {}",
"email": "Почта: {}",
"email_exp": "Почта: {} (тема: {}, текст: {})",
"wifi": "Wi-Fi:\nSSID: {} | Пароль: {} | Шифрование: {}",
"url": "URL: {}",
"calendar": "Событие: {}",
"MC-name": "👤 Имя: {}",
"MC-phone": "☎ Телефон: {}",
"MC-email": "📮 Почта: {}",
"MC-address": "🏡 Адрес: {}",
"MC-note": "📝 Примечание: {}",
"MC-url": "🔗 URL: {}",
"MC-organisation": "💼 Организация: {}",
"VE-summary": "🎯 Заголовок: {}",
"VE-location": "🗺 Место: {}",
"VE-description": "📜 Описание: {}",
"VE-start": "➡ Начало: {}",
"VE-end": "⬅ Конец: {}",
"_cls_doc": "Декодирует QR-коды.",
"_cmd_doc_scancode": "Сканировать QR-код"
},
strings_de = {
"name": "Entzifferer",
"media?": "🖼 Antworte auf eine Nachricht, die einen Code enthält.",
"qr?!": "❌ Es gibt keinen Code zum Scannen.",
"decoding": "🔍 Scanne…",
"uploading": "📤 Lade deine Datei hoch…",
"processing": "📊 Verarbeite das Ergebnis…",
"error": "❌ Etwas ist schief gelaufen.\nFehler: {}",
"result": "📄 Ergebnis:",
"qr": "🔍 QR-Code:",
"data": "Daten: {}",
"сontact": "Kontakt:\n{}",
"phone": "Telefon: {}",
"sms": "SMS: {} zu {}",
"geolocation": "Geolocation: Breite: {}, Länge: {}",
"email": "E-Mail: {}",
"email_exp": "E-Mail: {} (Betreff: {}, Text: {})",
"wifi": "WLAN:\nSSID: {} | Passwort: {} | Verschlüsselung: {}",
"url": "URL: {}",
"calendar": "Ereignis: {}",
"MC-name": "👤 Name: {}",
"MC-phone": "☎ Telefon: {}",
"MC-email": "📮 E-mail: {}",
"MC-address": "🏡 Address: {}",
"MC-note": "📝 Notiz: {}",
"MC-url": "🔗 URL: {}",
"MC-organisation": "💼 Arbeitsplatz: {}",
"VE-summary": "🎯 Zusammenfassung: {}",
"VE-location": "🗺 Ort: {}",
"VE-description": "📜 Beschreibung: {}",
"VE-start": "➡ Start: {}",
"VE-end": "⬅ Ende: {}",
"_cls_doc": "Entziffere QR-Codes.",
"_cmd_doc_scancode": "Scanne einen QR-Code"
}
# noinspection PyCallingNonCallable
async def scancodecmd(self, m: Message):
"""Scan a QR code."""
reply = await m.get_reply_message()
if not reply:
return await utils.answer(m, self.strings("media?", m))
if not (await check_photo(reply)):
return await utils.answer(m, self.strings("qr?!", m))
await utils.answer(m, self.strings("uploading", m))
file = await m.client.download_file(reply.photo, bytes)
path = requests.post(
"https://te.legra.ph/upload", files={"file": ("file", file, None)}
).json()
try:
link = "https://te.legra.ph" + path[0]["src"]
except KeyError:
link = path["error"]
await utils.answer(m, self.strings("decoding"))
path = urllib.parse.quote_plus(link)
url = f"https://api.qrserver.com/v1/read-qr-code/?fileurl={path}"
try:
r = requests.get(url).json()
except Exception as e:
logging.error(e)
return await utils.answer(m, self.strings("error").format(f'{e}'))
if r[0]["symbol"][0]["error"]:
return await utils.answer(m, self.strings("qr?!"))
r = r[0]["symbol"][0]["data"]
await utils.answer(m, self.strings("processing"))
res = ''
if len(r.split('\nQR-Code:')) > 1:
r = r.split('\nQR-Code:')
for i in r:
res += f'{self.strings("qr")}\n{self.classify(i)}\n\n'
else:
res = f"{self.strings('qr')}\n{str(self.classify(r))}"
await utils.answer(m, f'{self.strings("result")}\n\n{res}')
# noinspection PyCallingNonCallable
def classify(self, r: str):
if_url = urllib.parse.urlparse(r)
if all([if_url.scheme, if_url.netloc]):
r = self.strings("url").format(r)
elif Parsers.parse_mecard(r):
mecard = Parsers.parse_mecard(r)
r = ''
for key, value in mecard.items():
r = r + self.strings(f"MC-{key}").format(value) + '\n'
r = self.strings("contact").format(r)
elif Parsers.parse_wifi(r):
wifi = Parsers.parse_wifi(r)
r = self.strings("wifi").format(wifi["ssid"], wifi["password"], wifi["encryption"])
elif Parsers.parse_geo(r):
r = Parsers.parse_geo(r)
r = self.strings("geolocation").format(r[0]['lat'], r[0]['lon'])
elif Parsers.parse_sms(r):
r = self.strings("sms").format(Parsers.parse_sms(r)["message"], Parsers.parse_sms(r)["phone"])
elif Parsers.parse_phone(r):
r = Parsers.parse_phone(r)
r = self.strings("phone").format(r["phone"])
elif Parsers.parse_email(r):
if len(list(Parsers.parse_email(r).keys())) > 1:
r = self.strings("email_exp").format(
Parsers.parse_email(r)["email"],
Parsers.parse_email(r)["subject"],
Parsers.parse_email(r)["body"]
)
else:
r = self.strings("email").format(Parsers.parse_email(r)["email"])
elif Parsers.parse_vevent(r):
vevent = Parsers.parse_vevent(r)
r = ''
for key, value in vevent.items():
r = r + self.strings(f"VE-{key}").format(value) + '\n'
r = self.strings("calendar").format(r)
else:
r = self.strings("data").format(r)
return r