]> git.joonet.de Git - adminer.git/commitdiff
IMAP: New driver created just for fun
authorJakub Vrana <jakub@vrana.cz>
Tue, 18 Mar 2025 10:28:20 +0000 (11:28 +0100)
committerJakub Vrana <jakub@vrana.cz>
Tue, 18 Mar 2025 10:35:14 +0000 (11:35 +0100)
README.md
plugins/drivers/imap.php [new file with mode: 0644]

index a56cc2fe75709b2f2aea520e0e668af3014aef1f..62f31c6bbf463bd3ad3e12f7149d5c3f42208a1c 100644 (file)
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ to the target server. **Adminer Editor** offers data manipulation for end-users.
 https://www.adminer.org/
 
 - **Supports:** MySQL, MariaDB, PostgreSQL, CockroachDB, SQLite, MS SQL, Oracle
-- **Plugins for:** Elasticsearch, SimpleDB, MongoDB, Firebird, ClickHouse
+- **Plugins for:** Elasticsearch, SimpleDB, MongoDB, Firebird, ClickHouse, IMAP
 - **Requirements:** PHP 5.3+
 
 ## Screenshot
diff --git a/plugins/drivers/imap.php b/plugins/drivers/imap.php
new file mode 100644 (file)
index 0000000..832938e
--- /dev/null
@@ -0,0 +1,235 @@
+<?php
+/** Experimental driver for IMAP created just for fun. Features:
+* - list mailboxes with number of messages (Rows) and unread messages (Data Free)
+* - list messages in each mailbox - limit and offset works but there's no search and order
+* - for each message, there's subject, from, to, date and some flags
+* - editing the message shows some other information
+* - inserting, deleting or updating the message does nothing
+*/
+
+namespace Adminer;
+
+add_driver("imap", "IMAP");
+
+if (isset($_GET["imap"])) {
+       define('Adminer\DRIVER', "imap");
+
+       if (extension_loaded("imap")) {
+               class Db {
+                       public $extension = "IMAP";
+                       public $error;
+                       public $server_info = "?"; // imap_mailboxmsginfo() doesn't return anything useful
+                       private $mailbox;
+                       private $imap;
+
+                       function connect($server, $username, $password) {
+                               $this->mailbox = "{" . "$server:993/ssl}"; // Adminer disallows specifying privileged port in server name
+                               $this->imap = @imap_open($this->mailbox, $username, $password, 0, 1);
+                               if (!$this->imap) {
+                                       $this->error = imap_last_error();
+                               }
+                               return $this->imap;
+                       }
+
+                       function select_db($database) {
+                               return ($database == "imap");
+                       }
+
+                       function query($query, $unbuffered = false) {
+                               preg_match('~\sFROM (\w+).*?(?:\sWHERE uid = (\d+))?.*?(?:\sLIMIT (\d+)(?:\sOFFSET (\d+))?)?~s', $query, $match);
+                               list(, $table, $uid, $limit, $offset) = $match;
+                               if ($uid) {
+                                       $return = array((array) imap_fetchstructure($this->imap, $uid, FT_UID));
+                               } else {
+                                       imap_reopen($this->imap, "$this->mailbox$table");
+                                       $check = imap_check($this->imap);
+                                       $range = ($offset + 1) . ":" . ($limit ? min($check->Nmsgs, $offset + $limit) : $check->Nmsgs);
+                                       $return = array();
+                                       foreach (imap_fetch_overview($this->imap, $range) as $row) {
+                                               // imap_utf8 doesn't work with some strings
+                                               $row->subject = iconv_mime_decode($row->subject, 2, "utf-8");
+                                               $row->from = iconv_mime_decode($row->from, 2, "utf-8");
+                                               $row->to = iconv_mime_decode($row->to, 2, "utf-8");
+                                               $row->udate = gmdate("Y-m-d H:i:s", $row->udate);
+                                               $return[] = array_merge(array_fill_keys(array_keys(fields($table)), null), (array) $row);
+                                       }
+                               }
+                               return new Result($return);
+                       }
+
+                       function quote($string) {
+                               return $string;
+                       }
+
+                       function tables_list() {
+                               static $return;
+                               if ($return === null) {
+                                       $return = array();
+                                       foreach (imap_list($this->imap, $this->mailbox, "*") as $val) {
+                                               $return[substr($val, strlen($this->mailbox))] = "table";
+                                       }
+                               }
+                               return array_reverse($return);
+                       }
+
+                       function table_status($name, $fast) {
+                               if ($fast) {
+                                       return array("Name" => $name);
+                               }
+                               $return = imap_status($this->imap, $this->mailbox . $name, SA_ALL);
+                               return array(
+                                       "Name" => $name,
+                                       "Rows" => $return->messages,
+                                       "Auto_increment" => $return->uidnext,
+                                       "Data_free" => $return->unseen,
+                               );
+                       }
+               }
+
+               class Result {
+                       public $num_rows;
+                       private $result;
+
+                       function __construct($result) {
+                               $this->result = $result;
+                               $this->num_rows = count($result);
+                       }
+
+                       function fetch_assoc() {
+                               $row = current($this->result);
+                               next($this->result);
+                               return $row;
+                       }
+               }
+       }
+
+       class Driver extends SqlDriver {
+               static $possibleDrivers = array("imap");
+               static $jush = "imap";
+               public $editFunctions = array(array("json"));
+       }
+
+       function logged_user() {
+               return $_GET["username"];
+       }
+
+       function get_databases($flush) {
+               return array("imap");
+       }
+
+       function collations() {
+               return array();
+       }
+
+       function db_collation($db, $collations) {
+       }
+
+       function information_schema($db) {
+       }
+
+       function indexes($table, $connection2 = null) {
+               return array(array("type" => "PRIMARY", "columns" => array("uid")));
+       }
+
+       function fields($table) {
+               $return = array();
+               foreach (
+                       array( // taken from imap_fetch_overview
+                               'subject' => 'the messages subject',
+                               'from' => 'who sent it',
+                               'to' => 'recipient',
+                               'date' => 'when was it sent',
+                               'message_id' => 'Message-ID',
+                               'references' => 'is a reference to this message id',
+                               'in_reply_to' => 'is a reply to this message id',
+                               'size' => 'size in bytes',
+                               'uid' => 'UID the message has in the mailbox',
+                               'msgno' => 'message sequence number in the mailbox',
+                               'recent' => 'flagged as recent',
+                               'flagged' => 'flagged',
+                               'answered' => 'flagged as answered',
+                               'deleted' => 'flagged for deletion',
+                               'seen' => 'flagged as already read',
+                               'draft' => 'flagged as being a draft',
+                               'udate' => 'the GMT time of the arrival date',
+                       ) as $name => $comment
+               ) {
+                       $return[$name] = array(
+                               "field" => $name,
+                               "type" => (preg_match('~^(size|uid|msgno)$~', $name) ? "int" : ""),
+                               "privileges" => array("select" => 1),
+                               "comment" => $comment,
+                       );
+               }
+               return $return;
+       }
+
+       function convert_field($field) {
+       }
+
+       function unconvert_field($field, $return) {
+               return $return;
+       }
+
+       function limit($query, $where, $limit, $offset = 0, $separator = " ") {
+               return " $query$where" . ($limit !== null ? $separator . "LIMIT $limit" . ($offset ? " OFFSET $offset" : "") : "");
+       }
+
+       function idf_escape($idf) {
+               return $idf; //! maybe {}
+       }
+
+       function table($idf) {
+               return idf_escape($idf);
+       }
+
+       function foreign_keys($table) {
+               return array();
+       }
+
+       function tables_list() {
+               global $connection;
+               return $connection->tables_list();
+       }
+
+       function table_status($name = "", $fast = false) {
+               global $connection;
+               if ($name != "") {
+                       return $connection->table_status($name, $fast);
+               }
+               $return = array();
+               foreach (tables_list() as $table => $type) {
+                       $return[$table] = $connection->table_status($table, $fast);
+               }
+               return $return;
+       }
+
+       function count_tables($databases) {
+               return array(reset($databases) => count(tables_list()));
+       }
+
+       function error() {
+               global $connection;
+               return h($connection->error);
+       }
+
+       function is_view($table_status) {
+               return false;
+       }
+
+       function found_rows($table_status, $where) {
+               return $table_status["Rows"];
+       }
+
+       function connect($credentials) {
+               $connection = new Db;
+               if ($connection->connect($credentials[0], $credentials[1], $credentials[2])) {
+                       return $connection;
+               }
+               return $connection->error;
+       }
+
+       function support($feature) {
+               return preg_match("~^()$~", $feature);
+       }
+}