Source for file class.POP3.php

Documentation is available at class.POP3.php

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

Documentation generated on Tue, 25 Nov 2014 04:20:28 +0100 by phpDocumentor 1.4.3