Frederico Falcao aacf4b23ae first commit
2025-06-17 14:20:43 +01:00

151 lines
5.0 KiB
PHP

<?php
/**
* Log a message depending on CLI or web context
*/
function log_message(string $message, bool $is_cli, ?string $target = null): void {
if ($is_cli) {
file_put_contents($target ?? '/dev/stdout', $message . PHP_EOL);
} else {
error_log($message);
}
}
/**
* Exit the script with an error message
*/
function fail(string $message, bool $is_cli, ?string $target = null, int $http_code = 400): void {
if ($is_cli) {
log_message($message, $is_cli, $target);
} else {
http_response_code($http_code);
echo $message;
}
exit(1);
}
/**
* Sanitize an email component to use in file paths
*/
function sanitize_path_part(string $part): string {
return preg_replace('/[^a-zA-Z0-9_.+-]/', '_', $part);
}
/**
* Ensure Maildir structure exists for a given email
*/
function ensure_maildir(string $maildir_path, bool $is_cli, ?string $target): void {
if (is_dir($maildir_path)) return;
if (!mkdir($maildir_path, 0775, true)) {
log_message("Failed to create Maildir structure: $maildir_path", $is_cli, $target);
return;
}
foreach (['new', 'cur', 'tmp'] as $sub) {
mkdir("$maildir_path/$sub", 0775, true);
}
}
/**
* Save an email message to a given Maildir
*/
function save_email(string $path, string $msg, bool $is_cli, ?string $target): void {
if (file_put_contents($path, $msg) === false) {
log_message("Failed to save email to $path", $is_cli, $target);
} else {
log_message("Email saved to $path", $is_cli, $target);
}
}
/**
* Get input payload depending on the environment
*/
function get_input(bool $is_cli): string {
if ($is_cli) {
$options = getopt('', ['cli']);
if (!isset($options['cli'])) {
fail("Missing --cli option for CLI execution.", true, '/dev/stderr');
}
return file_get_contents('php://stdin');
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
fail("Method not allowed. Use POST.", false, null, 405);
}
return file_get_contents('php://input');
}
/**
* Logs metadata about an incoming or outgoing email into a local SQLite3 database.
*
* This function ensures the database exists, creates the schema if it's the first run,
* extracts basic metadata (user, domain, subject, size), and inserts it into a table.
*
* @param string $email The recipient or sender email address.
* @param string $raw_msg The full raw email content.
* @param string $direction Direction of the email: 'incoming' or 'outgoing'. Default is 'incoming'.
*/
function log_email_to_sqlite(string $email, string $raw_msg, string $direction = 'incoming'): void {
$db_path = '/home/pi/emails.db';
$db_initialized = file_exists($db_path);
try {
// Open (or create) the SQLite3 database
$db = new SQLite3($db_path);
// Initialize the schema only if the database file did not previously exist
if (!$db_initialized) {
$db->exec("
CREATE TABLE emails (
id INTEGER PRIMARY KEY AUTOINCREMENT,
direction TEXT CHECK(direction IN ('incoming', 'outgoing')) NOT NULL,
user TEXT,
domain TEXT,
subject TEXT,
date TEXT,
attachments_no INTEGER,
sizeKb INTEGER
)
");
}
// Extract local part and domain from the email address
$local = preg_replace('/[^a-zA-Z0-9_.+-]/', '_', strstr($email, '@', true));
$domain = preg_replace('/[^a-zA-Z0-9_.+-]/', '_', substr(strstr($email, '@'), 1));
// Attempt to parse the Subject header from the raw message
$subject = '';
if (preg_match('/^Subject:\s*(.*)$/mi', $raw_msg, $matches)) {
$subject = trim($matches[1]);
}
// Calculate message size in kilobytes
$size_kb = (int)(strlen($raw_msg) / 1024);
// Use the current timestamp as the 'date'
$timestamp = date('Y-m-d H:i:s');
// Prepare and execute the insert query
$stmt = $db->prepare("
INSERT INTO emails (direction, user, domain, subject, date, attachments_no, sizeKb)
VALUES (:direction, :user, :domain, :subject, :date, :attachments, :size)
");
$stmt->bindValue(':direction', $direction, SQLITE3_TEXT);
$stmt->bindValue(':user', $local, SQLITE3_TEXT);
$stmt->bindValue(':domain', $domain, SQLITE3_TEXT);
$stmt->bindValue(':subject', $subject, SQLITE3_TEXT);
$stmt->bindValue(':date', $timestamp, SQLITE3_TEXT);
$stmt->bindValue(':attachments', 0, SQLITE3_INTEGER); // Can be extended later to count real attachments
$stmt->bindValue(':size', $size_kb, SQLITE3_INTEGER);
$stmt->execute();
// Close the database connection
$db->close();
} catch (Exception $e) {
// Log any unexpected SQLite errors (e.g., permission issues)
error_log("SQLite error: " . $e->getMessage());
}
}