diff --git a/.idea/MutiFunctionProgramProject.iml b/.idea/MutiFunctionProgramProject.iml index 07abf20..d8b3f6c 100644 --- a/.idea/MutiFunctionProgramProject.iml +++ b/.idea/MutiFunctionProgramProject.iml @@ -2,11 +2,7 @@ - + - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index db8786c..1d3ce46 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,7 +1,7 @@ - - + \ No newline at end of file diff --git a/src/resources/db_email/emails.db b/src/resources/db_email/emails.db new file mode 100644 index 0000000..3e8da67 Binary files /dev/null and b/src/resources/db_email/emails.db differ diff --git a/src/services/__pycache__/Radio_Player.cpython-313.pyc b/src/services/__pycache__/Radio_Player.cpython-313.pyc index a2bbd35..74cb7f7 100644 Binary files a/src/services/__pycache__/Radio_Player.cpython-313.pyc and b/src/services/__pycache__/Radio_Player.cpython-313.pyc differ diff --git a/src/services/__pycache__/email_client_pop.cpython-313.pyc b/src/services/__pycache__/email_client_pop.cpython-313.pyc new file mode 100644 index 0000000..1cb6d17 Binary files /dev/null and b/src/services/__pycache__/email_client_pop.cpython-313.pyc differ diff --git a/src/services/__pycache__/scrapper.cpython-313.pyc b/src/services/__pycache__/scrapper.cpython-313.pyc index 6c9e88b..dc095e1 100644 Binary files a/src/services/__pycache__/scrapper.cpython-313.pyc and b/src/services/__pycache__/scrapper.cpython-313.pyc differ diff --git a/src/services/__pycache__/tetris_game.cpython-313.pyc b/src/services/__pycache__/tetris_game.cpython-313.pyc index 6610eca..3f8f3af 100644 Binary files a/src/services/__pycache__/tetris_game.cpython-313.pyc and b/src/services/__pycache__/tetris_game.cpython-313.pyc differ diff --git a/src/services/__pycache__/threads_manager.cpython-313.pyc b/src/services/__pycache__/threads_manager.cpython-313.pyc index 103a7ae..1040893 100644 Binary files a/src/services/__pycache__/threads_manager.cpython-313.pyc and b/src/services/__pycache__/threads_manager.cpython-313.pyc differ diff --git a/src/services/email_client_pop.py b/src/services/email_client_pop.py index 5c6ce9d..11cc23d 100644 --- a/src/services/email_client_pop.py +++ b/src/services/email_client_pop.py @@ -8,10 +8,11 @@ from email.mime.multipart import MIMEMultipart import sqlite3 from datetime import datetime + class EmailClientPOP: - def __init__(self, pop_server, smtp_server, email, password, pop_port = 110, smtp_port=25): + def __init__(self, pop_server, smtp_server, email, password, pop_port=110, smtp_port=25): self.pop_server = pop_server - self.smtp = smtp_server + self.smtp_server = smtp_server self.email = email self.password = password self.pop_port = pop_port @@ -19,7 +20,7 @@ class EmailClientPOP: self.pop_conn = None self.smtp_conn = None - #Ruta del archivo SQLite: + # Ruta del archivo SQLite: self.db_file = os.path.join("resources/db_email", "emails.db") self.init_database() @@ -40,8 +41,169 @@ class EmailClientPOP: received_at DATETIME ) """) + cursor.execute(""" + CREATE TABLE IF NOT EXISTS sent_emails ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + recipient TEXT NOT NULL, + subject TEXT, + body TEXT, + sent_at DATETIME + ) + """) conn.commit() conn.close() print(f"Base de datos inicializada: {self.db_file}") except sqlite3.Error as e: - print(f"Error al inicializar la base de datos: {e}") \ No newline at end of file + print(f"Error al inicializar la base de datos: {e}") + + def connect_pop(self): + """Conexión al servidor POP""" + try: + self.pop_conn = poplib.POP3(self.pop_server, self.pop_port) + self.pop_conn.user(self.email) + self.pop_conn.pass_(self.password) + print("Conexión POP exitosa") + except Exception as e: + print(f"Error al conectar al servidor POP: {e}") + self.pop_conn = None + + def connect_smtp(self): + """Conexión al servidor SMTP""" + try: + self.smtp_conn = smtplib.SMTP(self.smtp_server, self.smtp_port) + self.smtp_conn.login(self.email, self.password) + print("Conexión SMTP exitosa") + except Exception as e: + print(f"Error al conectar al servidor SMTP: {e}") + self.smtp_conn = None + + def is_connected(self): + """Verifica si hay una conexión válida tanto de POP como de SMTP""" + return self.pop_conn is not None and self.smtp_conn is not None + + def reconnect(self): + """Intenta reconectar a los servidores POP y SMTP""" + print("Intentando reconectar al servidor de correo...") + self.connect_pop() + self.connect_smtp() + + def fetch_unread_count(self): + """Obtener el número de correos (POP3 no distingue entre leídos y no leídos)""" + try: + if not self.pop_conn: + self.connect_pop() + num_messages = len(self.pop_conn.list()[1]) + return num_messages # Total de mensajes + except Exception as e: + print(f"Error al obtener el conteo de correos: {e}") + return 0 + + def fetch_emails(self, save_to_db=True): + """Obtiene correos desde el servidor POP""" + try: + if not self.pop_conn: + self.connect_pop() + + emails = [] + num_messages = len(self.pop_conn.list()[1]) + for i in range(1, num_messages + 1): + raw_messages = b"\n".join(self.pop_conn.retr(i)[1]) + msg = email.message_from_bytes(raw_messages) + subject, encoding = decode_header(msg["Subject"])[0] + if isinstance(subject, bytes): + subject = subject.decode(encoding or "utf-8") + sender = msg.get("From") + body = "" + if msg.is_multipart(): + for part in msg.walk(): + if part.get_content_type() == "text/plain": + body = part.get_payload(decode=True).decode("utf-8", errors="ignore") + else: + body = msg.get_payload(decode=True).decode("utf-8", errors="ignore") + + email_data = { + "sender": sender, + "subject": subject, + "body": body, + "received_at": datetime.now().isoformat() + } + emails.append(email_data) + + if save_to_db: + self.save_email_to_db(email_data) + + return emails + except Exception as e: + print(f"Error al obtener los correos: {e}") + return [] + + def fetch_folders(self): + """POP3 no tiene carpetas, devuelve un mensaje indicando esto""" + print("El protocolo POP3 no soporta carpetas. Devuelve solo la bandeja de entrada.") + return ["INBOX"] + + def save_email_to_db(self, email_data): + """Guarda un correo recibido en la base de datos.""" + try: + conn = sqlite3.connect(self.db_file) + cursor = conn.cursor() + cursor.execute(""" + INSERT INTO emails (sender, subject, body, received_at) + VALUES (?, ?, ?, ?) + """, (email_data["sender"], email_data["subject"], email_data["body"], email_data["received_at"])) + conn.commit() + conn.close() + print("Correo recibido guardado en la base de datos.") + except sqlite3.Error as e: + print(f"Error al guardar correo recibido: {e}") + + def send_mail(self, recipient, subject, body, save_to_db=True): + """Envía un correo usando SMTP""" + try: + if not self.smtp_conn: + self.connect_smtp() + + msg = MIMEMultipart() + msg["From"] = self.email + msg["To"] = recipient + msg["Subject"] = subject + msg.attach(MIMEText(body, "plain")) + self.smtp_conn.sendmail(self.email, recipient, msg.as_string()) + print(f"Correo ha sido enviado a {recipient}") + + if save_to_db: + self.save_sent_mail_to_db({ + "recipient": recipient, + "subject": subject, + "body": body, + "sent_at": datetime.now().isoformat() + }) + except Exception as e: + print(f"Error al enviar correo: {e}") + + def save_sent_mail_to_db(self, email_data): + """Guarda un correo enviado en la base de datos.""" + try: + conn = sqlite3.connect(self.db_file) + cursor = conn.cursor() + cursor.execute(""" + INSERT INTO sent_emails (recipient, subject, body, sent_at) + VALUES (?, ?, ?, ?) + """, (email_data["recipient"], email_data["subject"], email_data["body"], email_data["sent_at"])) + conn.commit() + conn.close() + print("Correo enviado guardado en la base de datos.") + except sqlite3.Error as e: + print(f"Error al guardar correo enviado: {e}") + + def list_emails(self, limit=10): + """Lista correos recientes (máximo `limit`)""" + emails = self.fetch_emails() + return emails[:limit] + + def close_connections(self): + """Cierra las conexiones POP y SMTP""" + if self.pop_conn: + self.pop_conn.quit() + if self.smtp_conn: + self.smtp_conn.quit() diff --git a/src/ui/__pycache__/centered_window.cpython-313.pyc b/src/ui/__pycache__/centered_window.cpython-313.pyc index 20a2c4c..ed43031 100644 Binary files a/src/ui/__pycache__/centered_window.cpython-313.pyc and b/src/ui/__pycache__/centered_window.cpython-313.pyc differ diff --git a/src/ui/centered_window.py b/src/ui/centered_window.py index b893300..555ff3d 100644 --- a/src/ui/centered_window.py +++ b/src/ui/centered_window.py @@ -6,7 +6,7 @@ from src.services.processes_manager import ProcessManager from src.services.system_monitor import SystemMonitor from src.services.tetris_game import TetrisGame from src.services.threads_manager import ThreadsManager -from src.services.email_client_imap import EmailClientImap +from src.services.email_client_pop import EmailClientPOP class CenteredWindow(ctk.CTk): @@ -16,9 +16,9 @@ class CenteredWindow(ctk.CTk): self.title(title) self.after_tasks = [] - #Configurar Email Client - self.email_client = EmailClientImap( - imap_server="192.168.120.103", + # Configurar Email Client IMAP + self.email_client = EmailClientPOP( + pop_server="192.168.120.103", smtp_server="192.168.120.103", email="dennis@psp.ieslamar.org", password="1234" @@ -28,21 +28,21 @@ class CenteredWindow(ctk.CTk): self.process_manager = ProcessManager() self.system_monitor = None - # Obtener la resolucion de la pantalla: + # Obtener la resolución de la pantalla: screen_width = self.winfo_screenwidth() screen_height = self.winfo_screenheight() - # Calcula el tamaño de la ventana según procentaje de la pantalla: + # Calcula el tamaño de la ventana según porcentaje de la pantalla: window_width = int(screen_width * width_percentage) window_height = int(screen_height * height_percentage) - # Calcular la posicion para centrar la ventana: + # Calcular la posición para centrar la ventana: position_x = (screen_width - window_width) // 2 position_y = (screen_height - window_height) // 2 self.geometry(f"{window_width}x{window_height}+{position_x}+{position_y}") - #Configura la ventana + # Configura la ventana self.configure_window() self.protocol("WM_DELETE_WINDOW", self.on_close) @@ -62,7 +62,6 @@ class CenteredWindow(ctk.CTk): self.thread_manager.start_threads() - def on_close(self): """Maneja el cierre de la ventana""" self.thread_manager.stop_threads() @@ -70,7 +69,7 @@ class CenteredWindow(ctk.CTk): if hasattr(self, "tetris_game") and self.tetris_game.running: self.tetris_game.stop_game() - if "tetris_game" in self.thread_manager.tasks: + if "tetris_game" in self.thread_manager.tasks: self.thread_manager.tasks["tetris_game"].stop() if hasattr(self.thread_manager, "scrapper"): @@ -91,10 +90,16 @@ class CenteredWindow(ctk.CTk): # Secciones y botones sections = { "Aplicaciones": [ - ("Abrir Chrome", lambda: self.process_manager.open_resource("browser", "https://google.com", "Cannot open browser")), - ("Visual Studio Code", lambda: self.process_manager.open_resource("program", r"C:\Program Files\Microsoft VS Code\Code.exe", "Can't find VSCode")), - ("Explorador de Windows", lambda: self.process_manager.open_resource("program", "explorer.exe", "Can't open Windows Explorer")), - ("Notepad++", lambda: self.process_manager.open_resource("program", r"C:\Program Files\Notepad++\notepad++.exe", "Can't open Notepad++")) + ("Abrir Chrome", + lambda: self.process_manager.open_resource("browser", "https://google.com", "Cannot open browser")), + ("Visual Studio Code", + lambda: self.process_manager.open_resource("program", r"C:\Program Files\Microsoft VS Code\Code.exe", + "Can't find VSCode")), + ("Explorador de Windows", + lambda: self.process_manager.open_resource("program", "explorer.exe", "Can't open Windows Explorer")), + ("Notepad++", + lambda: self.process_manager.open_resource("program", r"C:\Program Files\Notepad++\notepad++.exe", + "Can't open Notepad++")) ] } @@ -104,13 +109,13 @@ class CenteredWindow(ctk.CTk): url_entry_chrome.pack(pady=5, padx=10) # Botón para abrir la URL ingresada - internet_access_button = ctk.CTkButton( - left_panel, - text="Buscar URL", - command=lambda: self.process_manager.open_resource("browser", url_entry_chrome.get(), "Cannot open browser") - ) + internet_access_button = ctk.CTkButton( + left_panel, + text="Buscar URL", + command=lambda: self.process_manager.open_resource("browser", url_entry_chrome.get(), "Cannot open browser") + ) internet_access_button.pack(pady=5, padx=10) - + for section, buttons in sections.items(): if section: section_label = ctk.CTkLabel(left_panel, text=section, font=("Arial", 12, "bold")) @@ -122,20 +127,20 @@ class CenteredWindow(ctk.CTk): scrapping_label = ctk.CTkLabel(left_panel, text="Scrapping", font=("Arial", 12, "bold")) scrapping_label.pack(anchor=ctk.W, pady=5, padx=10) - url_entry = ctk.CTkEntry(left_panel, placeholder_text="Introduce la URL para scrapear") - url_entry.pack(pady=5, padx=10) + url_entry = ctk.CTkEntry(left_panel, placeholder_text="Introduce la URL para scrapear") + url_entry.pack(pady=5, padx=10) self.left_panel = left_panel self.left_panel.url_entry = url_entry self.left_panel.url_entry_chrome = url_entry_chrome - start_button = ctk.CTkButton(left_panel, text="Iniciar Scrapping", command=self.thread_manager.scrapper.start_scraping) + start_button = ctk.CTkButton(left_panel, text="Iniciar Scrapping", + command=self.thread_manager.scrapper.start_scraping) start_button.pack(pady=5, padx=10) - stop_button = ctk.CTkButton(left_panel, text="Detener Scrapping", command=self.thread_manager.scrapper.stop_scraping) + stop_button = ctk.CTkButton(left_panel, text="Detener Scrapping", + command=self.thread_manager.scrapper.stop_scraping) stop_button.pack(pady=5, padx=10) - - def create_center_panel(self): # Panel central con pestañas center_panel = ctk.CTkFrame(self) @@ -147,9 +152,12 @@ class CenteredWindow(ctk.CTk): # Crear pestañas y manejar contenido por separado for tab_name in ["Scrapping", "Radio", "Correos", "Juego", "Sistema"]: tab = tab_view.add(tab_name) - - if tab_name == "Radio": - self.create_radio_tab(tab) + + if tab_name == "Radio": + self.create_radio_tab(tab) + + if tab_name == "Correos": + self.create_email_tab(tab) if tab_name == "Scrapping": text_widget = ctk.CTkTextbox(tab, width=500, height=400) @@ -161,11 +169,11 @@ class CenteredWindow(ctk.CTk): if tab_name == "Sistema": # Crear un frame para los gráficos del sistema - system_frame = ctk.CTkFrame(tab) - system_frame.pack(fill=ctk.BOTH, expand=True, padx=5, pady=5) + system_frame = ctk.CTkFrame(tab) + system_frame.pack(fill=ctk.BOTH, expand=True, padx=5, pady=5) # Inicializar SystemMonitor con el frame de la pestaña - self.system_monitor = SystemMonitor(system_frame) + self.system_monitor = SystemMonitor(system_frame) # Asignar el system_monitor al thread_manager self.thread_manager.set_system_monitor(self.system_monitor) @@ -192,33 +200,25 @@ class CenteredWindow(ctk.CTk): self.tetris_game = TetrisGame(game_frame) self.tetris_game.pack() - # else: - # Agregar contenido genérico a otras pestañas - #label = ctk.CTkLabel(tab, text=f"Contenido de {tab_name}", font=("Arial", 12)) - #label.pack(pady=10) - - + # else: + # Agregar contenido genérico a otras pestañas + # label = ctk.CTkLabel(tab, text=f"Contenido de {tab_name}", font=("Arial", 12)) + # label.pack(pady=10) def start_tetris_game(self): """Método para iniciar el juego.""" if not self.tetris_game.running: self.tetris_game.running = True - #self.tetris_game.update_game() - - + # self.tetris_game.update_game() def pause_tetris_game(self): """Método para pausar el juego.""" self.tetris_game.running = False - - def restart_tetris_game(self): """Método para reiniciar el juego.""" self.tetris_game.reset_game() - - def create_right_panel(self): # Panel derecho right_panel = ctk.CTkFrame(self, width=250) @@ -236,7 +236,8 @@ class CenteredWindow(ctk.CTk): # Lista de alumnos for i in range(1, 4): - student_label = ctk.CTkLabel(right_panel, text=f"Alumno {i}", font=("Arial", 12, "bold"), text_color="black") + student_label = ctk.CTkLabel(right_panel, text=f"Alumno {i}", font=("Arial", 12, "bold"), + text_color="black") student_label.pack(anchor=ctk.W, pady=5, padx=10) student_info = ctk.CTkLabel( @@ -247,8 +248,6 @@ class CenteredWindow(ctk.CTk): ) student_info.pack(anchor=ctk.W, padx=10) - - def create_bottom_bar(self): # Crear la barra inferior self.bottom_bar = ctk.CTkFrame(self, fg_color="lightblue", height=40) @@ -258,7 +257,8 @@ class CenteredWindow(ctk.CTk): self.info_labels = { "hora": ctk.CTkLabel(self.bottom_bar, text="Hora: --:--:--", font=("Arial", 12), text_color="black"), "fecha": ctk.CTkLabel(self.bottom_bar, text="Fecha: --/--/----", font=("Arial", 12), text_color="black"), - "temperatura": ctk.CTkLabel(self.bottom_bar, text="Temperatura local: --°C", font=("Arial", 12), text_color="black"), + "temperatura": ctk.CTkLabel(self.bottom_bar, text="Temperatura local: --°C", font=("Arial", 12), + text_color="black"), "emails": ctk.CTkLabel(self.bottom_bar, text="Correos sin leer: 0", font=("Arial", 12), text_color="black"), } @@ -266,58 +266,141 @@ class CenteredWindow(ctk.CTk): for label in self.info_labels.values(): label.pack(side=ctk.LEFT, padx=10, pady=5) - - def dummy_action(self): print("Acción no implementada") - - def create_radio_tab(self, tab): - """Crea la interfaz para la funcionalidad de emisoras de radio.""" - self.radio_player = self.thread_manager.radio_player + + def create_radio_tab(self, tab): + """Crea la interfaz para la funcionalidad de emisoras de radio.""" + self.radio_player = self.thread_manager.radio_player # Lista de emisoras - radio_stations = { - "Box Radio UK": "http://uk2.internet-radio.com:8024/", - "Jazz Radio": "http://us2.internet-radio.com:8443/", - "Deep House Radio": "http://uk7.internet-radio.com:8000/", - } + radio_stations = { + "Box Radio UK": "http://uk2.internet-radio.com:8024/", + "Jazz Radio": "http://us2.internet-radio.com:8443/", + "Deep House Radio": "http://uk7.internet-radio.com:8000/", + } # Dropdown para seleccionar emisora - self.selected_station = ctk.StringVar(value="Selecciona una emisora") - station_menu = ctk.CTkOptionMenu(tab, variable=self.selected_station, values=list(radio_stations.keys())) - station_menu.pack(pady=10) + self.selected_station = ctk.StringVar(value="Selecciona una emisora") + station_menu = ctk.CTkOptionMenu(tab, variable=self.selected_station, values=list(radio_stations.keys())) + station_menu.pack(pady=10) # Botón para reproducir - play_button = ctk.CTkButton( - tab, - text="Reproducir", - command=lambda: self.start_radio(radio_stations[self.selected_station.get()]) - ) - play_button.pack(pady=5) + play_button = ctk.CTkButton( + tab, + text="Reproducir", + command=lambda: self.start_radio(radio_stations[self.selected_station.get()]) + ) + play_button.pack(pady=5) # Botón para detener - stop_button = ctk.CTkButton( - tab, - text="Detener", - command=self.stop_radio, + stop_button = ctk.CTkButton( + tab, + text="Detener", + command=self.stop_radio, state=tk.DISABLED # Deshabilitado inicialmente - ) - stop_button.pack(pady=5) + ) + stop_button.pack(pady=5) # Guardar referencias para habilitar/deshabilitar botones - self.radio_controls = {"play_button": play_button, "stop_button": stop_button} + self.radio_controls = {"play_button": play_button, "stop_button": stop_button} - def start_radio(self, url): - """Inicia la reproducción de radio y actualiza los botones.""" - if url == "Selecciona una emisora": - tk.messagebox.showwarning("Advertencia", "Por favor, selecciona una emisora válida.") - return - self.radio_player.play(url) - self.radio_controls["play_button"].configure(state=tk.DISABLED) - self.radio_controls["stop_button"].configure(state=tk.NORMAL) + def start_radio(self, url): + """Inicia la reproducción de radio y actualiza los botones.""" + if url == "Selecciona una emisora": + tk.messagebox.showwarning("Advertencia", "Por favor, selecciona una emisora válida.") + return + self.radio_player.play(url) + self.radio_controls["play_button"].configure(state=tk.DISABLED) + self.radio_controls["stop_button"].configure(state=tk.NORMAL) - def stop_radio(self): - """Detiene la reproducción de radio y actualiza los botones.""" - self.radio_player.stop() - self.radio_controls["play_button"].configure(state=tk.NORMAL) - self.radio_controls["stop_button"].configure(state=tk.DISABLED) \ No newline at end of file + def stop_radio(self): + """Detiene la reproducción de radio y actualiza los botones.""" + self.radio_player.stop() + self.radio_controls["play_button"].configure(state=tk.NORMAL) + self.radio_controls["stop_button"].configure(state=tk.DISABLED) + + def create_email_tab(self, tab): + """Crea una interfaz moderna para gestionar los correos con customtkinter.""" + # Configurar el grid para permitir que los elementos se expandan + tab.grid_columnconfigure(0, weight=1) + tab.grid_rowconfigure(0, weight=1) + + # Crear un marco principal para la pestaña + main_frame = ctk.CTkFrame(tab) + main_frame.grid(row=0, column=0, sticky="nsew", padx=10, pady=10) + + # Lista de correos en un marco + listbox_frame = ctk.CTkFrame(main_frame) + listbox_frame.grid(row=0, column=0, sticky="nsew", padx=10, pady=10) + + # Crear una lista de correos con un scrollbar + self.email_listbox = ctk.CTkTextbox(listbox_frame, width=800, height=800) + self.email_listbox.grid(row=0, column=0, sticky="nsew", padx=10, pady=10) + self.email_listbox.configure(state="disabled") # Inicialmente deshabilitada + + scrollbar = ctk.CTkScrollbar(listbox_frame, command=self.email_listbox.yview) + scrollbar.grid(row=0, column=1, sticky="ns") + self.email_listbox.configure(yscrollcommand=scrollbar.set) + + # Frame para botones de acción + button_frame = ctk.CTkFrame(main_frame) + button_frame.grid(row=1, column=0, sticky="ew", padx=10, pady=10) + + # Crear botones para acciones: Marcar como leído, Eliminar, Actualizar + mark_read_button = ctk.CTkButton( + button_frame, text="Marcar como leído", command=self.mark_email_as_read, fg_color="green" + ) + mark_read_button.grid(row=0, column=0, padx=5, pady=5, sticky="ew") + + delete_button = ctk.CTkButton( + button_frame, text="Eliminar correo", command=self.delete_email, fg_color="red" + ) + delete_button.grid(row=0, column=1, padx=5, pady=5, sticky="ew") + + refresh_button = ctk.CTkButton( + button_frame, text="Actualizar", command=self.refresh_email_list, fg_color="blue" + ) + refresh_button.grid(row=0, column=2, padx=5, pady=5, sticky="ew") + + # Expandir las filas y columnas del marco principal + main_frame.grid_rowconfigure(0, weight=1) + main_frame.grid_columnconfigure(0, weight=1) + + def refresh_email_list(self): + """Actualiza la lista de correos en la interfaz.""" + try: + if not self.email_client.is_connected(): + self.email_client.reconnect() + + if self.email_client.is_connected(): + emails = self.email_client.fetch_emails() + self.email_listbox.delete(0, tk.END) + for email in emails: + self.email_listbox.insert(tk.END, f"{email['subject']} - {email['from']}") + else: + print("No hay conexión al servidor de correo.") + except Exception as e: + print(f"Error al actualizar la lista de correos: {e}") + + def mark_email_as_read(self): + """Marca el correo seleccionado como leído.""" + selected_index = self.email_listbox.curselection() + if not selected_index: + print("No se ha seleccionado ningún correo.") + return + + selected_email = self.email_listbox.get(selected_index) + # Aquí puedes agregar la lógica para marcar el correo como leído + print(f"Correo marcado como leído: {selected_email}") + + def delete_email(self): + """Elimina el correo seleccionado.""" + selected_index = self.email_listbox.curselection() + if not selected_index: + print("No se ha seleccionado ningún correo.") + return + + selected_email = self.email_listbox.get(selected_index) + # Aquí puedes agregar la lógica para eliminar el correo + print(f"Correo eliminado: {selected_email}")