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