home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress / wp-includes / class-pop3.php < prev    next >
Encoding:
PHP Script  |  2016-10-30  |  20.4 KB  |  663 lines

  1. <?php
  2. /**
  3.  * mail_fetch/setup.php
  4.  *
  5.  * Copyright (c) 1999-2011 CDI (cdi@thewebmasters.net) All Rights Reserved
  6.  * Modified by Philippe Mingo 2001-2009 mingo@rotedic.com
  7.  * An RFC 1939 compliant wrapper class for the POP3 protocol.
  8.  *
  9.  * Licensed under the GNU GPL. For full terms see the file COPYING.
  10.  *
  11.  * POP3 class
  12.  *
  13.  * @copyright 1999-2011 The SquirrelMail Project Team
  14.  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  15.  * @package plugins
  16.  * @subpackage mail_fetch
  17.  */
  18.  
  19. class POP3 {
  20.     var $ERROR      = '';       //  Error string.
  21.  
  22.     var $TIMEOUT    = 60;       //  Default timeout before giving up on a
  23.                                 //  network operation.
  24.  
  25.     var $COUNT      = -1;       //  Mailbox msg count
  26.  
  27.     var $BUFFER     = 512;      //  Socket buffer for socket fgets() calls.
  28.                                 //  Per RFC 1939 the returned line a POP3
  29.                                 //  server can send is 512 bytes.
  30.  
  31.     var $FP         = '';       //  The connection to the server's
  32.                                 //  file descriptor
  33.  
  34.     var $MAILSERVER = '';       // Set this to hard code the server name
  35.  
  36.     var $DEBUG      = FALSE;    // set to true to echo pop3
  37.                                 // commands and responses to error_log
  38.                                 // this WILL log passwords!
  39.  
  40.     var $BANNER     = '';       //  Holds the banner returned by the
  41.                                 //  pop server - used for apop()
  42.  
  43.     var $ALLOWAPOP  = FALSE;    //  Allow or disallow apop()
  44.                                 //  This must be set to true
  45.                                 //  manually
  46.  
  47.     /**
  48.      * PHP5 constructor.
  49.      */
  50.     function __construct ( $server = '', $timeout = '' ) {
  51.         settype($this->BUFFER,"integer");
  52.         if( !empty($server) ) {
  53.             // Do not allow programs to alter MAILSERVER
  54.             // if it is already specified. They can get around
  55.             // this if they -really- want to, so don't count on it.
  56.             if(empty($this->MAILSERVER))
  57.                 $this->MAILSERVER = $server;
  58.         }
  59.         if(!empty($timeout)) {
  60.             settype($timeout,"integer");
  61.             $this->TIMEOUT = $timeout;
  62.             if (!ini_get('safe_mode'))
  63.                 set_time_limit($timeout);
  64.         }
  65.         return true;
  66.     }
  67.  
  68.     /**
  69.      * PHP4 constructor.
  70.      */
  71.     public function POP3( $server = '', $timeout = '' ) {
  72.         self::__construct( $server, $timeout );
  73.     }
  74.  
  75.     function update_timer () {
  76.         if (!ini_get('safe_mode'))
  77.             set_time_limit($this->TIMEOUT);
  78.         return true;
  79.     }
  80.  
  81.     function connect ($server, $port = 110)  {
  82.         //  Opens a socket to the specified server. Unless overridden,
  83.         //  port defaults to 110. Returns true on success, false on fail
  84.  
  85.         // If MAILSERVER is set, override $server with its value.
  86.  
  87.     if (!isset($port) || !$port) {$port = 110;}
  88.         if(!empty($this->MAILSERVER))
  89.             $server = $this->MAILSERVER;
  90.  
  91.         if(empty($server)){
  92.             $this->ERROR = "POP3 connect: " . _("No server specified");
  93.             unset($this->FP);
  94.             return false;
  95.         }
  96.  
  97.         $fp = @fsockopen("$server", $port, $errno, $errstr);
  98.  
  99.         if(!$fp) {
  100.             $this->ERROR = "POP3 connect: " . _("Error ") . "[$errno] [$errstr]";
  101.             unset($this->FP);
  102.             return false;
  103.         }
  104.  
  105.         socket_set_blocking($fp,-1);
  106.         $this->update_timer();
  107.         $reply = fgets($fp,$this->BUFFER);
  108.         $reply = $this->strip_clf($reply);
  109.         if($this->DEBUG)
  110.             error_log("POP3 SEND [connect: $server] GOT [$reply]",0);
  111.         if(!$this->is_ok($reply)) {
  112.             $this->ERROR = "POP3 connect: " . _("Error ") . "[$reply]";
  113.             unset($this->FP);
  114.             return false;
  115.         }
  116.         $this->FP = $fp;
  117.         $this->BANNER = $this->parse_banner($reply);
  118.         return true;
  119.     }
  120.  
  121.     function user ($user = "") {
  122.         // Sends the USER command, returns true or false
  123.  
  124.         if( empty($user) ) {
  125.             $this->ERROR = "POP3 user: " . _("no login ID submitted");
  126.             return false;
  127.         } elseif(!isset($this->FP)) {
  128.             $this->ERROR = "POP3 user: " . _("connection not established");
  129.             return false;
  130.         } else {
  131.             $reply = $this->send_cmd("USER $user");
  132.             if(!$this->is_ok($reply)) {
  133.                 $this->ERROR = "POP3 user: " . _("Error ") . "[$reply]";
  134.                 return false;
  135.             } else
  136.                 return true;
  137.         }
  138.     }
  139.  
  140.     function pass ($pass = "")     {
  141.         // Sends the PASS command, returns # of msgs in mailbox,
  142.         // returns false (undef) on Auth failure
  143.  
  144.         if(empty($pass)) {
  145.             $this->ERROR = "POP3 pass: " . _("No password submitted");
  146.             return false;
  147.         } elseif(!isset($this->FP)) {
  148.             $this->ERROR = "POP3 pass: " . _("connection not established");
  149.             return false;
  150.         } else {
  151.             $reply = $this->send_cmd("PASS $pass");
  152.             if(!$this->is_ok($reply)) {
  153.                 $this->ERROR = "POP3 pass: " . _("Authentication failed") . " [$reply]";
  154.                 $this->quit();
  155.                 return false;
  156.             } else {
  157.                 //  Auth successful.
  158.                 $count = $this->last("count");
  159.                 $this->COUNT = $count;
  160.                 return $count;
  161.             }
  162.         }
  163.     }
  164.  
  165.     function apop ($login,$pass) {
  166.         //  Attempts an APOP login. If this fails, it'll
  167.         //  try a standard login. YOUR SERVER MUST SUPPORT
  168.         //  THE USE OF THE APOP COMMAND!
  169.         //  (apop is optional per rfc1939)
  170.  
  171.         if(!isset($this->FP)) {
  172.             $this->ERROR = "POP3 apop: " . _("No connection to server");
  173.             return false;
  174.         } elseif(!$this->ALLOWAPOP) {
  175.             $retVal = $this->login($login,$pass);
  176.             return $retVal;
  177.         } elseif(empty($login)) {
  178.             $this->ERROR = "POP3 apop: " . _("No login ID submitted");
  179.             return false;
  180.         } elseif(empty($pass)) {
  181.             $this->ERROR = "POP3 apop: " . _("No password submitted");
  182.             return false;
  183.         } else {
  184.             $banner = $this->BANNER;
  185.             if( (!$banner) or (empty($banner)) ) {
  186.                 $this->ERROR = "POP3 apop: " . _("No server banner") . ' - ' . _("abort");
  187.                 $retVal = $this->login($login,$pass);
  188.                 return $retVal;
  189.             } else {
  190.                 $AuthString = $banner;
  191.                 $AuthString .= $pass;
  192.                 $APOPString = md5($AuthString);
  193.                 $cmd = "APOP $login $APOPString";
  194.                 $reply = $this->send_cmd($cmd);
  195.                 if(!$this->is_ok($reply)) {
  196.                     $this->ERROR = "POP3 apop: " . _("apop authentication failed") . ' - ' . _("abort");
  197.                     $retVal = $this->login($login,$pass);
  198.                     return $retVal;
  199.                 } else {
  200.                     //  Auth successful.
  201.                     $count = $this->last("count");
  202.                     $this->COUNT = $count;
  203.                     return $count;
  204.                 }
  205.             }
  206.         }
  207.     }
  208.  
  209.     function login ($login = "", $pass = "") {
  210.         // Sends both user and pass. Returns # of msgs in mailbox or
  211.         // false on failure (or -1, if the error occurs while getting
  212.         // the number of messages.)
  213.  
  214.         if( !isset($this->FP) ) {
  215.             $this->ERROR = "POP3 login: " . _("No connection to server");
  216.             return false;
  217.         } else {
  218.             $fp = $this->FP;
  219.             if( !$this->user( $login ) ) {
  220.                 //  Preserve the error generated by user()
  221.                 return false;
  222.             } else {
  223.                 $count = $this->pass($pass);
  224.                 if( (!$count) || ($count == -1) ) {
  225.                     //  Preserve the error generated by last() and pass()
  226.                     return false;
  227.                 } else
  228.                     return $count;
  229.             }
  230.         }
  231.     }
  232.  
  233.     function top ($msgNum, $numLines = "0") {
  234.         //  Gets the header and first $numLines of the msg body
  235.         //  returns data in an array with each returned line being
  236.         //  an array element. If $numLines is empty, returns
  237.         //  only the header information, and none of the body.
  238.  
  239.         if(!isset($this->FP)) {
  240.             $this->ERROR = "POP3 top: " . _("No connection to server");
  241.             return false;
  242.         }
  243.         $this->update_timer();
  244.  
  245.         $fp = $this->FP;
  246.         $buffer = $this->BUFFER;
  247.         $cmd = "TOP $msgNum $numLines";
  248.         fwrite($fp, "TOP $msgNum $numLines\r\n");
  249.         $reply = fgets($fp, $buffer);
  250.         $reply = $this->strip_clf($reply);
  251.         if($this->DEBUG) {
  252.             @error_log("POP3 SEND [$cmd] GOT [$reply]",0);
  253.         }
  254.         if(!$this->is_ok($reply))
  255.         {
  256.             $this->ERROR = "POP3 top: " . _("Error ") . "[$reply]";
  257.             return false;
  258.         }
  259.  
  260.         $count = 0;
  261.         $MsgArray = array();
  262.  
  263.         $line = fgets($fp,$buffer);
  264.         while ( !preg_match('/^\.\r\n/',$line))
  265.         {
  266.             $MsgArray[$count] = $line;
  267.             $count++;
  268.             $line = fgets($fp,$buffer);
  269.             if(empty($line))    { break; }
  270.         }
  271.  
  272.         return $MsgArray;
  273.     }
  274.  
  275.     function pop_list ($msgNum = "") {
  276.         //  If called with an argument, returns that msgs' size in octets
  277.         //  No argument returns an associative array of undeleted
  278.         //  msg numbers and their sizes in octets
  279.  
  280.         if(!isset($this->FP))
  281.         {
  282.             $this->ERROR = "POP3 pop_list: " . _("No connection to server");
  283.             return false;
  284.         }
  285.         $fp = $this->FP;
  286.         $Total = $this->COUNT;
  287.         if( (!$Total) or ($Total == -1) )
  288.         {
  289.             return false;
  290.         }
  291.         if($Total == 0)
  292.         {
  293.             return array("0","0");
  294.             // return -1;   // mailbox empty
  295.         }
  296.  
  297.         $this->update_timer();
  298.  
  299.         if(!empty($msgNum))
  300.         {
  301.             $cmd = "LIST $msgNum";
  302.             fwrite($fp,"$cmd\r\n");
  303.             $reply = fgets($fp,$this->BUFFER);
  304.             $reply = $this->strip_clf($reply);
  305.             if($this->DEBUG) {
  306.                 @error_log("POP3 SEND [$cmd] GOT [$reply]",0);
  307.             }
  308.             if(!$this->is_ok($reply))
  309.             {
  310.                 $this->ERROR = "POP3 pop_list: " . _("Error ") . "[$reply]";
  311.                 return false;
  312.             }
  313.             list($junk,$num,$size) = preg_split('/\s+/',$reply);
  314.             return $size;
  315.         }
  316.         $cmd = "LIST";
  317.         $reply = $this->send_cmd($cmd);
  318.         if(!$this->is_ok($reply))
  319.         {
  320.             $reply = $this->strip_clf($reply);
  321.             $this->ERROR = "POP3 pop_list: " . _("Error ") .  "[$reply]";
  322.             return false;
  323.         }
  324.         $MsgArray = array();
  325.         $MsgArray[0] = $Total;
  326.         for($msgC=1;$msgC <= $Total; $msgC++)
  327.         {
  328.             if($msgC > $Total) { break; }
  329.             $line = fgets($fp,$this->BUFFER);
  330.             $line = $this->strip_clf($line);
  331.             if(strpos($line, '.') === 0)
  332.             {
  333.                 $this->ERROR = "POP3 pop_list: " . _("Premature end of list");
  334.                 return false;
  335.             }
  336.             list($thisMsg,$msgSize) = preg_split('/\s+/',$line);
  337.             settype($thisMsg,"integer");
  338.             if($thisMsg != $msgC)
  339.             {
  340.                 $MsgArray[$msgC] = "deleted";
  341.             }
  342.             else
  343.             {
  344.                 $MsgArray[$msgC] = $msgSize;
  345.             }
  346.         }
  347.         return $MsgArray;
  348.     }
  349.  
  350.     function get ($msgNum) {
  351.         //  Retrieve the specified msg number. Returns an array
  352.         //  where each line of the msg is an array element.
  353.  
  354.         if(!isset($this->FP))
  355.         {
  356.             $this->ERROR = "POP3 get: " . _("No connection to server");
  357.             return false;
  358.         }
  359.  
  360.         $this->update_timer();
  361.  
  362.         $fp = $this->FP;
  363.         $buffer = $this->BUFFER;
  364.         $cmd = "RETR $msgNum";
  365.         $reply = $this->send_cmd($cmd);
  366.  
  367.         if(!$this->is_ok($reply))
  368.         {
  369.             $this->ERROR = "POP3 get: " . _("Error ") . "[$reply]";
  370.             return false;
  371.         }
  372.  
  373.         $count = 0;
  374.         $MsgArray = array();
  375.  
  376.         $line = fgets($fp,$buffer);
  377.         while ( !preg_match('/^\.\r\n/',$line))
  378.         {
  379.             if ( $line{0} == '.' ) { $line = substr($line,1); }
  380.             $MsgArray[$count] = $line;
  381.             $count++;
  382.             $line = fgets($fp,$buffer);
  383.             if(empty($line))    { break; }
  384.         }
  385.         return $MsgArray;
  386.     }
  387.  
  388.     function last ( $type = "count" ) {
  389.         //  Returns the highest msg number in the mailbox.
  390.         //  returns -1 on error, 0+ on success, if type != count
  391.         //  results in a popstat() call (2 element array returned)
  392.  
  393.         $last = -1;
  394.         if(!isset($this->FP))
  395.         {
  396.             $this->ERROR = "POP3 last: " . _("No connection to server");
  397.             return $last;
  398.         }
  399.  
  400.         $reply = $this->send_cmd("STAT");
  401.         if(!$this->is_ok($reply))
  402.         {
  403.             $this->ERROR = "POP3 last: " . _("Error ") . "[$reply]";
  404.             return $last;
  405.         }
  406.  
  407.         $Vars = preg_split('/\s+/',$reply);
  408.         $count = $Vars[1];
  409.         $size = $Vars[2];
  410.         settype($count,"integer");
  411.         settype($size,"integer");
  412.         if($type != "count")
  413.         {
  414.             return array($count,$size);
  415.         }
  416.         return $count;
  417.     }
  418.  
  419.     function reset () {
  420.         //  Resets the status of the remote server. This includes
  421.         //  resetting the status of ALL msgs to not be deleted.
  422.         //  This method automatically closes the connection to the server.
  423.  
  424.         if(!isset($this->FP))
  425.         {
  426.             $this->ERROR = "POP3 reset: " . _("No connection to server");
  427.             return false;
  428.         }
  429.         $reply = $this->send_cmd("RSET");
  430.         if(!$this->is_ok($reply))
  431.         {
  432.             //  The POP3 RSET command -never- gives a -ERR
  433.             //  response - if it ever does, something truly
  434.             //  wild is going on.
  435.  
  436.             $this->ERROR = "POP3 reset: " . _("Error ") . "[$reply]";
  437.             @error_log("POP3 reset: ERROR [$reply]",0);
  438.         }
  439.         $this->quit();
  440.         return true;
  441.     }
  442.  
  443.     function send_cmd ( $cmd = "" )
  444.     {
  445.         //  Sends a user defined command string to the
  446.         //  POP server and returns the results. Useful for
  447.         //  non-compliant or custom POP servers.
  448.         //  Do NOT includ the \r\n as part of your command
  449.         //  string - it will be appended automatically.
  450.  
  451.         //  The return value is a standard fgets() call, which
  452.         //  will read up to $this->BUFFER bytes of data, until it
  453.         //  encounters a new line, or EOF, whichever happens first.
  454.  
  455.         //  This method works best if $cmd responds with only
  456.         //  one line of data.
  457.  
  458.         if(!isset($this->FP))
  459.         {
  460.             $this->ERROR = "POP3 send_cmd: " . _("No connection to server");
  461.             return false;
  462.         }
  463.  
  464.         if(empty($cmd))
  465.         {
  466.             $this->ERROR = "POP3 send_cmd: " . _("Empty command string");
  467.             return "";
  468.         }
  469.  
  470.         $fp = $this->FP;
  471.         $buffer = $this->BUFFER;
  472.         $this->update_timer();
  473.         fwrite($fp,"$cmd\r\n");
  474.         $reply = fgets($fp,$buffer);
  475.         $reply = $this->strip_clf($reply);
  476.         if($this->DEBUG) { @error_log("POP3 SEND [$cmd] GOT [$reply]",0); }
  477.         return $reply;
  478.     }
  479.  
  480.     function quit() {
  481.         //  Closes the connection to the POP3 server, deleting
  482.         //  any msgs marked as deleted.
  483.  
  484.         if(!isset($this->FP))
  485.         {
  486.             $this->ERROR = "POP3 quit: " . _("connection does not exist");
  487.             return false;
  488.         }
  489.         $fp = $this->FP;
  490.         $cmd = "QUIT";
  491.         fwrite($fp,"$cmd\r\n");
  492.         $reply = fgets($fp,$this->BUFFER);
  493.         $reply = $this->strip_clf($reply);
  494.         if($this->DEBUG) { @error_log("POP3 SEND [$cmd] GOT [$reply]",0); }
  495.         fclose($fp);
  496.         unset($this->FP);
  497.         return true;
  498.     }
  499.  
  500.     function popstat () {
  501.         //  Returns an array of 2 elements. The number of undeleted
  502.         //  msgs in the mailbox, and the size of the mbox in octets.
  503.  
  504.         $PopArray = $this->last("array");
  505.  
  506.         if($PopArray == -1) { return false; }
  507.  
  508.         if( (!$PopArray) or (empty($PopArray)) )
  509.         {
  510.             return false;
  511.         }
  512.         return $PopArray;
  513.     }
  514.  
  515.     function uidl ($msgNum = "")
  516.     {
  517.         //  Returns the UIDL of the msg specified. If called with
  518.         //  no arguments, returns an associative array where each
  519.         //  undeleted msg num is a key, and the msg's uidl is the element
  520.         //  Array element 0 will contain the total number of msgs
  521.  
  522.         if(!isset($this->FP)) {
  523.             $this->ERROR = "POP3 uidl: " . _("No connection to server");
  524.             return false;
  525.         }
  526.  
  527.         $fp = $this->FP;
  528.         $buffer = $this->BUFFER;
  529.  
  530.         if(!empty($msgNum)) {
  531.             $cmd = "UIDL $msgNum";
  532.             $reply = $this->send_cmd($cmd);
  533.             if(!$this->is_ok($reply))
  534.             {
  535.                 $this->ERROR = "POP3 uidl: " . _("Error ") . "[$reply]";
  536.                 return false;
  537.             }
  538.             list ($ok,$num,$myUidl) = preg_split('/\s+/',$reply);
  539.             return $myUidl;
  540.         } else {
  541.             $this->update_timer();
  542.  
  543.             $UIDLArray = array();
  544.             $Total = $this->COUNT;
  545.             $UIDLArray[0] = $Total;
  546.  
  547.             if ($Total < 1)
  548.             {
  549.                 return $UIDLArray;
  550.             }
  551.             $cmd = "UIDL";
  552.             fwrite($fp, "UIDL\r\n");
  553.             $reply = fgets($fp, $buffer);
  554.             $reply = $this->strip_clf($reply);
  555.             if($this->DEBUG) { @error_log("POP3 SEND [$cmd] GOT [$reply]",0); }
  556.             if(!$this->is_ok($reply))
  557.             {
  558.                 $this->ERROR = "POP3 uidl: " . _("Error ") . "[$reply]";
  559.                 return false;
  560.             }
  561.  
  562.             $line = "";
  563.             $count = 1;
  564.             $line = fgets($fp,$buffer);
  565.             while ( !preg_match('/^\.\r\n/',$line)) {
  566.                 list ($msg,$msgUidl) = preg_split('/\s+/',$line);
  567.                 $msgUidl = $this->strip_clf($msgUidl);
  568.                 if($count == $msg) {
  569.                     $UIDLArray[$msg] = $msgUidl;
  570.                 }
  571.                 else
  572.                 {
  573.                     $UIDLArray[$count] = 'deleted';
  574.                 }
  575.                 $count++;
  576.                 $line = fgets($fp,$buffer);
  577.             }
  578.         }
  579.         return $UIDLArray;
  580.     }
  581.  
  582.     function delete ($msgNum = "") {
  583.         //  Flags a specified msg as deleted. The msg will not
  584.         //  be deleted until a quit() method is called.
  585.  
  586.         if(!isset($this->FP))
  587.         {
  588.             $this->ERROR = "POP3 delete: " . _("No connection to server");
  589.             return false;
  590.         }
  591.         if(empty($msgNum))
  592.         {
  593.             $this->ERROR = "POP3 delete: " . _("No msg number submitted");
  594.             return false;
  595.         }
  596.         $reply = $this->send_cmd("DELE $msgNum");
  597.         if(!$this->is_ok($reply))
  598.         {
  599.             $this->ERROR = "POP3 delete: " . _("Command failed ") . "[$reply]";
  600.             return false;
  601.         }
  602.         return true;
  603.     }
  604.  
  605.     //  *********************************************************
  606.  
  607.     //  The following methods are internal to the class.
  608.  
  609.     function is_ok ($cmd = "") {
  610.         //  Return true or false on +OK or -ERR
  611.  
  612.         if( empty($cmd) )
  613.             return false;
  614.         else
  615.             return( stripos($cmd, '+OK') !== false );
  616.     }
  617.  
  618.     function strip_clf ($text = "") {
  619.         // Strips \r\n from server responses
  620.  
  621.         if(empty($text))
  622.             return $text;
  623.         else {
  624.             $stripped = str_replace(array("\r","\n"),'',$text);
  625.             return $stripped;
  626.         }
  627.     }
  628.  
  629.     function parse_banner ( $server_text ) {
  630.         $outside = true;
  631.         $banner = "";
  632.         $length = strlen($server_text);
  633.         for($count =0; $count < $length; $count++)
  634.         {
  635.             $digit = substr($server_text,$count,1);
  636.             if(!empty($digit))             {
  637.                 if( (!$outside) && ($digit != '<') && ($digit != '>') )
  638.                 {
  639.                     $banner .= $digit;
  640.                 }
  641.                 if ($digit == '<')
  642.                 {
  643.                     $outside = false;
  644.                 }
  645.                 if($digit == '>')
  646.                 {
  647.                     $outside = true;
  648.                 }
  649.             }
  650.         }
  651.         $banner = $this->strip_clf($banner);    // Just in case
  652.         return "<$banner>";
  653.     }
  654.  
  655. }   // End class
  656.  
  657. // For php4 compatibility
  658. if (!function_exists("stripos")) {
  659.     function stripos($haystack, $needle){
  660.         return strpos($haystack, stristr( $haystack, $needle ));
  661.     }
  662. }
  663.