Source for file MailServer.php

Documentation is available at MailServer.php

  1. <?php
  2.  
  3. /**
  4.  * The MailServer Module
  5.  *
  6.  * This module provides a simple wrapper around PHP's IMAP library while adding some
  7.  * functionality to make interacting with the mail server as easy as possible.
  8.  *
  9.  * This module can be used by other modules as follows:-
  10.  * - Copy module file to module directory
  11.  * - Adjust configuration file as needed (see further below on configuration file requirements)
  12.  * - In any action run:
  13.  * - $this->exec_module_action('MailServer', 'action')
  14.  *
  15.  * The MailServer module requires the following entries in the configuration file.
  16.  *
  17.  * [mailserver]
  18.  * hostname = imap.server.com    : Name of the email host to connect to
  19.  * port = number            : Port number to connect to for the above host
  20.  * root = Mail/            : Root folder on the server
  21.  * secure = true/false        : Set to true to never send password as plain text
  22.  * ssl = true/false            : Set to true to connect using SSL
  23.  * novalidate-cert = true/false    : Set to true if no need to validate the server certificate
  24.  * tls = true/false            : Set to true to force usage of tls
  25.  * notls = true/false        : Set to true to not use tls even if available on server
  26.  *
  27.  * The defaults are as below:
  28.  * [mailserver]
  29.  * hostname = localhost
  30.  * port = 143
  31.  * root = ''
  32.  * secure = false
  33.  * ssl = false
  34.  * novalidate-cert = false
  35.  * tls = false
  36.  * notls = false
  37.  */
  38. class MailServer extends Module {
  39.     /** 
  40.      * @var array $server_config Connection information loaded from the configuration file
  41.      */
  42.     var $server_config = array(
  43.         'hostname' => 'localhost',
  44.         'port' => 143,
  45.         'root' => '',
  46.         'secure' => false,
  47.         'ssl' => false,
  48.         'novalidate-cert' => false,
  49.         'tls' => false,
  50.         'notls' => false
  51.     );
  52.     
  53.     /**
  54.      * @var resource $connection Connection to the server
  55.      */
  56.     var $connection = null;
  57.     
  58.     /**
  59.      * @var string $current_user Name of the user currently logged in to the server
  60.      */
  61.     var $current_user = '';
  62.     
  63.     /**
  64.      * @var string $current_mailbox Name of the mailbox currently opened
  65.      */
  66.     var $current_mailbox = '';
  67.     
  68.     ///////////////////////////////////////////////////////
  69.     // Basic Setup
  70.  
  71.     /**
  72.      * Constructor for the email server module
  73.      *
  74.      * The constructor registers all error messages used by this module.
  75.      */
  76.     function MailServer({
  77.         // Register all error messages
  78.         $this->register();
  79.     }
  80.     
  81.     /**
  82.      * Get the configuration from config file
  83.      *
  84.      * Load all configuration items under section 'mailserver' in the
  85.      * main configuration file. Default values selected are described
  86.      * in the module description.
  87.      */
  88.     function get_configuration({
  89.         // Load values from config file if applicable
  90.         if (isset($this->application->config['mailserver'])) {
  91.             $keys explode(' ''hostname port root secure ssl novalidate-cert tls notls');
  92.             foreach ($keys as $key)
  93.                 if (isset_and_non_empty($this->application->config['mailserver'][$key]))
  94.                     $this->server_config[$key$this->application->config['mailserver'][$key];
  95.         }
  96.  
  97.         // Save connection information
  98.         $this->server_config['server'
  99.             '{' 
  100.             $this->server_config['hostname'
  101.             ':' 
  102.             $this->server_config['port'
  103.             '}';
  104.     }
  105.     
  106.     ///////////////////////////////////////////////////////
  107.     // Connection related code
  108.  
  109.     /**
  110.      * Connect to the server in a half-open mode (don't select any mailbox)
  111.      *
  112.      * Connect to the server using the username and password specified. This
  113.      * action should be invoked from another module before executing any other
  114.      * actions.
  115.      *
  116.      * Function loads the configuration from config file.
  117.      *
  118.      * @param string $username Username to connect to the server with
  119.      * @param string $password Password to authenticate with
  120.      *
  121.      * @return resource Returns the server connection
  122.      */
  123.     function connect($username$password{
  124.         // Get configuration from file
  125.         $this->get_configuration();
  126.  
  127.         // Figure out what flags to set
  128.         $flags '';
  129.         $flag_names explode(' ''secure ssl novalidate-cert tls notls');
  130.         foreach ($flag_names as $flag_name)
  131.             if (isset($this->server_config[$flag_name]&& $this->server_config[$flag_name== true)
  132.                 $flags .= "/$flag_name";
  133.         
  134.         // Connect to the server
  135.         $this->connection = imap_open(
  136.             rtrim($this->server_config['server']'}'$flags '}',
  137.             $username,
  138.             $password,
  139.             OP_HALFOPEN
  140.         );
  141.  
  142.         // Display error if failure
  143.         if ($this->connection === false)
  144.             $this->error->display_error('ERROR_MAILSERVER_CONNECTION_FAILED'imap_last_error());
  145.         
  146.         // Save current user
  147.         $this->current_user = $username;
  148.         
  149.         // Return connection or false
  150.         return $this->connection;
  151.     }
  152.     
  153.     /**
  154.      * Expunge currently selected mailbox
  155.      *
  156.      * Select a mailbox using $this->open_mailbox($mailbox_name);
  157.      */
  158.     function expunge({
  159.         // Perform the expunge
  160.         $returned imap_expunge($this->connection);
  161.         
  162.         // Display error if failure
  163.         if ($returned == false)
  164.             $this->error->display_error('ERROR_MAILSERVER_EXPUNGE_FAILED'imap_last_error());
  165.             
  166.         return $returned;
  167.     }
  168.  
  169.     /**
  170.      * Disconnect from the current server if connected
  171.      */
  172.     function disconnect({
  173.         // Disconnect if connected
  174.         if (isset($this->connection&& $this->connection !== false)
  175.             imap_close($this->connection);
  176.             
  177.         // Reset the logged in user and current mailbox
  178.         $this->current_user = '';
  179.         $this->current_mailbox = '';
  180.     }
  181.  
  182.     ///////////////////////////////////////////////////////
  183.     // Mailbox related code
  184.  
  185.     /**
  186.      * Open the specified mailbox
  187.      *
  188.      * Call $this->connect($username, $password ) before calling this function
  189.      *
  190.      * @param string $mailbox_name Name of the mailbox to open, default INBOX
  191.      */
  192.     function open_mailbox($mailbox_name='INBOX'{
  193.         // Open the mailbox
  194.         $returned imap_reopen(
  195.             $this->connection,
  196.             $this->server_config['server'$mailbox_name
  197.         );
  198.  
  199.         // Display error if failure
  200.         if ($returned === false)
  201.             $this->error->display_error('ERROR_MAILSERVER_OPEN_MAILBOX_FAILED'$mailbox_nameimap_last_error());
  202.         else
  203.             $this->current_mailbox = $mailbox_name;
  204.         
  205.         return $returned;
  206.     }
  207.  
  208.     /**
  209.      * Create the specified mailbox
  210.      *
  211.      * @param string $mailbox_name Name of the mailbox to create
  212.      */
  213.     function create_mailbox($mailbox_name{
  214.         // Do the create
  215.         $returned imap_createmailbox(
  216.             $this->connection
  217.             $this->server_config['server'$mailbox_name
  218.         );
  219.  
  220.         // Display error if failure
  221.         if ($returned === false)
  222.             $this->error->display_error('ERROR_MAILSERVER_CREATE_MAILBOX_FAILED'$mailbox_nameimap_last_error());
  223.             
  224.         return $returned;
  225.     }
  226.     
  227.     /**
  228.      * Rename the specified mailbox as requested
  229.      *
  230.      * @param string $mailbox_name Name of the mailbox to rename
  231.      * @param string $new_mailbox_name New name of the mailbox
  232.      */
  233.     function rename_mailbox($mailbox_name$new_mailbox_name{
  234.         // Do the rename
  235.         $returned imap_renamemailbox(
  236.             $this->connection
  237.             $this->server_config['server'$mailbox_name,
  238.             $this->server_config['server'$new_mailbox_name
  239.         );
  240.  
  241.         // Display error if failure
  242.         if ($returned === false)
  243.             $this->error->display_error('ERROR_MAILSERVER_RENAME_MAILBOX_FAILED'
  244.                 $mailbox_name$new_mailbox_nameimap_last_error());
  245.             
  246.         return $returned;
  247.     }
  248.     
  249.     /**
  250.      * Delete the specified mailbox
  251.      *
  252.      * @param string $mailbox_name Name of the mailbox to delete
  253.      */
  254.     function delete_mailbox($mailbox_name{
  255.         // Do the delete
  256.         $returned imap_deletemailbox(
  257.             $this->connection
  258.             $this->server_config['server'$mailbox_name
  259.         );
  260.  
  261.         // Display error if failure
  262.         if ($returned === false)
  263.             $this->error->display_error('ERROR_MAILSERVER_DELETE_MAILBOX_FAILED'$mailbox_nameimap_last_error());
  264.             
  265.         return $returned;
  266.     }
  267.  
  268.     /**
  269.      * Get all mailboxes for current connection
  270.      *
  271.      * @return array Returns an array of mailbox name strings
  272.      */
  273.     function get_mailboxes({
  274.         // Get the list of mailboxes in folder root
  275.         $list imap_list(
  276.             $this->connection,
  277.             $this->server_config['server'$this->server_config['root'],
  278.             '*'
  279.         );
  280.         
  281.         // Remove full server path
  282.         for ($i 0$i sizeof($list)$i++)
  283.             $list[$isubstr($list[$i]strlen($this->server_config['server']));
  284.         
  285.         // Sort list by name
  286.         if (is_array($list)) sort($list);
  287.         
  288.         // Display error if failure
  289.         if (!is_array($list))
  290.             $this->error->display_error('ERROR_MAILSERVER_GET_MAILBOXES_FAILED'imap_last_error());
  291.             
  292.         return $list;
  293.     }
  294.     
  295.     /**
  296.      * Get only subscribed mailboxes for current connection
  297.      *
  298.      * @return array Returns an array of mailbox name strings
  299.      */
  300.     function get_subscribed_mailboxes({
  301.         // Get the list of subscribed mailboxes
  302.         $list imap_lsub(
  303.             $this->connection,
  304.             $this->server_config['server'],
  305.             '*'
  306.         );
  307.         
  308.         // Remove full server path
  309.         for ($i 0$i sizeof($list)$i++)
  310.             $list[$isubstr($list[$i]strlen($this->server_config['server']));
  311.         
  312.         // Sort list by name
  313.         if (is_array($list)) sort($list);
  314.         
  315.         // Display error if failure
  316.         if (!is_array($list))
  317.             $this->error->display_error('ERROR_MAILSERVER_GET_SUBSCRIBED_MAILBOXES_FAILED'imap_last_error());
  318.             
  319.         return $list;
  320.     }
  321.     
  322.     /**
  323.      * Get the status information for the specified mailbox
  324.      *
  325.      * @param string $mailbox_name Name of the mailbox, default INBOX
  326.      *
  327.      * @return array Returns an associative array with fields 'num_messages', 'num_recent', 'num_unseen' and 'uid_validity'
  328.      */
  329.     function get_mailbox_status($mailbox_name='INBOX'{
  330.         // Get the mailbox status
  331.         $status imap_status(
  332.             $this->connection
  333.             $this->server_config['server'$mailbox_name,
  334.             SA_MESSAGES SA_RECENT SA_UNSEEN SA_UIDVALIDITY
  335.         );
  336.         
  337.         // Display error if failure
  338.         if (!$status)
  339.             $this->error->display_error('ERROR_MAILSERVER_GET_MAILBOX_STATUS_FAILED'
  340.                 $mailbox_nameimap_last_error());
  341.  
  342.         // Return information as an array
  343.         return array(
  344.             'num_messages' => $status->messages,
  345.             'num_recent' => $status->recent,
  346.             'num_unread' => $status->unseen,
  347.             'uid_validity' => $status->uidvalidity,
  348.         );
  349.     }
  350.     
  351.     /**
  352.      * Subscribe to the specified mailbox
  353.      *
  354.      * @param string $mailbox_name Name of the mailbox to subscribe to
  355.      */
  356.     function subscribe_mailbox($mailbox_name{
  357.         // Subscribe
  358.         $returned imap_subscribe(
  359.             $this->connection
  360.             $this->server_config['server'$mailbox_name
  361.         );
  362.  
  363.         // Display error if failure
  364.         if ($returned === false)
  365.             $this->error->display_error('ERROR_MAILSERVER_SUBSCRIBE_MAILBOX_FAILED'
  366.                 $mailbox_nameimap_last_error());
  367.             
  368.         return $returned;
  369.     }
  370.     
  371.     /**
  372.      * Unsubscribe from the specified mailbox
  373.      *
  374.      * @param string $mailbox_name Name of the mailbox to unsubscribe from
  375.      */
  376.     function unsubscribe_mailbox($mailbox_name{
  377.         // Unsubscribe
  378.         $returned imap_unsubscribe(
  379.             $this->connection
  380.             $this->server_config['server'$mailbox_name
  381.         );
  382.  
  383.         // Display error if failure
  384.         if ($returned === false)
  385.             $this->error->display_error('ERROR_MAILSERVER_UNSUBSCRIBE_MAILBOX_FAILED'
  386.                 $mailbox_nameimap_last_error());
  387.             
  388.         return $returned;
  389.     }
  390.     
  391.     ///////////////////////////////////////////////////////
  392.     // Message information related code
  393.     
  394.     /**
  395.      * Get all the message headers for the current mailbox
  396.      *
  397.      * The object returned has several members which are documented here:
  398.      * http://www.php.net/manual/en/function.imap-headerinfo.php
  399.      *
  400.      * The Msgno member value is replaced with the message UID instead.
  401.      *
  402.      * @return array Returns an array of message header associative arrays with multiple fields
  403.      */
  404.     function get_all_messages({
  405.         // Get all message numbers
  406.         $list imap_search(
  407.             $this->connection
  408.             'ALL'
  409.         );
  410.  
  411.         // Display error if failure
  412.         if ($list === false)
  413.             $this->error->display_error('ERROR_MAILSERVER_MESSAGE_SEARCH_FAILED'imap_last_error());
  414.  
  415.         // Sort the list
  416.         if (is_array($list)) sort($list);
  417.  
  418.         // Store the headers for all the emails
  419.         $headers array();
  420.         foreach ($list as $id{
  421.             // Headers for this message
  422.             $header array();
  423.             
  424.             // Get the headers for each message
  425.             $header_obj imap_headerinfo(
  426.                 $this->connection
  427.                 $id
  428.             );
  429.             
  430.             // Convert msgno to uid since it is unique whereas msgno changes
  431.             $header['email_uid'imap_uid(
  432.                 $this->connection
  433.                 $header_obj->Msgno
  434.             );
  435.  
  436.             // The other message properties
  437.             $header['message_id'$header_obj->message_id;
  438.             $header['udate'$header_obj->udate;
  439.             $header['subject'$header_obj->subject;
  440.             $header['size'$header_obj->Size;
  441.             
  442.             // Unread flag
  443.             $header['unread'0;
  444.             if (isset($header_obj->Unseen&& $header_obj->Unseen == 'U' || $header_obj->Recent == 'N')
  445.                 $header['unread'1;
  446.                 
  447.             // Answered flag
  448.             $header['answered'0;
  449.             if (isset($header_obj->Answered&& $header_obj->Answered == 'A')
  450.                 $header['answered'1;
  451.             
  452.             // Draft flag
  453.             $header['draft'0;
  454.             if (isset($header_obj->Draft&& $header_obj->Draft == 'X')
  455.                 $header['draft'== 1;
  456.             
  457.             // Email information
  458.             $types explode(' ''from to cc bcc reply_to sender');
  459.             foreach ($types as $type{
  460.                 $header[$typearray();
  461.                 if (isset($header_obj->$type))
  462.                     $header[$type$header_obj->$type;
  463.             }
  464.             
  465.             array_push($headers$header);
  466.         }
  467.         
  468.         return $headers;
  469.     }
  470.     
  471.     /** 
  472.      * Get the raw headers for the specified message uid
  473.      *
  474.      * @param int $message_uid The message uid to pull headers for
  475.      *
  476.      * @return string Returns a string containing all the header information
  477.      */
  478.     function get_raw_headers($message_uid{
  479.         // Get the headers
  480.         $returned imap_fetchheader(
  481.             $this->connection,
  482.             $message_uid,
  483.             FT_UID
  484.         );
  485.         
  486.         // Display error if failure
  487.         if ($returned === false)
  488.             $this->error->display_error('ERROR_MAILSERVER_FETCH_HEADER_FAILED'$message_uidimap_last_error());
  489.         
  490.         return $returned;
  491.     }
  492.     
  493.     // Get a list of message parts
  494.     function get_message_parts($message_uid{
  495.         // Get the structure
  496.         $struct imap_fetchstructure(
  497.             $this->connection,
  498.             $message_uid,
  499.             FT_UID
  500.         );
  501.         
  502.         // Display error if failure
  503.         if ($struct === falsebreak;
  504.         
  505.         return $struct;
  506.     }
  507.     
  508.     ///////////////////////////////////////////////////////
  509.     // Message action related code
  510.     
  511.     /**
  512.      * Copy the specified messages to the specified mailbox
  513.      *
  514.      * @param string $message_uids One or more message uids, comma separated
  515.      * @param string $mailbox_name Mailbox to copy the messages to
  516.      */
  517.     function copy_messages($message_uids$mailbox_name{
  518.         // Don't copy anything if source and destination mailbox are the same
  519.         if ($this->current_mailbox == $mailbox_namereturn;
  520.         
  521.         // Perform the copy
  522.         $returned imap_mail_copy(
  523.             $this->connection,
  524.             $message_uids,
  525.             $mailbox_name,
  526.             CP_UID
  527.         );
  528.         
  529.         // Display error if failure
  530.         if ($returned === false)
  531.             $this->error->display_error('ERROR_MAILSERVER_MESSAGE_COPY_FAILED'
  532.                 $message_uids$mailbox_nameimap_last_error());
  533.         
  534.         return $returned;
  535.     }
  536.  
  537.     /**
  538.      * Move the specified messages to the specified mailbox
  539.      *
  540.      * @param string $message_uids One or more message uids, comma separated
  541.      * @param string $mailbox_name Mailbox to move the messages to
  542.      */
  543.     function move_messages($message_uids$mailbox_name{
  544.         // Don't move anything if source and destination mailbox are the same
  545.         if ($this->current_mailbox == $mailbox_namereturn;
  546.         
  547.         // Perform the move
  548.         $returned imap_mail_move(
  549.             $this->connection,
  550.             $message_uids,
  551.             $mailbox_name,
  552.             CP_UID
  553.         );
  554.         
  555.         // Display error if failure
  556.         if ($returned === false)
  557.             $this->error->display_error('ERROR_MAILSERVER_MESSAGE_MOVE_FAILED'
  558.                 $message_uids$mailbox_nameimap_last_error());
  559.         
  560.         return $returned;
  561.     }
  562.  
  563.     /** 
  564.      * Mark specified messages as read
  565.      *
  566.      * @param string $message_uids One or more message uids, comma separated, to mark as read
  567.      */
  568.     function mark_messages_as_read($message_uids{
  569.         // Mark as seen
  570.         $returned imap_setflag_full(
  571.             $this->connection,
  572.             $message_uids,
  573.             "\\Seen"