#!/usr/bin/env python3
"""Minimal receive-only SMTP server. Stores each message as a file."""
import asyncio, os, time, re, email
MAILDIR = "/home/agent/mail/inbox"
os.makedirs(MAILDIR, exist_ok=True)
HOST_NAME = "144-31-195-17.sslip.io"

async def handle(reader, writer):
    peer = writer.get_extra_info('peername')
    async def send(s):
        writer.write((s + "\r\n").encode()); await writer.drain()
    async def line():
        d = await asyncio.wait_for(reader.readline(), timeout=120)
        return d.decode('utf-8', 'replace').rstrip('\r\n')
    try:
        await send(f"220 {HOST_NAME} ESMTP ready")
        mailfrom, rcpts = "", []
        while True:
            l = await line()
            if not l: break
            u = l.upper()
            if u.startswith("EHLO"):
                await send(f"250-{HOST_NAME}"); await send("250-8BITMIME"); await send("250 SIZE 20971520")
            elif u.startswith("HELO"): await send(f"250 {HOST_NAME}")
            elif u.startswith("MAIL FROM"):
                mailfrom = l[10:].strip(); await send("250 OK")
            elif u.startswith("RCPT TO"):
                rcpts.append(l[8:].strip()); await send("250 OK")
            elif u.startswith("DATA"):
                await send("354 End data with <CR><LF>.<CR><LF>")
                buf = []
                while True:
                    dl = await line()
                    if dl == ".": break
                    buf.append(dl[1:] if dl.startswith("..") else dl)
                raw = "\n".join(buf)
                ts = time.strftime("%Y%m%d-%H%M%S")
                safe = re.sub(r'[^A-Za-z0-9]+', '_', (rcpts[0] if rcpts else 'none'))[:40]
                fn = f"{MAILDIR}/{ts}-{safe}-{int(time.time()*1000)%100000}.eml"
                with open(fn, "w") as f:
                    f.write(f"X-Peer: {peer}\nX-MailFrom: {mailfrom}\nX-RcptTo: {', '.join(rcpts)}\n{raw}")
                print(f"[{ts}] stored {fn} from={mailfrom} to={rcpts}", flush=True)
                await send("250 OK queued")
                mailfrom, rcpts = "", []
            elif u.startswith("RSET"): mailfrom, rcpts = "", []; await send("250 OK")
            elif u.startswith("NOOP"): await send("250 OK")
            elif u.startswith("QUIT"): await send("221 Bye"); break
            else: await send("250 OK")
    except Exception as e:
        print("err", e, flush=True)
    finally:
        try: writer.close()
        except: pass

async def main():
    s = await asyncio.start_server(handle, "0.0.0.0", 25)
    print("listening on :25", flush=True)
    async with s: await s.serve_forever()

asyncio.run(main())
