upd
This commit is contained in:
114
main.py
114
main.py
@@ -1,6 +1,9 @@
|
||||
import os
|
||||
import logging
|
||||
import subprocess
|
||||
import email
|
||||
from email import policy
|
||||
from email.parser import BytesParser
|
||||
from telegram import Update
|
||||
from telegram.ext import Application, CommandHandler, MessageHandler, filters, ContextTypes
|
||||
|
||||
@@ -32,7 +35,8 @@ async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
'Available commands:\n'
|
||||
'/start - Start the bot\n'
|
||||
'/help - Show help message\n'
|
||||
'/checkmail - Check new emails'
|
||||
'/checkmail - List new emails\n'
|
||||
'/readmail <number> - Read a specific email'
|
||||
)
|
||||
|
||||
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
@@ -41,7 +45,8 @@ async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
'Available commands:\n'
|
||||
'/start - Start the bot\n'
|
||||
'/help - Show this help message\n'
|
||||
'/checkmail - Check new emails in your mailbox\n'
|
||||
'/checkmail - List new emails in your mailbox\n'
|
||||
'/readmail <number> - Read a specific email (e.g., /readmail 1)\n'
|
||||
'\nJust send me any text and I will echo it back!'
|
||||
)
|
||||
|
||||
@@ -75,15 +80,19 @@ async def check_mail(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
|
||||
if not emails or emails == ['']:
|
||||
await update.message.reply_text("📭 No new emails!")
|
||||
# Clear stored emails
|
||||
context.user_data['emails'] = []
|
||||
return
|
||||
|
||||
# Store email list in user context for readmail command
|
||||
context.user_data['emails'] = emails
|
||||
|
||||
# Format the response
|
||||
response = f"📬 You have {len(emails)} new email(s):\n\n"
|
||||
for i, email in enumerate(emails, 1):
|
||||
for i, email_file in enumerate(emails, 1):
|
||||
# Parse email filename to extract info
|
||||
# Format: timestamp.M###P###.mail,S=size,W=size
|
||||
parts = email.split(',')
|
||||
timestamp_part = parts[0] if parts else email
|
||||
parts = email_file.split(',')
|
||||
timestamp_part = parts[0] if parts else email_file
|
||||
size_part = parts[1] if len(parts) > 1 else ""
|
||||
|
||||
# Extract size in bytes
|
||||
@@ -100,6 +109,7 @@ async def check_mail(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
|
||||
response += f"{i}. {timestamp_part} ({size_str})\n"
|
||||
|
||||
response += f"\n💡 Use /readmail <number> to read an email"
|
||||
await update.message.reply_text(response)
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
@@ -110,6 +120,97 @@ async def check_mail(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
logger.error(f"Error checking mail: {e}")
|
||||
await update.message.reply_text(f"❌ An error occurred: {str(e)}")
|
||||
|
||||
async def read_mail(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
"""Read a specific email by number."""
|
||||
# Check authorization
|
||||
if not check_authorization(update):
|
||||
await update.message.reply_text("❌ You are not authorized to use this command.")
|
||||
logger.warning(f"Unauthorized access attempt by user {update.effective_user.id}")
|
||||
return
|
||||
|
||||
# Check if user has checked mail first
|
||||
if 'emails' not in context.user_data or not context.user_data['emails']:
|
||||
await update.message.reply_text("📭 Please use /checkmail first to see available emails.")
|
||||
return
|
||||
|
||||
# Parse email number from command
|
||||
if not context.args:
|
||||
await update.message.reply_text("❌ Please specify an email number. Usage: /readmail 1")
|
||||
return
|
||||
|
||||
try:
|
||||
email_num = int(context.args[0])
|
||||
emails = context.user_data['emails']
|
||||
|
||||
if email_num < 1 or email_num > len(emails):
|
||||
await update.message.reply_text(f"❌ Invalid email number. Please choose between 1 and {len(emails)}")
|
||||
return
|
||||
|
||||
# Get the email filename (array is 0-indexed)
|
||||
email_filename = emails[email_num - 1]
|
||||
email_path = f"/var/mail/fymio.us/me/new/{email_filename}"
|
||||
|
||||
# Read email content using docker exec
|
||||
result = subprocess.run(
|
||||
['docker', 'exec', 'mailserver', 'cat', email_path],
|
||||
capture_output=True,
|
||||
timeout=10
|
||||
)
|
||||
|
||||
if result.returncode != 0:
|
||||
await update.message.reply_text(f"❌ Error reading email:\n`{result.stderr.decode()}`", parse_mode='Markdown')
|
||||
return
|
||||
|
||||
# Parse email
|
||||
msg = BytesParser(policy=policy.default).parsebytes(result.stdout)
|
||||
|
||||
# Extract email details
|
||||
subject = msg.get('Subject', 'No Subject')
|
||||
from_addr = msg.get('From', 'Unknown')
|
||||
to_addr = msg.get('To', 'Unknown')
|
||||
date = msg.get('Date', 'Unknown')
|
||||
|
||||
# Get email body
|
||||
body = ""
|
||||
if msg.is_multipart():
|
||||
for part in msg.walk():
|
||||
content_type = part.get_content_type()
|
||||
if content_type == "text/plain":
|
||||
try:
|
||||
body = part.get_content()
|
||||
break
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
body = msg.get_content()
|
||||
except:
|
||||
body = "Could not extract email body"
|
||||
|
||||
# Truncate body if too long (Telegram has message length limits)
|
||||
max_body_length = 3000
|
||||
if len(body) > max_body_length:
|
||||
body = body[:max_body_length] + "\n\n... (truncated)"
|
||||
|
||||
# Format response
|
||||
response = f"📧 **Email #{email_num}**\n\n"
|
||||
response += f"**From:** {from_addr}\n"
|
||||
response += f"**To:** {to_addr}\n"
|
||||
response += f"**Date:** {date}\n"
|
||||
response += f"**Subject:** {subject}\n"
|
||||
response += f"\n━━━━━━━━━━━━━━━━━━\n\n"
|
||||
response += body
|
||||
|
||||
await update.message.reply_text(response, parse_mode='Markdown')
|
||||
|
||||
except ValueError:
|
||||
await update.message.reply_text("❌ Invalid email number. Please provide a number.")
|
||||
except subprocess.TimeoutExpired:
|
||||
await update.message.reply_text("❌ Command timed out while reading email.")
|
||||
except Exception as e:
|
||||
logger.error(f"Error reading mail: {e}")
|
||||
await update.message.reply_text(f"❌ An error occurred: {str(e)}")
|
||||
|
||||
async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
"""Echo the user message."""
|
||||
await update.message.reply_text(f"You said: {update.message.text}")
|
||||
@@ -127,6 +228,7 @@ def main():
|
||||
application.add_handler(CommandHandler("start", start))
|
||||
application.add_handler(CommandHandler("help", help_command))
|
||||
application.add_handler(CommandHandler("checkmail", check_mail))
|
||||
application.add_handler(CommandHandler("readmail", read_mail))
|
||||
application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, echo))
|
||||
|
||||
# Start the Bot
|
||||
|
||||
Reference in New Issue
Block a user