From c4b0cca2779f5b5be7d7926f8309061f12280bfe Mon Sep 17 00:00:00 2001 From: kevin Date: Tue, 4 Feb 2025 20:29:36 +0100 Subject: [PATCH] v3 --- Main.py | 125 ++--------------------- __pycache__/controlador.cpython-313.pyc | Bin 0 -> 1462 bytes __pycache__/modelo.cpython-313.pyc | Bin 0 -> 5707 bytes __pycache__/vista.cpython-313.pyc | Bin 0 -> 10288 bytes controlador.py | 17 ++++ modelo.py | 110 +++++++++++++++++++++ vista.py | 126 ++++++++++++++++++++++++ 7 files changed, 262 insertions(+), 116 deletions(-) create mode 100644 __pycache__/controlador.cpython-313.pyc create mode 100644 __pycache__/modelo.cpython-313.pyc create mode 100644 __pycache__/vista.cpython-313.pyc create mode 100644 controlador.py create mode 100644 modelo.py create mode 100644 vista.py diff --git a/Main.py b/Main.py index 0bf156b..cfabf3a 100644 --- a/Main.py +++ b/Main.py @@ -1,117 +1,10 @@ -import poplib -import email -import pymongo -from email.utils import parsedate_to_datetime +import tkinter as tk +from controlador import CorreoControlador +from vista import CorreoVista -# Configuración del servidor POP3 (Sin SSL) -POP3_SERVER = "192.168.120.103" -POP3_PORT = 110 # Puerto POP3 estándar sin SSL -EMAIL_USER = "kevin@psp.ieslamar.org" -EMAIL_PASS = "1234" - -# Configuración de la base de datos MongoDB -MONGO_CLIENT = "mongodb://localhost:27017/" -DB_NAME = "correo_db" -COLLECTION_NAME = "correos" - -# Conectar a MongoDB -client = pymongo.MongoClient(MONGO_CLIENT) -db = client[DB_NAME] -collection = db[COLLECTION_NAME] - -def correo_existe(remitente, asunto, fecha): - """ Verifica si un correo ya existe en la base de datos. """ - return collection.find_one({"remitente": remitente, "asunto": asunto, "fecha": fecha}) is not None - -def guardar_correo(remitente, asunto, fecha, cuerpo): - """ Guarda un correo en la base de datos si no existe. """ - if correo_existe(remitente, asunto, fecha): - print("⚠️ Correo ya guardado, se omite.") - return - - correo = { - "remitente": remitente, - "asunto": asunto, - "fecha": fecha, - "cuerpo": cuerpo - } - collection.insert_one(correo) - print("✅ Correo guardado en la base de datos.") - -def descargar_correos(): - """ Descarga correos desde el servidor y solo guarda los nuevos. """ - try: - print("📡 Conectando al servidor POP3 para descargar correos...\n") - mail = poplib.POP3(POP3_SERVER, POP3_PORT) - mail.user(EMAIL_USER) - mail.pass_(EMAIL_PASS) - - num_mensajes = len(mail.list()[1]) - print(f"📩 Se encontraron {num_mensajes} correos en la bandeja de entrada.\n") - - for i in range(1, num_mensajes + 1): - response, lines, octets = mail.retr(i) - raw_email = b"\n".join(lines) - msg = email.message_from_bytes(raw_email) - - remitente = msg["From"] - asunto = msg["Subject"] - fecha = msg["Date"] - - if fecha: - try: - fecha = parsedate_to_datetime(fecha).strftime("%Y-%m-%d %H:%M:%S") - except Exception: - pass - - cuerpo = "" - if msg.is_multipart(): - for part in msg.walk(): - if part.get_content_type() == "text/plain": - cuerpo = part.get_payload(decode=True).decode(errors="ignore") - break - else: - cuerpo = msg.get_payload(decode=True).decode(errors="ignore") - - guardar_correo(remitente, asunto, fecha, cuerpo.strip()) - - mail.quit() - print("✅ Descarga de correos completada.\n") - - except Exception as e: - print(f"❌ Error al descargar correos: {e}") - -def mostrar_correos(): - """ Muestra todos los correos almacenados en MongoDB. """ - print("📂 Mostrando correos almacenados en la base de datos...\n") - correos = collection.find() - - for correo in correos: - print(f"📅 Fecha: {correo['fecha']}") - print(f"🔹 Remitente: {correo['remitente']}") - print(f"📌 Asunto: {correo['asunto']}") - print(f"📝 Mensaje:\n{correo['cuerpo']}") - print("-" * 40) - -def menu(): - """ Menú interactivo para ejecutar las opciones del programa. """ - while True: - print("\n📬 MENÚ:") - print("1. Descargar correos nuevos") - print("2. Mostrar correos almacenados") - print("3. Salir") - - opcion = input("Seleccione una opción: ") - - if opcion == "1": - descargar_correos() - elif opcion == "2": - mostrar_correos() - elif opcion == "3": - print("👋 Saliendo...") - break - else: - print("❌ Opción no válida, intente de nuevo.") - -# Ejecutar el menú interactivo -menu() +if __name__ == "__main__": + root = tk.Tk() + controlador = CorreoControlador() + vista = CorreoVista(root, controlador) + controlador.vista = vista + root.mainloop() diff --git a/__pycache__/controlador.cpython-313.pyc b/__pycache__/controlador.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8fecb21b0fe0690d6eb7c4971bac170731ac0a6c GIT binary patch literal 1462 zcmbVM&uiR96rRyaYk61B+GLZuZm3l|3CK96!MKM|3MCDcxY>Y}J!N5#3O_LVm(kc@9R}QIVE7y=zA=VD=@77d z6LrCDKY?n4-922JL!YG0;=^xUw#i$b z0kk2juH>vYd1h)EFKa@%*<5(7)7BDn=e}HxlFsc!eg)C0?A*{HM5%&Ebu`R&!Xr{M z-~N!CS$Kl3qk6<%o}c(7d2Iev@1uJ>BSPgFWoT?5{{@1akOe}V zkTT3*L&no6nLs2;Js=IF2UKhN(ruWmQ5K5x!G z9^9)pe=~RL7hXE&cb)MaXZ)$XHFfKS)B2k}xI2#f^n$P2ba@(GKVPAq_jQs9P@fohX&j?*)Fo;_*|GbzDwV2989+i@YxVSJyB|btwJLuqB z*LCK^J|e2mp~5;e&OUj#{&2T3wcVI{-k9F9r}I2Ko*&urY`Rkkb{_9kO$fZKy_jrA zi0`mT2P+LBmLt$<93?VQLcke}o;L<^PUnQcKBiG9f;5F_v6o6M#3swnD!9`O0x6mg zJ%Z{-wr_Cj(tfpSU4Apntt$nZFfGr@`4vydKzcvI!GwIY@)$tR&{6Qr{=6Xm1zf}h cdSdeY|EX}!U$OC5?BjpUA%10_p~|=Y4^$vQTL1t6 literal 0 HcmV?d00001 diff --git a/__pycache__/modelo.cpython-313.pyc b/__pycache__/modelo.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1db84433cdbc8b634f2fcc5ee53a0aac4320087a GIT binary patch literal 5707 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 literal 0 HcmV?d00001 diff --git a/__pycache__/vista.cpython-313.pyc b/__pycache__/vista.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5cd302316ccaf10cbc724afa4430224309a82f02 GIT binary patch literal 10288 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 literal 0 HcmV?d00001 diff --git a/controlador.py b/controlador.py new file mode 100644 index 0000000..f25d05e --- /dev/null +++ b/controlador.py @@ -0,0 +1,17 @@ +from modelo import CorreoModelo +from tkinter import messagebox + +class CorreoControlador: + def __init__(self): + self.modelo = CorreoModelo() + + def descargar_correos(self): + resultado = self.modelo.descargar_correos() + if resultado is True: + messagebox.showinfo("Éxito", "Correos descargados correctamente") + else: + messagebox.showerror("Error", f"Error al descargar correos: {resultado}") + self.vista.actualizar_lista() + + def obtener_correos(self): + return self.modelo.obtener_correos() diff --git a/modelo.py b/modelo.py new file mode 100644 index 0000000..55e1524 --- /dev/null +++ b/modelo.py @@ -0,0 +1,110 @@ +import poplib +import email +import pymongo +from email.utils import parsedate_to_datetime + +class CorreoModelo: + POP3_SERVER = "192.168.120.103" + POP3_PORT = 110 + EMAIL_USER = "kevin@psp.ieslamar.org" + EMAIL_PASS = "1234" + + MONGO_CLIENT = "mongodb://localhost:27017/" + DB_NAME = "correo_db" + COLLECTION_NAME = "correos" + + def __init__(self): + self.client = pymongo.MongoClient(self.MONGO_CLIENT) + self.db = self.client[self.DB_NAME] + self.collection = self.db[self.COLLECTION_NAME] + + def correo_existe(self, remitente, asunto, fecha): + return self.collection.find_one({"remitente": remitente, "asunto": asunto, "fecha": fecha}) is not None + + def guardar_correo(self, remitente, asunto, fecha, cuerpo): + if self.correo_existe(remitente, asunto, fecha): + return + correo = {"remitente": remitente, "asunto": asunto, "fecha": fecha, "cuerpo": cuerpo} + self.collection.insert_one(correo) + + def descargar_correos(self): + try: + mail = poplib.POP3(self.POP3_SERVER, self.POP3_PORT) + mail.user(self.EMAIL_USER) + mail.pass_(self.EMAIL_PASS) + + num_mensajes = len(mail.list()[1]) + mensajes_nuevos = False + + for i in range(1, num_mensajes + 1): + response, lines, octets = mail.retr(i) + raw_email = b"\n".join(lines) + msg = email.message_from_bytes(raw_email) + + remitente = msg["From"] + asunto = msg["Subject"] + fecha = msg["Date"] + + if fecha: + try: + fecha = parsedate_to_datetime(fecha).strftime("%Y-%m-%d %H:%M:%S") + except Exception: + pass + + cuerpo = "" + if msg.is_multipart(): + for part in msg.walk(): + if part.get_content_type() == "text/plain": + cuerpo = part.get_payload(decode=True).decode(errors="ignore") + break + else: + cuerpo = msg.get_payload(decode=True).decode(errors="ignore") + + if not self.correo_existe(remitente, asunto, fecha): + self.guardar_correo(remitente, asunto, fecha, cuerpo.strip()) + mensajes_nuevos = True + + mail.quit() + return True + except Exception as e: + return str(e) + + def obtener_correos(self): + return list(self.collection.find()) + + def hay_mensajes_nuevos(self): + """ + Verifica si hay correos nuevos en el servidor POP3 que no estén en la base de datos. + """ + try: + mail = poplib.POP3(self.POP3_SERVER, self.POP3_PORT) + mail.user(self.EMAIL_USER) + mail.pass_(self.EMAIL_PASS) + + num_mensajes = len(mail.list()[1]) + + for i in range(1, num_mensajes + 1): + response, lines, octets = mail.retr(i) + raw_email = b"\n".join(lines) + msg = email.message_from_bytes(raw_email) + + remitente = msg["From"] + asunto = msg["Subject"] + fecha = msg["Date"] + + if fecha: + try: + fecha = parsedate_to_datetime(fecha).strftime("%Y-%m-%d %H:%M:%S") + except Exception: + pass + + if not self.correo_existe(remitente, asunto, fecha): + mail.quit() + return True # Hay al menos un mensaje nuevo + + mail.quit() + return False # No hay mensajes nuevos + + except Exception as e: + return False # En caso de error, asumimos que no hay nuevos mensajes + diff --git a/vista.py b/vista.py new file mode 100644 index 0000000..713effb --- /dev/null +++ b/vista.py @@ -0,0 +1,126 @@ +import tkinter as tk +from tkinter import ttk, messagebox, scrolledtext +from controlador import CorreoControlador +import threading +import time + +class CorreoVista: + def __init__(self, root, controlador): + self.root = root + self.controlador = controlador + self.root.title("📬 Gestor de Correos") + self.root.geometry("900x600") + self.root.configure(bg="#f4f4f4") + + # Frame del menú izquierdo + self.menu_frame = tk.Frame(self.root, bg="#333333", width=200) + self.menu_frame.pack(side=tk.LEFT, fill=tk.Y) + + # Botones del menú + self.btn_f1 = tk.Button(self.menu_frame, text="📋 Listado", font=("Arial", 12), bg="#555555", fg="white", relief=tk.FLAT, command=self.mostrar_frame_f1) + self.btn_f1.pack(fill=tk.X, pady=5, padx=5) + + self.btn_f2 = tk.Button(self.menu_frame, text="⚙️ Configuración", font=("Arial", 12), bg="#555555", fg="white", relief=tk.FLAT, command=self.mostrar_frame_f2) + self.btn_f2.pack(fill=tk.X, pady=5, padx=5) + + # Frame principal derecho + self.main_frame = tk.Frame(self.root, bg="#f4f4f4") + self.main_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True) + + # Barra inferior + self.footer_frame = tk.Frame(self.root, bg="#1E90FF", height=30) + self.footer_frame.place(relx=0, rely=1.0, relwidth=1, anchor="sw") + + self.footer_label = tk.Label(self.footer_frame, text="Gestor de Correos - 2025", bg="#1E90FF", fg="white", font=("Arial", 10)) + self.footer_label.pack(side=tk.RIGHT, padx=10) + + # Frames individuales para cada sección + self.frame_f1 = tk.Frame(self.main_frame, bg="#f4f4f4") + self.frame_f2 = tk.Frame(self.main_frame, bg="#f4f4f4") + + self.crear_frame_f1() + self.crear_frame_f2() + + # Mostrar el primer frame por defecto + self.frame_f1.pack(fill=tk.BOTH, expand=True) + + # Iniciar el hilo de actualización de la barra + self.ejecutar_hilo_actualizacion_barra() + + def mostrar_frame_f1(self): + self.frame_f2.pack_forget() + self.frame_f1.pack(fill=tk.BOTH, expand=True) + + def mostrar_frame_f2(self): + self.frame_f1.pack_forget() + self.frame_f2.pack(fill=tk.BOTH, expand=True) + + def crear_frame_f1(self): + frame_top = tk.Frame(self.frame_f1, bg="#f4f4f4") + frame_top.pack(pady=10, fill=tk.X) + + btn_descargar = ttk.Button(frame_top, text="📥 Descargar Correos", command=self.controlador.descargar_correos) + btn_descargar.pack(side=tk.LEFT, padx=10) + + btn_mostrar = ttk.Button(frame_top, text="🔍 Mostrar Correo", command=self.mostrar_correo) + btn_mostrar.pack(side=tk.LEFT, padx=10) + + frame_list = tk.Frame(self.frame_f1, bg="#ffffff", bd=2, relief=tk.GROOVE) + frame_list.pack(fill=tk.BOTH, expand=True, padx=10, pady=5) + + self.tree = ttk.Treeview(frame_list, columns=("Remitente", "Asunto", "Fecha", "Cuerpo"), show="headings") + self.tree.heading("Remitente", text="✉️ Remitente") + self.tree.heading("Asunto", text="📌 Asunto") + self.tree.heading("Fecha", text="📅 Fecha") + self.tree.heading("Cuerpo", text="📝 Cuerpo") + self.tree.pack(fill=tk.BOTH, expand=True) + + frame_details = tk.Frame(self.frame_f1, bg="#ffffff", bd=2, relief=tk.GROOVE) + frame_details.pack(fill=tk.BOTH, expand=True, padx=10, pady=5) + + self.detalle_text = scrolledtext.ScrolledText(frame_details, wrap=tk.WORD, height=10, font=("Arial", 10)) + self.detalle_text.pack(fill=tk.BOTH, expand=True) + + def crear_frame_f2(self): + label_config = tk.Label(self.frame_f2, text="⚙️ Configuración", font=("Arial", 16), bg="#f4f4f4") + label_config.pack(pady=20) + + def mostrar_correo(self): + seleccionado = self.tree.selection() + if not seleccionado: + messagebox.showwarning("⚠️ Advertencia", "Seleccione un correo") + return + + correo_id = seleccionado[0] + correo = self.tree.item(correo_id, "values") + + self.detalle_text.delete("1.0", tk.END) + self.detalle_text.insert(tk.END, f"📧 Remitente: {correo[0]}\n") + self.detalle_text.insert(tk.END, f"📌 Asunto: {correo[1]}\n") + self.detalle_text.insert(tk.END, f"📅 Fecha: {correo[2]}\n\n") + self.detalle_text.insert(tk.END, f"📝 Mensaje:\n{correo[3]}") + + def actualizar_lista(self): + self.tree.delete(*self.tree.get_children()) + for correo in self.controlador.obtener_correos(): + self.tree.insert("", "end", values=(correo["remitente"], correo["asunto"], correo["fecha"], correo["cuerpo"])) + + def ejecutar_hilo_actualizacion_barra(self): + """ Inicia un hilo para actualizar el color de la barra inferior cada 5 segundos. """ + hilo = threading.Thread(target=self.actualizar_barra_periodicamente, daemon=True) + hilo.start() + + def actualizar_barra_periodicamente(self): + """ Cambia el color de la barra inferior cada 5 segundos según si hay nuevos correos. """ + while True: + hay_nuevos = self.controlador.modelo.hay_mensajes_nuevos() + + # Cambiar color de la barra en el hilo principal de Tkinter + self.root.after(0, self.cambiar_color_barra, "#FF0000" if hay_nuevos else "#1E90FF") + + time.sleep(5) # Esperar 5 segundos antes de verificar nuevamente + + def cambiar_color_barra(self, color): + """ Cambia el color de la barra inferior. """ + self.footer_frame.configure(bg=color) + self.footer_label.configure(bg=color)