151 lines
5.0 KiB
PHP
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());
|
|
}
|
|
}
|