*/ /** IMAP connection abstraction In the IMAP terminology, "mailbox" is a folder in the mailbox of the user */ class imap { /** The mailbox string */ private $mailbox = null; /** The current folder in UTF-8 */ private $curDir = "INBOX"; /** The auto expunge feature, after deleting/moving an email */ public $autoexpunge = true; /** Limit to one instance of the connection to the same database */ // Based on an idea of http://tonylandis.com/php/php5-pdo-singleton-class/ private static $instance = array (); /** The constructor * The IMAP standard port is 143, but SSL tunnelled is 993 * @param string|null $imapserver The IMAP server to connect. Localhost is * used if not defined * @param integer|null $imapport The IMAP port to connect. 143 is used if not * defined * @param string|null $username The username to connect * @param string|null $password The password to connect * @param boolean|null $imapssl Use the SSL connection layer. Not used by * default * @param boolean|null $imapcertvalidate Check the certificates if using the * SSL connection. True by default */ public function __construct ($imapserver = "localhost", $imapport = 143, $username = null, $password = null, $imapssl = false, $imapcertvalidate = true) { $this->connect ($imapserver, $imapport, $username, $password, $imapssl, $imapcertvalidate); } /** The connect can be used when extends the imap class. The constructor can * be override by the child class. * The IMAP standard port is 143, but SSL tunnelled is 993 * @param string|null $imapserver The IMAP server to connect. Localhost is * used if not defined * @param integer|null $imapport The IMAP port to connect. 143 is used if not * defined * @param string|null $username The username to connect * @param string|null $password The password to connect * @param boolean|null $imapssl Use the SSL connection layer. Not used by * default * @param boolean|null $imapcertvalidate Check the certificates if using the * SSL connection. True by default */ public function connect ($imapserver = "localhost", $imapport = 143, $username = null, $password = null, $imapssl = false, $imapcertvalidate = true) { if (! function_exists ("imap_open")) throw new Exception ("PHP don't support IMAP. Please add it !", 500); if (! function_exists ("mb_convert_encoding")) throw new Exception ("PHP don't support MBString. Please add it !", 500); if ($username === null) throw new Exception ("No username provided for IMAP server", 500); if ($password === null) throw new Exception ("No password provided for IMAP server", 500); $imapssl = ($imapssl !== false) ? "/ssl" : ""; $imapcertvalidate = ($imapcertvalidate === false) ? "/novalidate-cert" : ""; $this->mailbox = "{"."$imapserver:$imapport/imap$imapssl$imapcertvalidate". "/user=$username}"; if (! array_key_exists ($this->mailbox, self::$instance)) { try { // Timeout authentication error to 1s (can't be less). By default, IMAP // wait 10s before returning an auth error imap_timeout (IMAP_READTIMEOUT, 1); self::$instance[$this->mailbox] = @imap_open ($this->mailbox, $username, $password); if (self::$instance[$this->mailbox] === FALSE) throw new Exception (imap_last_error()); } catch (Exception $e) { // imap_errors() takes the errors and clear the error stack $errors = imap_errors(); if (substr ($e->getMessage (), 0, 35) === "Can not authenticate to IMAP server") throw new Exception ("IMAP error : ".$e->getMessage(), 401); throw new Exception ("IMAP error : ".$e->getMessage(), 500); } } } /////////////////// /// FOLDERS /// /////////////////// /** Return an array of the existing folders. The sub-folders are with slash * separator * The names of folders are converted in UTF-8 */ public function foldersList () { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $list = array_keys ($this->foldersListWithAttr ()); sort ($list); return $list; } /** Return an array with folder name in key and attributes in value. The * attributes allow to see if there is new mails in folders */ public function foldersListWithAttr () { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $list = imap_getmailboxes (self::$instance[$this->mailbox], $this->mailbox, "*"); $res = array (); foreach ($list as $val) { $dir = substr ($val->name, strlen ($this->mailbox)); $dir = mb_convert_encoding ($dir, "UTF8", "UTF7-IMAP"); if (isset ($val->delimiter)) $dir = str_replace ($val->delimiter, "/", $dir); $res[$dir] = $val->attributes; } return ($res); } /** Change to provided folder * The folder name must be in UTF-8. The folder must be absolute * @param string $folder Change to the provided folder */ public function changeFolder ($folder) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); if (! in_array ($folder, $this->foldersList ())) throw new Exception ("Folder not found", 404); $folderUTF7 = mb_convert_encoding ($folder, "UTF7-IMAP","UTF-8"); $rc = @imap_reopen (self::$instance[$this->mailbox], $this->mailbox.$folderUTF7); if ($rc === true) $this->curDir = $folder; else throw new Exception ("Can't go in provided folder", 500); return $rc; } /** Return the current folder in UTF-8 */ public function getFolder () { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); return $this->curDir; } /** Create a new folder, provided in UTF-8. The folder must be absolute * @param string $folder Create the provided folder */ public function createFolder ($folder) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); if ( in_array ($folder, $this->foldersList ())) throw new Exception ("Folder already exists", 406); $folderUTF7 = mb_convert_encoding ($folder, "UTF7-IMAP","UTF-8"); return imap_createmailbox (self::$instance[$this->mailbox], $this->mailbox.$folderUTF7); } /** Delete an existing folder provided in UTF-8. The folder must be absolute * @param string $folder The folder to delete */ public function deleteFolder ($folder) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); if (! in_array ($folder, $this->foldersList ())) throw new Exception ("Folder not found", 404); $folderUTF7 = mb_convert_encoding ($folder, "UTF7-IMAP","UTF-8"); return imap_deletemailbox (self::$instance[$this->mailbox], $this->mailbox.$folderUTF7); } /** Return the list of the folders substcribed by the user. The folders are * in UTF-8 */ public function getSubscribe () { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $subs = imap_getsubscribed (self::$instance[$this->mailbox], $this->mailbox, "*"); $res = array (); foreach ($subs as $sub) { $res [] = str_replace ($sub->delimiter, "/", substr ($sub->name, strlen ($this->mailbox))); } $res = array_map (function ($folder) { return mb_convert_encoding ($folder, "UTF-8", "UTF7-IMAP"); }, $res); sort ($res); return $res; } /** Add a subscription for a folder. The folder must be in UTF-8 * @param string $folder Add the provided folder to the subscription file of * the user */ public function addSubscribe ($folder) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $folderUTF7 = mb_convert_encoding ($folder, "UTF7-IMAP","UTF-8"); return imap_subscribe (self::$instance[$this->mailbox], $this->mailbox.$folder); } /** Remove a subscription for a folder. The folder must be in UTF-8 * @param string $folder Remove the provided folder to the subscription file * of the user */ public function delSubscribe ($folder) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $folderUTF7 = mb_convert_encoding ($folder, "UTF7-IMAP","UTF-8"); return imap_unsubscribe (self::$instance[$this->mailbox], $this->mailbox.$folder); } /** Return the information concerning a folder. It return an object with the * following properties : * Date date of last change (current datetime) * Driver driver * Mailbox name of the mailbox * Nmsgs number of messages * Recent number of recent messages * Unread number of unread messages * Deleted number of deleted messages * Size mailbox size * @param string $folder The folder to get the informations */ public function getFolderInfo ($folder) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $oldFolder = $this->curDir; $this->changeFolder ($folder); $rc = imap_mailboxmsginfo (self::$instance[$this->mailbox]); $this->changeFolder ($oldFolder); if ($rc === false) throw new Exception ("Can't read information for folder $folder", 500); return $rc; } ////////////////////// /// LIST MAILS /// ////////////////////// /** Return an array of mailHeaders order by $field and by order ASC or DESC * @param array $mailHeaders The headers to sort * @param string $field The field to examine * @param boolean|null $orderAsc The order of sorting. Asc if not defined */ public function imapSortMail ($mailHeaders, $field, $orderAsc = TRUE) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $this->changeFolder ($this->curDir); $sortList = array (); $sortInc = array (); foreach ($mailHeaders as $mail) { // Permit to have to mails with the same comparator field. Add an // increment at the end of field if (!isset ($sortInc[$mail->$field])) $inc = 1; else $inc = $sortInc[$mail->$field] + 1; $sortInc[$mail->$field] = $inc; $sortList[$mail->$field.$inc] = $mail; } ksort ($sortList, SORT_NATURAL); return array_values ($sortList); } /** Fetch the headers for all messages in the current folder sorted by date * Return an array of mail object containing information like the subject, * the date, if the message is already read (recent), answered... * (see http://www.php.net/manual/en/function.imap-fetch-overview.php) * If the $from is negative, take the LAST $from mails * If from is zero, it's value is override to 1 * For information, takes 0.4s to select 30 mails on 1552 * @param integer|null $from The selector of the mails. 1 if not defined * @param integer|null $nbmails The number of mails returned by the method * 30 if not defined **/ public function mailsDate ($from = 1, $nbmails = 30) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $this->changeFolder ($this->curDir); if ($from === null) $from = 1; $MC = imap_check (self::$instance[$this->mailbox]); if ($MC->Nmsgs === 0) return array (); if ($nbmails > $MC->Nmsgs) $nbmails = $MC->Nmsgs; if ($from < 0) { $from = abs ($from); if ($from < 1) $from = 1; if ($from > $MC->Nmsgs) throw new Exception ("Mail start is higher than the number of mails", 500); $from = $MC->Nmsgs - $from + 1; $to = $from + $nbmails - 1; if ($to > $MC->Nmsgs) $to = $MC->Nmsgs; } else { if ($from > $MC->Nmsgs) throw new Exception ("Mail start is higher than the number of mails", 500); if ($from < 1) $from = 1; $to = $from + $nbmails - 1; if ($to > $MC->Nmsgs) $to = $MC->Nmsgs; } $headers = array (); // Adding the FT_UID options cost 1.1s $result = imap_fetch_overview (self::$instance[$this->mailbox], "$from:$to", 0); // imap_errors() takes the errors and clear the error stack $errors = imap_errors(); return $result; } /** Return all the mails numbers order by thread in an array. * [] => array ("msgno"=>msgno, "depth"=>depth) */ public function mailsThread () { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $this->changeFolder ($this->curDir); $threads = @imap_thread (self::$instance[$this->mailbox]); // imap_errors() takes the errors and clear the error stack $errors = imap_errors(); $thread = array (); $depth = 0; foreach ($threads as $key => $val) { $tree = explode('.', $key); if ($tree[1] == 'num') { // If the mail unknown (the mails starts at 1), skip the thread record if ($val === 0) continue; $thread[] = array ("msgno"=>$val, "depth"=>$depth); $depth++; } elseif ($tree[1] == 'branch' && $depth > 0) { $depth--; } } return $thread; } /** Send back the number of mails in the mailbox */ public function mailsNumber () { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $this->changeFolder ($this->curDir); $MC = imap_check (self::$instance[$this->mailbox]); return $MC->Nmsgs; } /** Return an array containing the msgno corresponding to the criteria * @param string $criteria The criteria to use for the IMAP search */ public function mailsSearch ($criteria) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $this->changeFolder ($this->curDir); return imap_search (self::$instance[$this->mailbox], $criteria); } /** Move the mail provided in the $folder in UTF-8. * If $msgno is an array, all the mails with the contain msgno are deleted * Expunge automatically the current folder to remove the old emails * @param integer|array $msgno The message number(s) to copy * @param string $folder The destination folder of the move. Must exists */ public function mailMove ($msgno, $folder) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $this->changeFolder ($this->curDir); if (is_array ($msgno)) $msgno = implode (",", $msgno); $folderUTF7 = mb_convert_encoding ($folder, "UTF7-IMAP","UTF-8"); $rc = imap_mail_move (self::$instance[$this->mailbox], $msgno, $folderUTF7); if ($rc !== TRUE) { return FALSE; } if ($this->autoexpunge) return imap_expunge (self::$instance[$this->mailbox]); return true; } /** Copy the mail provided in the $folder in UTF-8. * If $msgno is an array, all the mails with the contain msgno are copied * @param integer|array $msgno The message number(s) to copy * @param string $folder The destination folder of the copy. Must exists */ public function mailCopy ($msgno, $folder) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $this->changeFolder ($this->curDir); if (is_array ($msgno)) $msgno = implode (",", $msgno); $folderUTF7 = mb_convert_encoding ($folder, "UTF7-IMAP","UTF-8"); $rc = imap_mail_copy (self::$instance[$this->mailbox], $msgno, $folderUTF7); if ($rc !== TRUE) { return FALSE; } return true; } /** Expunge the mailbox. If the autoexpunge is activated, it is normally not * needed */ public function expunge () { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $this->changeFolder ($this->curDir); return imap_expunge (self::$instance[$this->mailbox]); } ///////////////////////////// /// GET/SET/DEL EMAIL /// ///////////////////////////// /** Get an existing email in the current folder in raw format * @param integer $msgno The message number to examine */ public function getEmailRaw ($msgno) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $this->changeFolder ($this->curDir); // Clear the errors imap_errors(); $content = @imap_fetchheader (self::$instance[$this->mailbox], $msgno)."\n". @imap_body (self::$instance[$this->mailbox], $msgno); $errors = imap_errors (); if ($errors !== false) throw new Exception ("Mail not found", 404); return $content; } /** Get the headers of the email (in raw format) * @param integer $msgno The message number to examine */ public function getEmailHeadersRaw ($msgno) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $this->changeFolder ($this->curDir); // Clear the errors imap_errors(); $content = @imap_fetchheader (self::$instance[$this->mailbox], $msgno); $errors = imap_errors (); if ($errors !== false) throw new Exception ("Mail not found", 404); return $content; } /** Get all the body (and attached files) of an email in raw format * @param integer $msgno The message number to examine */ public function getEmailBodyRaw ($msgno) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $this->changeFolder ($this->curDir); // Clear the errors imap_errors(); $content = @imap_body (self::$instance[$this->mailbox], $msgno); $errors = imap_errors (); if ($errors !== false) throw new Exception ("Mail not found", 404); return $content; } /** Return email structure of the body * @param integer $msgno The message number to examine */ public function getStructure ($msgno) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $this->changeFolder ($this->curDir); // Clear the errors imap_errors(); $structure = @imap_fetchstructure (self::$instance[$this->mailbox], $msgno); $errors = imap_errors (); if ($errors !== false) throw new Exception ("Mail not found", 404); return $structure; } /** Return the structure of the mail body with the associated content * @param integer $msgno The message number to examine */ public function getStructureWithContent ($msgno) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $this->changeFolder ($this->curDir); // Clear the errors imap_errors(); $structure = @imap_fetchstructure (self::$instance[$this->mailbox], $msgno); $errors = imap_errors (); if ($errors !== false) throw new Exception ("Mail not found", 404); if (! isset ($structure->parts)) { // In case of PLAIN text, there is no parts $content = imap_fetchbody (self::$instance[$this->mailbox], $msgno, 1); if ($structure->encoding === 4) $content = quoted_printable_decode ($content); elseif ($structure->encoding === 3) $content = base64_decode ($content); foreach ($structure->parameters as $param) { if ($param->attribute === "charset") $content = iconv ($param->value, "utf-8", $content); } $structure->content = $content; return $structure; } foreach ($structure->parts as $part1=>$struct1) { if (isset ($struct1->parts)) { foreach ($struct1->parts as $part2=>$struct2) { $content = imap_fetchbody (self::$instance[$this->mailbox], $msgno, ($part1+1).".".($part2+1)); if ($struct2->encoding === 4) $content = quoted_printable_decode ($content); elseif ($struct2->encoding === 3) $content = base64_decode ($content); foreach ($struct2->parameters as $param) { if ($param->attribute === "charset") $content = iconv ($param->value, "utf-8", $content); } $structure->parts[$part1]->parts[$part2]->content = $content; // Add the MIME type if ($struct2->type === 0) $structure->parts[$part1]->parts[$part2]->mimetype = "text/". strtolower ($struct2->subtype); elseif ($struct2->type === 1) $structure->parts[$part1]->parts[$part2]->mimetype = "multipart/". strtolower ($struct2->subtype); elseif ($struct2->type === 2) $structure->parts[$part1]->parts[$part2]->mimetype = "message/". strtolower ($struct2->subtype); elseif ($struct2->type === 3) $structure->parts[$part1]->parts[$part2]->mimetype = "application/". strtolower ($struct2->subtype); elseif ($struct2->type === 4) $structure->parts[$part1]->parts[$part2]->mimetype = "audio/". strtolower ($struct2->subtype); elseif ($struct2->type === 5) $structure->parts[$part1]->parts[$part2]->mimetype = "image/". strtolower ($struct2->subtype); elseif ($struct2->type === 6) $structure->parts[$part1]->parts[$part2]->mimetype = "video/". strtolower ($struct2->subtype); elseif ($struct2->type === 7) $structure->parts[$part1]->parts[$part2]->mimetype = "other/". strtolower ($struct2->subtype); else throw new Exception (sprintf ( dgettext("domframework", "Unknown type in imap_fetchstructure : %s"), $struct2->type), 500); } } else { $content = imap_fetchbody (self::$instance[$this->mailbox], $msgno, $part1+1); if ($struct1->encoding === 4) $content = quoted_printable_decode ($content); elseif ($struct1->encoding === 3) $content = base64_decode ($content); foreach ($struct1->parameters as $param) { if ($param->attribute === "charset") $content = iconv ($param->value, "utf-8", $content); } $structure->parts[$part1]->content = $content; // Add the MIME type if ($struct1->type === 0) $structure->parts[$part1]->mimetype = "text/". strtolower ($struct1->subtype); elseif ($struct1->type === 1) $structure->parts[$part1]->mimetype = "multipart/". strtolower ($struct1->subtype); elseif ($struct1->type === 2) $structure->parts[$part1]->mimetype = "message/". strtolower ($struct1->subtype); elseif ($struct1->type === 3) $structure->parts[$part1]->mimetype = "application/". strtolower ($struct1->subtype); elseif ($struct1->type === 4) $structure->parts[$part1]->mimetype = "audio/". strtolower ($struct1->subtype); elseif ($struct1->type === 5) $structure->parts[$part1]->mimetype = "image/". strtolower ($struct1->subtype); elseif ($struct1->type === 6) $structure->parts[$part1]->mimetype = "video/". strtolower ($struct1->subtype); elseif ($struct1->type === 7) $structure->parts[$part1]->mimetype = "other/". strtolower ($struct1->subtype); else throw new Exception (sprintf ( dgettext("domframework", "Unknown type in imap_fetchstructure : %s"), $struct1->type), 500); } } return $structure; } /** Return the content of a part of the mail body defined in the structure in * an object, with the associated mimetype, the parameters like the charset * if they are defined, the number of lines associated to this part in the * mail and some other info * @param integer $msgno The message number to examine * @param integer $part The message part to get */ public function getStructureContent ($msgno, $part) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $structure = $this->getStructureWithContent ($msgno); if (isset ($structure->parts[$part])) return $structure->parts[$part]; throw new Exception ("Part not found in the mail", 404); } /** Return the part identifiers of the structure of the mail body. To be used * in getStructureContent * @param integer $msgno The message number to examine */ public function getStructureParts ($msgno) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $structure = $this->getStructure ($msgno); if (! isset ($structure->parts)) return array (); return array_keys ($structure->parts); } /** Delete all the mailIDs (msgno) provided in an array or a single mail if * $msgno is not an array * DO NOT MOVE THE MAIL IN TRASH, DESTROY THE MAIL REALLY * Expunge the mails at the end of the operation * @param array|integer $msgno The message number(s) to remove */ public function mailsDel ($msgno) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $this->changeFolder ($this->curDir); if (is_array ($msgno)) $msgno = implode (",", $msgno); $rc = @imap_delete (self::$instance[$this->mailbox], $msgno); imap_errors(); if ($rc === FALSE) throw new Exception ("No mailID provided can be found : ABORT"); if ($this->autoexpunge) return imap_expunge(self::$instance[$this->mailbox]); return $rc; } /** Add a new mail in the current folder. The content must be a string * containing all the mail (header and body). If the content is invalid, the * directory listing can provide erroneous data * @param string $content the content of the mail to add */ public function mailAdd ($content) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $folderUTF7 = mb_convert_encoding ($this->curDir, "UTF7-IMAP","UTF-8"); $rc = imap_append (self::$instance[$this->mailbox], $this->mailbox.$folderUTF7, $content); $errors = imap_errors(); if ($rc === FALSE) throw new Exception ("Error when saving the mail in folder : ". implode (" ", $errors), 500); return true; } ///////////////// /// QUOTA /// ///////////////// /** Return the quota used by the user in Mo */ public function getQuota () { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $quota = @imap_get_quotaroot (self::$instance[$this->mailbox], "INBOX"); imap_errors(); if (! isset ($quota["STORAGE"])) return array (); return array_map (function ($n) {return intval ($n/1000);}, $quota["STORAGE"]); } ///////////////// /// FLAGS /// ///////////////// /** Set the flags of the msgno. If msgno is an array, the flags will be write * on the list of mails. The others flags of the email are not modified. * The flags must be an array containing : * \Seen Message has been read * \Answered Message has been answered * \Flagged Message is "flagged" for urgent/special attention * \Deleted Message is "deleted" for removal by later EXPUNGE * \Draft Message has not completed composition (marked as a draft). * @param integer|array $msgno The messages number(s) to add the flags * @param array $flags The flags to add */ public function setFlag ($msgno, $flags) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $this->changeFolder ($this->curDir); if (is_array ($msgno)) $msgno = implode (",", $msgno); $rc = @imap_setflag_full (self::$instance[$this->mailbox], $msgno, implode (" ", $flags)); imap_errors(); if ($rc === FALSE) throw new Exception ("Can't define the flags", 500); return true; } /** Unset the flags of the msgno. If msgno is an array, the flags will be * write on the list of mails. The others flags of the email are not * modified. * The flags must be an array containing : * \Seen Message has been read * \Answered Message has been answered * \Flagged Message is "flagged" for urgent/special attention * \Deleted Message is "deleted" for removal by later EXPUNGE * \Draft Message has not completed composition (marked as a draft). * @param integer|array $msgno The messages number(s) to remove the flags * @param array $flags The flags to remove */ public function unsetFlag ($msgno, $flags) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $this->changeFolder ($this->curDir); if (is_array ($msgno)) $msgno = implode (",", $msgno); $rc = @imap_clearflag_full (self::$instance[$this->mailbox], $msgno, implode (" ", $flags)); imap_errors(); if ($rc === FALSE) throw new Exception ("Can't define the flags", 500); return true; } /** Mark mail(s) as read. * If msgno is an array, a list of mails will be modified. * If msgno is an integer, only one mail will be modified * @param integer|array $msgno The messages number(s) to mark as read */ public function markMailAsRead ($msgno) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $this->changeFolder ($this->curDir); if (is_array ($msgno)) $msgno = implode (",", $msgno); $rc = @imap_setflag_full (self::$instance[$this->mailbox], $msgno, "\\Seen"); imap_errors(); if ($rc === FALSE) throw new Exception ("Can't mark mail as read", 500); return true; } /** Mark mail(s) as unread. * If msgno is an array, a list of mails will be modified. * If msgno is an integer, only one mail will be modified * @param integer|array $msgno The messages number(s) to mark as unread */ public function markMailAsUnread ($msgno) { if ($this->mailbox === null) throw new Exception ("IMAP server not connected", 500); $this->changeFolder ($this->curDir); if (is_array ($msgno)) $msgno = implode (",", $msgno); $rc = @imap_clearflag_full (self::$instance[$this->mailbox], $msgno, "\\Seen"); imap_errors(); if ($rc === FALSE) throw new Exception ("Can't mark mail as read", 500); return true; } }