diff --git a/db/migrations/002_add_attachments_to_manual_emails.sql b/db/migrations/002_add_attachments_to_manual_emails.sql new file mode 100644 index 0000000..5e70822 --- /dev/null +++ b/db/migrations/002_add_attachments_to_manual_emails.sql @@ -0,0 +1 @@ +ALTER TABLE `manual_emails` ADD `attachments` TEXT NULL DEFAULT NULL AFTER `message`; diff --git a/lang/ar.php b/lang/ar.php index 5bff107..a6ad0e8 100644 --- a/lang/ar.php +++ b/lang/ar.php @@ -21,8 +21,8 @@ $lang = [ "select_message_for_replies" => "اختر رسالة لعرض الردود المقترحة.", // Manual Email - "option_1" => "الخيار 1: رفع ملف بريد إلكتروني", - "choose_email_file" => "اختر ملفًا (.eml, .txt, .pdf, .doc, .docx)", + "option_1" => "الخيار 1: رفع ملف", + "choose_email_file" => "اختر ملفًا (.eml, .txt, .pdf, .doc, .docx, .xls, .xlsx)", "analyze_and_populate" => "تحليل الملف وتعبئة الحقول", "option_2" => "الخيار 2: إدخال يدوي", "from" => "من", @@ -45,8 +45,14 @@ $lang = [ "english" => "English", "french" => "Français", - // أخطاء تحميل الملفات - "unsupported_file_type" => "نوع الملف غير مدعوم. يرجى رفع ملف من نوع .eml, .txt, .pdf, .doc, or .docx.", - "error_parsing_file" => "تعذر استخراج النص من الملف. قد يكون فارغًا أو تالفًا أو محميًا بكلمة مرور." + // File Upload Errors + "unsupported_file_type" => "نوع الملف غير مدعوم. يرجى رفع ملف مدعوم.", + "error_parsing_file" => "تعذر استخراج النص من الملف. قد يكون فارغًا أو تالفًا أو محميًا بكلمة مرور.", + "excel_conversion_failed" => "فشل تحويل ملف Excel. قد لا تكون الأداة مثبتة أو أن الملف تالف.", + "file_upload_error" => "خطأ في تحميل الملف: ", + + // Attachments + "attachments" => "المرفقات", + "drop_files_here" => "اسحب وأفلت الملفات هنا أو انقر للاختيار" ]; ?> \ No newline at end of file diff --git a/lang/en.php b/lang/en.php index 35e1a2e..612ddd1 100644 --- a/lang/en.php +++ b/lang/en.php @@ -21,8 +21,8 @@ $lang = [ "select_message_for_replies" => "Select a message to display suggested replies.", // Manual Email - "option_1" => "Option 1: Upload Email File", - "choose_email_file" => "Choose a file (.eml, .txt, .pdf, .doc, .docx)", + "option_1" => "Option 1: Upload File", + "choose_email_file" => "Choose a file (.eml, .txt, .pdf, .doc, .docx, .xls, .xlsx)", "analyze_and_populate" => "Analyze and Populate Fields", "option_2" => "Option 2: Manual Entry", "from" => "From", @@ -46,7 +46,13 @@ $lang = [ "french" => "Français", // File Upload Errors - "unsupported_file_type" => "Unsupported file type. Please upload a .eml, .txt, .pdf, .doc, or .docx file.", - "error_parsing_file" => "Could not extract text from the file. It might be empty, corrupted, or password-protected." + "unsupported_file_type" => "Unsupported file type. Please upload a supported file.", + "error_parsing_file" => "Could not extract text from the file. It might be empty, corrupted, or password-protected.", + "excel_conversion_failed" => "Failed to convert Excel file. The tool might not be installed or the file is corrupted.", + "file_upload_error" => "File upload error: ", + + // Attachments + "attachments" => "Attachments", + "drop_files_here" => "Drag & drop files here or click to select" ]; ?> \ No newline at end of file diff --git a/lang/fr.php b/lang/fr.php index c74ce7b..f82ee9e 100644 --- a/lang/fr.php +++ b/lang/fr.php @@ -21,8 +21,8 @@ $lang = [ "select_message_for_replies" => "Sélectionnez un message pour afficher les réponses suggérées.", // Manual Email - "option_1" => "Option 1 : Télécharger un fichier e-mail", - "choose_email_file" => "Choisissez un fichier (.eml, .txt, .pdf, .doc, .docx)", + "option_1" => "Option 1 : Télécharger un fichier", + "choose_email_file" => "Choisissez un fichier (.eml, .txt, .pdf, .doc, .docx, .xls, .xlsx)", "analyze_and_populate" => "Analyser et remplir les champs", "option_2" => "Option 2 : Saisie manuelle", "from" => "De", @@ -45,8 +45,14 @@ $lang = [ "english" => "English", "french" => "Français", - // Erreurs de téléchargement de fichiers - "unsupported_file_type" => "Type de fichier non pris en charge. Veuillez télécharger un fichier .eml, .txt, .pdf, .doc ou .docx.", - "error_parsing_file" => "Impossible d'extraire le texte du fichier. Il est peut-être vide, corrompu ou protégé par un mot de passe." + // File Upload Errors + "unsupported_file_type" => "Type de fichier non pris en charge. Veuillez télécharger un fichier pris en charge.", + "error_parsing_file" => "Impossible d'extraire le texte du fichier. Il est peut-être vide, corrompu ou protégé par un mot de passe.", + "excel_conversion_failed" => "Échec de la conversion du fichier Excel. L'outil n'est peut-être pas installé ou le fichier est corrompu.", + "file_upload_error" => "Erreur de téléchargement de fichier : ", + + // Attachments + "attachments" => "Pièces jointes", + "drop_files_here" => "Glissez-déposez les fichiers ici ou cliquez pour sélectionner" ]; ?> \ No newline at end of file diff --git a/manual_email.php b/manual_email.php index c1157a9..bc27af7 100644 --- a/manual_email.php +++ b/manual_email.php @@ -18,7 +18,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['email_file']) && $_F $subject = pathinfo($file_name, PATHINFO_FILENAME); // Use filename as subject by default $from = ''; // From is not available in these files - // IMPORTANT: Ensure the temp file path is properly escaped to prevent command injection $escaped_path = escapeshellarg($file_tmp_path); switch ($file_ext) { @@ -31,11 +30,21 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['email_file']) && $_F case 'doc': $message = shell_exec("antiword " . $escaped_path); break; + case 'xls': + case 'xlsx': + $output_path = sys_get_temp_dir() . '/' . uniqid() . '.csv'; + shell_exec("ssconvert " . $escaped_path . " " . $output_path); + if (file_exists($output_path)) { + $message = file_get_contents($output_path); + unlink($output_path); + } else { + $upload_error = t('excel_conversion_failed'); + } + break; case 'eml': case 'txt': $file_content = file_get_contents($file_tmp_path); if ($file_content) { - // Basic EML parsing $body_started = false; $body_lines = []; $lines = explode("\n", $file_content); @@ -47,7 +56,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['email_file']) && $_F } elseif (preg_match('/^Subject:\s*(.*)/i', $line, $matches)) { $subject = trim($matches[1]); } elseif (trim($line) === '') { - $body_started = true; // Headers are done, body begins + $body_started = true; } } else { $body_lines[] = $line; @@ -55,16 +64,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['email_file']) && $_F } $message = implode("\n", $body_lines); } else { - $upload_error = 'Failed to read uploaded file.'; + $upload_error = t('file_read_failed'); } break; default: - $upload_error = 'Unsupported file type. Please upload a .eml, .txt, .pdf, .doc, or .docx file.'; + $upload_error = t('unsupported_file_type_parser'); break; } if (empty($message) && empty($upload_error)) { - $upload_error = 'Could not extract text from the file. It might be empty, corrupted, or password-protected.'; + $upload_error = t('text_extraction_failed'); } } elseif ($_SERVER['REQUEST_METHOD'] === 'POST') { @@ -72,12 +81,34 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['email_file']) && $_F $from = isset($_POST['from']) ? $_POST['from'] : ''; $subject = isset($_POST['subject']) ? $_POST['subject'] : ''; $message = isset($_POST['message']) ? $_POST['message'] : ''; + $attachments_list = []; + + // Handle Attachments + if (isset($_FILES['attachments'])) { + $upload_dir = 'uploads/'; + if (!is_dir($upload_dir)) { + mkdir($upload_dir, 0775, true); + } + + foreach ($_FILES['attachments']['name'] as $key => $name) { + if ($_FILES['attachments']['error'][$key] == UPLOAD_ERR_OK) { + $tmp_name = $_FILES['attachments']['tmp_name'][$key]; + // Sanitize filename + $safe_name = preg_replace('/[^A-Za-z0-9_\-\.]/', '_', basename($name)); + $destination = $upload_dir . uniqid() . '-' . $safe_name; + + if (move_uploaded_file($tmp_name, $destination)) { + $attachments_list[] = $destination; + } + } + } + } if ($from && $subject && $message) { try { $pdo = db(); - $stmt = $pdo->prepare('INSERT INTO manual_emails (sender, subject, message) VALUES (?, ?, ?)'); - $stmt->execute([$from, $subject, $message]); + $stmt = $pdo->prepare('INSERT INTO manual_emails (sender, subject, message, attachments) VALUES (?, ?, ?, ?)'); + $stmt->execute([$from, $subject, $message, json_encode($attachments_list)]); $success_message = t('email_saved_successfully'); // Clear fields after successful save $from = ''; @@ -93,7 +124,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['email_file']) && $_F $saved_emails = []; try { $pdo = db(); - $stmt = $pdo->query('SELECT sender, subject, message, created_at FROM manual_emails ORDER BY created_at DESC'); + $stmt = $pdo->query('SELECT sender, subject, message, attachments, created_at FROM manual_emails ORDER BY created_at DESC'); $saved_emails = $stmt->fetchAll(); } catch (PDOException $e) { $db_error = 'Error fetching emails: ' . $e->getMessage(); @@ -124,6 +155,24 @@ try { +
:
:
+ 0) { + echo '' . t('attachments') . ':