Guest User

Untitled

a guest
May 12th, 2016
214
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 52.87 KB | None | 0 0
  1. <?php
  2. /*
  3. * smtp.php
  4. *
  5. * @(#) $Header: /opt2/ena/metal/smtp/smtp.php,v 1.48 2014/11/23 22:45:30 mlemos Exp $
  6. *
  7. */
  8.  
  9. /*
  10. {metadocument}<?xml version="1.0" encoding="ISO-8859-1"?>
  11. <class>
  12.  
  13. <package>net.manuellemos.smtp</package>
  14.  
  15. <version>@(#) $Id: smtp.php,v 1.48 2014/11/23 22:45:30 mlemos Exp $</version>
  16. <copyright>Copyright (C) Manuel Lemos 1999-2011</copyright>
  17. <title>Sending e-mail messages via SMTP protocol</title>
  18. <author>Manuel Lemos</author>
  19. <authoraddress>mlemos-at-acm.org</authoraddress>
  20.  
  21. <documentation>
  22. <idiom>en</idiom>
  23. <purpose>Sending e-mail messages via SMTP protocol</purpose>
  24. <translation>If you are interested in translating the documentation of
  25. this class to your own idiom, please <link>
  26. <data>contact the author</data>
  27. <url>mailto:<getclassproperty>authoraddress</getclassproperty></url>
  28. </link>.</translation>
  29. <support>Technical support for using this class may be obtained in the
  30. <tt>smtpclass</tt> support forum. Just go to the support forum pages
  31. page to browse the forum archives and post support request
  32. messages:<paragraphbreak />
  33. <link>
  34. <data>http://www.phpclasses.org/discuss/package/14/</data>
  35. <url>http://www.phpclasses.org/discuss/package/14/</url>
  36. </link></support>
  37. <usage>To use this class just create a new object, set any variables
  38. to configure its options and call the
  39. <functionlink>SendMessage</functionlink> function to send a
  40. message.<paragraphbreak />It is not recommended that you use this
  41. class alone unless you have deep understanding of Internet mail
  42. standards on how to compose compliant e-mail messages. Instead, use
  43. the <link>
  44. <data>MIME message composing and sending class</data>
  45. <url>http://www.phpclasses.org/mimemessage</url>
  46. </link> and its sub-class SMTP message together with this SMTP class
  47. to properly compose e-mail messages, so your messages are not
  48. discarded for not being correctly composed.</usage>
  49. </documentation>
  50.  
  51. {/metadocument}
  52. */
  53.  
  54. class smtp_class
  55. {
  56. /*
  57. {metadocument}
  58. <variable>
  59. <name>user</name>
  60. <type>STRING</type>
  61. <value></value>
  62. <documentation>
  63. <purpose>Define the authorized user when sending messages to a SMTP
  64. server.</purpose>
  65. <usage>Set this variable to the user name when the SMTP server
  66. requires authentication.</usage>
  67. </documentation>
  68. </variable>
  69. {/metadocument}
  70. */
  71. var $user="";
  72.  
  73. /*
  74. {metadocument}
  75. <variable>
  76. <name>realm</name>
  77. <type>STRING</type>
  78. <value></value>
  79. <documentation>
  80. <purpose>Define the authentication realm when sending messages to a
  81. SMTP server.</purpose>
  82. <usage>Set this variable when the SMTP server requires
  83. authentication and if more than one authentication realm is
  84. supported.</usage>
  85. </documentation>
  86. </variable>
  87. {/metadocument}
  88. */
  89. var $realm="";
  90.  
  91. /*
  92. {metadocument}
  93. <variable>
  94. <name>password</name>
  95. <type>STRING</type>
  96. <value></value>
  97. <documentation>
  98. <purpose>Define the authorized user password when sending messages
  99. to a SMTP server.</purpose>
  100. <usage>Set this variable to the user password when the SMTP server
  101. requires authentication.</usage>
  102. </documentation>
  103. </variable>
  104. {/metadocument}
  105. */
  106. var $password="";
  107.  
  108. /*
  109. {metadocument}
  110. <variable>
  111. <name>workstation</name>
  112. <type>STRING</type>
  113. <value></value>
  114. <documentation>
  115. <purpose>Define the client workstation name when sending messages
  116. to a SMTP server.</purpose>
  117. <usage>Set this variable to the client workstation when the SMTP
  118. server requires authentication identifiying the origin workstation
  119. name.</usage>
  120. </documentation>
  121. </variable>
  122. {/metadocument}
  123. */
  124. var $workstation="";
  125.  
  126. /*
  127. {metadocument}
  128. <variable>
  129. <name>authentication_mechanism</name>
  130. <type>STRING</type>
  131. <value></value>
  132. <documentation>
  133. <purpose>Force the use of a specific authentication mechanism.</purpose>
  134. <usage>Set it to an empty string to let the class determine the
  135. authentication mechanism to use automatically based on the
  136. supported mechanisms by the server and by the SASL client library
  137. classes.<paragraphbreak />
  138. Set this variable to a specific mechanism name if you want to
  139. override the automatic authentication mechanism selection.</usage>
  140. </documentation>
  141. </variable>
  142. {/metadocument}
  143. */
  144. var $authentication_mechanism="";
  145.  
  146. /*
  147. {metadocument}
  148. <variable>
  149. <name>host_name</name>
  150. <type>STRING</type>
  151. <value></value>
  152. <documentation>
  153. <purpose>Define the SMTP server host name.</purpose>
  154. <usage>Set to the host name of the SMTP server to which you want to
  155. relay the messages.</usage>
  156. </documentation>
  157. </variable>
  158. {/metadocument}
  159. */
  160. var $host_name="";
  161.  
  162. /*
  163. {metadocument}
  164. <variable>
  165. <name>host_port</name>
  166. <type>INTEGER</type>
  167. <value>25</value>
  168. <documentation>
  169. <purpose>Define the SMTP server host port.</purpose>
  170. <usage>Set to the TCP port of the SMTP server host to connect.</usage>
  171. </documentation>
  172. </variable>
  173. {/metadocument}
  174. */
  175. var $host_port=25;
  176.  
  177. /*
  178. {metadocument}
  179. <variable>
  180. <name>socks_host_name</name>
  181. <type>STRING</type>
  182. <value></value>
  183. <documentation>
  184. <purpose>Define the SOCKS server host name.</purpose>
  185. <usage>Set to the SOCKS server host name through which the SMTP
  186. connection should be routed. Leave it empty if you do not want the
  187. connections to be established through a SOCKS server.</usage>
  188. </documentation>
  189. </variable>
  190. {/metadocument}
  191. */
  192. var $socks_host_name = '';
  193.  
  194. /*
  195. {metadocument}
  196. <variable>
  197. <name>socks_host_port</name>
  198. <type>INTEGER</type>
  199. <value>1080</value>
  200. <documentation>
  201. <purpose>Define the SOCKS server host port.</purpose>
  202. <usage>Set to the port of the SOCKS server host through which the
  203. the SMTP connection should be routed.</usage>
  204. </documentation>
  205. </variable>
  206. {/metadocument}
  207. */
  208. var $socks_host_port=1080;
  209.  
  210. /*
  211. {metadocument}
  212. <variable>
  213. <name>socks_version</name>
  214. <type>STRING</type>
  215. <value>5</value>
  216. <documentation>
  217. <purpose>Set the SOCKS protocol version.</purpose>
  218. <usage>Change this value if SOCKS server you want to use is
  219. listening to a different port.</usage>
  220. </documentation>
  221. </variable>
  222. {/metadocument}
  223. */
  224. var $socks_version='5';
  225.  
  226. /*
  227. {metadocument}
  228. <variable>
  229. <name>http_proxy_host_name</name>
  230. <type>STRING</type>
  231. <value></value>
  232. <documentation>
  233. <purpose>Define the HTTP proxy server host name.</purpose>
  234. <usage>Set to the HTTP proxy server host name through which the
  235. SMTP connection should be routed. Leave it empty if you do not
  236. want the connections to be established through an HTTP proxy.</usage>
  237. </documentation>
  238. </variable>
  239. {/metadocument}
  240. */
  241. var $http_proxy_host_name = '';
  242.  
  243. /*
  244. {metadocument}
  245. <variable>
  246. <name>http_proxy_host_port</name>
  247. <type>INTEGER</type>
  248. <value>80</value>
  249. <documentation>
  250. <purpose>Define the HTTP proxy server host port.</purpose>
  251. <usage>Set to the port of the HTTP proxy server host through which
  252. the SMTP connection should be routed.</usage>
  253. </documentation>
  254. </variable>
  255. {/metadocument}
  256. */
  257. var $http_proxy_host_port=80;
  258.  
  259. /*
  260. {metadocument}
  261. <variable>
  262. <name>user_agent</name>
  263. <type>STRING</type>
  264. <value>SMTP Class (http://www.phpclasses.org/smtpclass $Revision: 1.48 $)</value>
  265. <documentation>
  266. <purpose>Set the user agent used when connecting via an HTTP proxy.</purpose>
  267. <usage>Change this value only if for some reason you want emulate a
  268. certain e-mail client.</usage>
  269. </documentation>
  270. </variable>
  271. {/metadocument}
  272. */
  273. var $user_agent='SMTP Class (http://www.phpclasses.org/smtpclass $Revision: 1.48 $)';
  274.  
  275. /*
  276. {metadocument}
  277. <variable>
  278. <name>ssl</name>
  279. <type>BOOLEAN</type>
  280. <value>0</value>
  281. <documentation>
  282. <purpose>Define whether the connection to the SMTP server should be
  283. established securely using SSL protocol.</purpose>
  284. <usage>Set to <booleanvalue>1</booleanvalue> if the SMTP server
  285. requires secure connections using SSL protocol.</usage>
  286. </documentation>
  287. </variable>
  288. {/metadocument}
  289. */
  290. var $ssl=0;
  291.  
  292. /*
  293. {metadocument}
  294. <variable>
  295. <name>start_tls</name>
  296. <type>BOOLEAN</type>
  297. <value>0</value>
  298. <documentation>
  299. <purpose>Define whether the connection to the SMTP server should use
  300. encryption after the connection is established using TLS
  301. protocol.</purpose>
  302. <usage>Set to <booleanvalue>1</booleanvalue> if the SMTP server
  303. requires that authentication be done securely starting the TLS
  304. protocol after the connection is established.</usage>
  305. </documentation>
  306. </variable>
  307. {/metadocument}
  308. */
  309. var $start_tls = 0;
  310.  
  311. /*
  312. {metadocument}
  313. <variable>
  314. <name>localhost</name>
  315. <type>STRING</type>
  316. <value></value>
  317. <documentation>
  318. <purpose>Name of the local host computer</purpose>
  319. <usage>Set to the name of the computer connecting to the SMTP
  320. server from the local network.</usage>
  321. </documentation>
  322. </variable>
  323. {/metadocument}
  324. */
  325. var $localhost="";
  326.  
  327. /*
  328. {metadocument}
  329. <variable>
  330. <name>timeout</name>
  331. <type>INTEGER</type>
  332. <value>0</value>
  333. <documentation>
  334. <purpose>Specify the connection timeout period in seconds.</purpose>
  335. <usage>Leave it set to <integervalue>0</integervalue> if you want
  336. the connection attempts to wait forever. Change this value if for
  337. some reason the timeout period seems insufficient or otherwise it
  338. seems too long.</usage>
  339. </documentation>
  340. </variable>
  341. {/metadocument}
  342. */
  343. var $timeout=0;
  344.  
  345. /*
  346. {metadocument}
  347. <variable>
  348. <name>data_timeout</name>
  349. <type>INTEGER</type>
  350. <value>0</value>
  351. <documentation>
  352. <purpose>Specify the timeout period in seconds to wait for data from
  353. the server.</purpose>
  354. <usage>Leave it set to <integervalue>0</integervalue> if you want
  355. to use the same value defined in the
  356. <variablelink>timeout</variablelink> variable. Change this value
  357. if for some reason the default data timeout period seems
  358. insufficient or otherwise it seems too long.</usage>
  359. </documentation>
  360. </variable>
  361. {/metadocument}
  362. */
  363. var $data_timeout=0;
  364.  
  365. /*
  366. {metadocument}
  367. <variable>
  368. <name>direct_delivery</name>
  369. <type>BOOLEAN</type>
  370. <value>0</value>
  371. <documentation>
  372. <purpose>Boolean flag that indicates whether the message should be
  373. sent in direct delivery mode, i.e. the message is sent to the SMTP
  374. server associated to the domain of the recipient instead of
  375. relaying to the server specified by the
  376. <variablelink>host_name</variablelink> variable.</purpose>
  377. <usage>Set this to <tt><booleanvalue>1</booleanvalue></tt> if you
  378. want to send urgent messages directly to the recipient domain SMTP
  379. server.</usage>
  380. </documentation>
  381. </variable>
  382. {/metadocument}
  383. */
  384. var $direct_delivery=0;
  385.  
  386. /*
  387. {metadocument}
  388. <variable>
  389. <name>error</name>
  390. <type>STRING</type>
  391. <value></value>
  392. <documentation>
  393. <purpose>Message that describes the error when a call to a class
  394. function fails.</purpose>
  395. <usage>Check this variable when an error occurs to understand what
  396. happened.</usage>
  397. </documentation>
  398. </variable>
  399. {/metadocument}
  400. */
  401. var $error="";
  402.  
  403. /*
  404. {metadocument}
  405. <variable>
  406. <name>debug</name>
  407. <type>BOOLEAN</type>
  408. <value>0</value>
  409. <documentation>
  410. <purpose>Specify whether it is necessary to output SMTP connection
  411. debug information.</purpose>
  412. <usage>Set this variable to
  413. <tt><booleanvalue>1</booleanvalue></tt> if you need to see
  414. the progress of the SMTP connection and protocol dialog when you
  415. need to understand the reason for delivery problems.</usage>
  416. </documentation>
  417. </variable>
  418. {/metadocument}
  419. */
  420. var $debug=0;
  421.  
  422. /*
  423. {metadocument}
  424. <variable>
  425. <name>html_debug</name>
  426. <type>BOOLEAN</type>
  427. <value>0</value>
  428. <documentation>
  429. <purpose>Specify whether the debug information should be outputted in
  430. HTML format.</purpose>
  431. <usage>Set this variable to
  432. <tt><booleanvalue>1</booleanvalue></tt> if you need to see
  433. the debug output in a Web page.</usage>
  434. </documentation>
  435. </variable>
  436. {/metadocument}
  437. */
  438. var $html_debug=0;
  439.  
  440. /*
  441. {metadocument}
  442. <variable>
  443. <name>esmtp</name>
  444. <type>BOOLEAN</type>
  445. <value>1</value>
  446. <documentation>
  447. <purpose>Specify whether the class should attempt to use ESMTP
  448. extensions supported by the server.</purpose>
  449. <usage>Set this variable to
  450. <tt><booleanvalue>0</booleanvalue></tt> if for some reason you
  451. want to avoid benefitting from ESMTP extensions.</usage>
  452. </documentation>
  453. </variable>
  454. {/metadocument}
  455. */
  456. var $esmtp=1;
  457.  
  458. /*
  459. {metadocument}
  460. <variable>
  461. <name>esmtp_extensions</name>
  462. <type>HASH</type>
  463. <value></value>
  464. <documentation>
  465. <purpose>Associative array with the list of ESMTP extensions
  466. supported by the SMTP server.</purpose>
  467. <usage>Check this variable after connecting to the SMTP server to
  468. determine which ESMTP extensions are supported.</usage>
  469. </documentation>
  470. </variable>
  471. {/metadocument}
  472. */
  473. var $esmtp_extensions=array();
  474.  
  475. /*
  476. {metadocument}
  477. <variable>
  478. <name>exclude_address</name>
  479. <type>STRING</type>
  480. <value></value>
  481. <documentation>
  482. <purpose>Specify an address that should be considered invalid
  483. when resolving host name addresses.</purpose>
  484. <usage>In some networks any domain name that does not exist is
  485. resolved as a sub-domain of the default local domain. If the DNS is
  486. configured in such way that it always resolves any sub-domain of
  487. the default local domain to a given address, it is hard to
  488. determine whether a given domain does not exist.<paragraphbreak />
  489. If your network is configured this way, you may set this variable
  490. to the address that all sub-domains of the default local domain
  491. resolves, so the class can assume that such address is invalid.</usage>
  492. </documentation>
  493. </variable>
  494. {/metadocument}
  495. */
  496. var $exclude_address="";
  497.  
  498. /*
  499. {metadocument}
  500. <variable>
  501. <name>getmxrr</name>
  502. <type>STRING</type>
  503. <value>getmxrr</value>
  504. <documentation>
  505. <purpose>Specify the name of the function that is called to determine
  506. the SMTP server address of a given domain.</purpose>
  507. <usage>Change this to a working replacement of the PHP
  508. <tt>getmxrr()</tt> function if this is not working in your system
  509. and you want to send messages in direct delivery mode.</usage>
  510. </documentation>
  511. </variable>
  512. {/metadocument}
  513. */
  514. var $getmxrr="GetMXRR";
  515.  
  516. /*
  517. {metadocument}
  518. <variable>
  519. <name>pop3_auth_host</name>
  520. <type>STRING</type>
  521. <value></value>
  522. <documentation>
  523. <purpose>Specify the server address for POP3 based authentication.</purpose>
  524. <usage>Set this variable to the address of the POP3 server if the
  525. SMTP server requires POP3 based authentication.</usage>
  526. </documentation>
  527. </variable>
  528. {/metadocument}
  529. */
  530. var $pop3_auth_host="";
  531.  
  532. /*
  533. {metadocument}
  534. <variable>
  535. <name>pop3_auth_port</name>
  536. <type>INTEGER</type>
  537. <value>110</value>
  538. <documentation>
  539. <purpose>Specify the server port for POP3 based authentication.</purpose>
  540. <usage>Set this variable to the port of the POP3 server if the
  541. SMTP server requires POP3 based authentication.</usage>
  542. </documentation>
  543. </variable>
  544. {/metadocument}
  545. */
  546. var $pop3_auth_port=110;
  547.  
  548. /* private variables - DO NOT ACCESS */
  549.  
  550. var $state="Disconnected";
  551. var $connection=0;
  552. var $pending_recipients=0;
  553. var $next_token="";
  554. var $direct_sender="";
  555. var $connected_domain="";
  556. var $result_code;
  557. var $disconnected_error=0;
  558. var $esmtp_host="";
  559. var $maximum_piped_recipients=100;
  560.  
  561. /* Private methods - DO NOT CALL */
  562.  
  563. Function Tokenize($string,$separator="")
  564. {
  565. if(!strcmp($separator,""))
  566. {
  567. $separator=$string;
  568. $string=$this->next_token;
  569. }
  570. for($character=0;$character<strlen($separator);$character++)
  571. {
  572. if(GetType($position=strpos($string,$separator[$character]))=="integer")
  573. $found=(IsSet($found) ? min($found,$position) : $position);
  574. }
  575. if(IsSet($found))
  576. {
  577. $this->next_token=substr($string,$found+1);
  578. return(substr($string,0,$found));
  579. }
  580. else
  581. {
  582. $this->next_token="";
  583. return($string);
  584. }
  585. }
  586.  
  587. Function OutputDebug($message)
  588. {
  589. $message.="\n";
  590. if($this->html_debug)
  591. $message=str_replace("\n","<br />\n",HtmlEntities($message));
  592. echo $message;
  593. flush();
  594. }
  595.  
  596. Function SetDataAccessError($error)
  597. {
  598. $this->error=$error;
  599. if(function_exists("socket_get_status"))
  600. {
  601. $status=socket_get_status($this->connection);
  602. if($status["timed_out"])
  603. $this->error.=": data access time out";
  604. elseif($status["eof"])
  605. {
  606. $this->error.=": the server disconnected";
  607. $this->disconnected_error=1;
  608. }
  609. }
  610. return($this->error);
  611. }
  612.  
  613. Function SetError($error)
  614. {
  615. return($this->error=$error);
  616. }
  617.  
  618. Function GetLine()
  619. {
  620. for($line="";;)
  621. {
  622. if(feof($this->connection))
  623. {
  624. $this->error="reached the end of data while reading from the SMTP server conection";
  625. return("");
  626. }
  627. if(GetType($data=@fgets($this->connection,100))!="string"
  628. || strlen($data)==0)
  629. {
  630. $this->SetDataAccessError("it was not possible to read line from the SMTP server");
  631. return("");
  632. }
  633. $line.=$data;
  634. $length=strlen($line);
  635. if($length>=2
  636. && substr($line,$length-2,2)=="\r\n")
  637. {
  638. $line=substr($line,0,$length-2);
  639. if($this->debug)
  640. $this->OutputDebug("S $line");
  641. return($line);
  642. }
  643. }
  644. }
  645.  
  646. Function PutLine($line)
  647. {
  648. if($this->debug)
  649. $this->OutputDebug("C $line");
  650. if(!@fputs($this->connection,"$line\r\n"))
  651. {
  652. $this->SetDataAccessError("it was not possible to send a line to the SMTP server");
  653. return(0);
  654. }
  655. return(1);
  656. }
  657.  
  658. Function PutData(&$data)
  659. {
  660. if(strlen($data))
  661. {
  662. if($this->debug)
  663. $this->OutputDebug("C $data");
  664. if(!@fputs($this->connection,$data))
  665. {
  666. $this->SetDataAccessError("it was not possible to send data to the SMTP server");
  667. return(0);
  668. }
  669. }
  670. return(1);
  671. }
  672.  
  673. Function VerifyResultLines($code,&$responses)
  674. {
  675. $responses=array();
  676. Unset($this->result_code);
  677. while(strlen($line=$this->GetLine($this->connection)))
  678. {
  679. if(IsSet($this->result_code))
  680. {
  681. if(strcmp($this->Tokenize($line," -"),$this->result_code))
  682. {
  683. $this->error=$line;
  684. return(0);
  685. }
  686. }
  687. else
  688. {
  689. $this->result_code=$this->Tokenize($line," -");
  690. if(GetType($code)=="array")
  691. {
  692. for($codes=0;$codes<count($code) && strcmp($this->result_code,$code[$codes]);$codes++);
  693. if($codes>=count($code))
  694. {
  695. $this->error=$line;
  696. return(0);
  697. }
  698. }
  699. else
  700. {
  701. if(strcmp($this->result_code,$code))
  702. {
  703. $this->error=$line;
  704. return(0);
  705. }
  706. }
  707. }
  708. $responses[]=$this->Tokenize("");
  709. if(!strcmp($this->result_code,$this->Tokenize($line," ")))
  710. return(1);
  711. }
  712. return(-1);
  713. }
  714.  
  715. Function FlushRecipients()
  716. {
  717. if($this->pending_sender)
  718. {
  719. if($this->VerifyResultLines("250",$responses)<=0)
  720. return(0);
  721. $this->pending_sender=0;
  722. }
  723. for(;$this->pending_recipients;$this->pending_recipients--)
  724. {
  725. if($this->VerifyResultLines(array("250","251"),$responses)<=0)
  726. return(0);
  727. }
  728. return(1);
  729. }
  730.  
  731. Function Resolve($domain, &$ip, $server_type)
  732. {
  733. if(preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/',$domain))
  734. $ip=$domain;
  735. else
  736. {
  737. if($this->debug)
  738. $this->OutputDebug('Resolving '.$server_type.' server domain "'.$domain.'"...');
  739. if(!strcmp($ip=@gethostbyname($domain),$domain))
  740. $ip="";
  741. }
  742. if(strlen($ip)==0
  743. || (strlen($this->exclude_address)
  744. && !strcmp(@gethostbyname($this->exclude_address),$ip)))
  745. return($this->SetError("could not resolve the host domain \"".$domain."\""));
  746. return('');
  747. }
  748.  
  749. Function ConnectToHost($domain, $port, $resolve_message)
  750. {
  751. if($this->ssl)
  752. {
  753. $version=explode(".",function_exists("phpversion") ? phpversion() : "3.0.7");
  754. $php_version=intval($version[0])*1000000+intval($version[1])*1000+intval($version[2]);
  755. if($php_version<4003000)
  756. return("establishing SSL connections requires at least PHP version 4.3.0");
  757. if(!function_exists("extension_loaded")
  758. || !extension_loaded("openssl"))
  759. return("establishing SSL connections requires the OpenSSL extension enabled");
  760. }
  761. if(strlen($this->Resolve($domain, $ip, 'SMTP')))
  762. return($this->error);
  763. if(strlen($this->socks_host_name))
  764. {
  765. switch($this->socks_version)
  766. {
  767. case '4':
  768. $version = 4;
  769. break;
  770. case '5':
  771. $version = 5;
  772. break;
  773. default:
  774. return('it was not specified a supported SOCKS protocol version');
  775. break;
  776. }
  777. $host_ip = $ip;
  778. $host_port = $port;
  779. if(strlen($this->error = $this->Resolve($this->socks_host_name, $ip, 'SOCKS')))
  780. return($this->error);
  781. if($this->ssl)
  782. $ip="ssl://".($socks_host = $this->socks_host_name);
  783. else
  784. $socks_host = $ip;
  785. if($this->debug)
  786. $this->OutputDebug("Connecting to SOCKS server \"".$socks_host."\" port ".$this->http_proxy_host_port."...");
  787.  
  788.  
  789. if(($this->connection=($this->timeout ? fsockopen($socks_host, $this->socks_host_port, $errno, $error, $this->timeout) : fsockopen($socks_host, $this->socks_host_port, $errno, $error))))
  790. {
  791. $timeout=($this->data_timeout ? $this->data_timeout : $this->timeout);
  792. if($timeout
  793. && function_exists("socket_set_timeout"))
  794. socket_set_timeout($this->connection,$timeout,0);
  795. if(strlen($this->socks_host_name))
  796. {
  797. if($this->debug)
  798. $this->OutputDebug('Connected to the SOCKS server '.$this->socks_host_name);
  799. $send_error = 'it was not possible to send data to the SOCKS server';
  800. $receive_error = 'it was not possible to receive data from the SOCKS server';
  801. switch($version)
  802. {
  803. case 4:
  804. $command = 1;
  805. $user = '';
  806. if(!fputs($this->connection, chr($version).chr($command).pack('nN', $host_port, ip2long($host_ip)).$user.Chr(0)))
  807. $error = $this->SetDataAccessError($send_error);
  808. else
  809. {
  810. $response = fgets($this->connection, 9);
  811. if(strlen($response) != 8)
  812. $error = $this->SetDataAccessError($receive_error);
  813. else
  814. {
  815. $socks_errors = array(
  816. "\x5a"=>'',
  817. "\x5b"=>'request rejected',
  818. "\x5c"=>'request failed because client is not running identd (or not reachable from the server)',
  819. "\x5d"=>'request failed because client\'s identd could not confirm the user ID string in the request',
  820. );
  821. $error_code = $response[1];
  822. $error = (IsSet($socks_errors[$error_code]) ? $socks_errors[$error_code] : 'unknown');
  823. if(strlen($error))
  824. $error = 'SOCKS error: '.$error;
  825. }
  826. }
  827. break;
  828. case 5:
  829. if($this->debug)
  830. $this->OutputDebug('Negotiating the authentication method ...');
  831. $methods = 1;
  832. $method = 0;
  833. if(!fputs($this->connection, chr($version).chr($methods).chr($method)))
  834. $error = $this->SetDataAccessError($send_error);
  835. else
  836. {
  837. $response = fgets($this->connection, 3);
  838. if(strlen($response) != 2)
  839. $error = $this->SetDataAccessError($receive_error);
  840. elseif(Ord($response[1]) != $method)
  841. $error = 'the SOCKS server requires an authentication method that is not yet supported';
  842. else
  843. {
  844. if($this->debug)
  845. $this->OutputDebug('Connecting to SMTP server IP '.$host_ip.' port '.$host_port.'...');
  846. $command = 1;
  847. $address_type = 1;
  848. if(!fputs($this->connection, chr($version).chr($command)."\x00".chr($address_type).pack('Nn', ip2long($host_ip), $host_port)))
  849. $error = $this->SetDataAccessError($send_error);
  850. else
  851. {
  852. $response = fgets($this->connection, 11);
  853.  
  854.  
  855.  
  856. if(strlen($response) != 10)
  857. $error = $this->SetDataAccessError($receive_error);
  858. else
  859. {
  860. $socks_errors = array(
  861. "\x00"=>'',
  862. "\x01"=>'general SOCKS server failure',
  863. "\x02"=>'connection not allowed by ruleset',
  864. "\x03"=>'Network unreachable',
  865. "\x04"=>'Host unreachable',
  866. "\x05"=>'Connection refused',
  867. "\x06"=>'TTL expired',
  868. "\x07"=>'Command not supported',
  869. "\x08"=>'Address type not supported'
  870. );
  871. $error_code = $response[1];
  872. $error = (IsSet($socks_errors[$error_code]) ? $socks_errors[$error_code] : 'unknown');
  873.  
  874. if(strlen($error))
  875. $error = 'SOCKS error: '.$error;
  876. }
  877. }
  878. }
  879. }
  880. break;
  881. default:
  882. $error = 'support for SOCKS protocol version '.$this->socks_version.' is not yet implemented';
  883. break;
  884. }
  885. if(strlen($this->error = $error))
  886. {
  887. fclose($this->connection);
  888. return($error);
  889. }
  890. }
  891. return('');
  892. }
  893. }
  894. elseif(strlen($this->http_proxy_host_name))
  895. {
  896. if(strlen($error = $this->Resolve($this->http_proxy_host_name, $ip, 'SMTP')))
  897. return($error);
  898. if($this->ssl)
  899. $ip = 'ssl://'.($proxy_host = $this->http_proxy_host_name);
  900. else
  901. $proxy_host = $ip;
  902. if($this->debug)
  903. $this->OutputDebug("Connecting to HTTP proxy server \"".$ip."\" port ".$this->http_proxy_host_port."...");
  904. if(($this->connection=($this->timeout ? @fsockopen($ip, $this->http_proxy_host_port, $errno, $error, $this->timeout) : @fsockopen($ip, $this->http_proxy_host_port, $errno, $error))))
  905. {
  906. if($this->debug)
  907. $this->OutputDebug('Connected to HTTP proxy host "'.$this->http_proxy_host_name.'".');
  908. $timeout=($this->data_timeout ? $this->data_timeout : $this->timeout);
  909. if($timeout
  910. && function_exists("socket_set_timeout"))
  911. socket_set_timeout($this->connection,$timeout,0);
  912. if($this->PutLine('CONNECT '.$domain.':'.$port.' HTTP/1.0')
  913. && $this->PutLine('User-Agent: '.$this->user_agent)
  914. && $this->PutLine(''))
  915. {
  916. if(GetType($response = $this->GetLine()) == 'string')
  917. {
  918. if(!preg_match('/^http\\/[0-9]+\\.[0-9]+[ \t]+([0-9]+)[ \t]*(.*)$/i', $response,$matches))
  919. return($this->SetError("3 it was received an unexpected HTTP response status"));
  920. $error = $matches[1];
  921. switch($error)
  922. {
  923. case '200':
  924. for(;;)
  925. {
  926. if(GetType($response = $this->GetLine()) != 'string')
  927. break;
  928. if(strlen($response) == 0)
  929. return('');
  930. }
  931. break;
  932. default:
  933. $this->error = 'the HTTP proxy returned error '.$error.' '.$matches[2];
  934. break;
  935. }
  936. }
  937. }
  938. if($this->debug)
  939. $this->OutputDebug("Disconnected.");
  940. fclose($this->connection);
  941. $this->connection = 0;
  942. return($this->error);
  943. }
  944. }
  945. else
  946. {
  947. if($this->ssl)
  948. $ip = 'ssl://'.($host = $domain);
  949. elseif($this->start_tls)
  950. $ip = $host = $domain;
  951. else
  952. $host = $ip;
  953. if($this->debug)
  954. $this->OutputDebug("Connecting to SMTP server \"".$host."\" port ".$port."...");
  955. if(($this->connection=($this->timeout ? @fsockopen($ip, $port, $errno, $error, $this->timeout) : @fsockopen($ip, $port, $errno, $error))))
  956. return("");
  957. }
  958. $error=($this->timeout ? strval($error) : "??");
  959. switch($error)
  960. {
  961. case "-3":
  962. return("-3 socket could not be created");
  963. case "-4":
  964. return("-4 dns lookup on hostname \"".$domain."\" failed");
  965. case "-5":
  966. return("-5 connection refused or timed out");
  967. case "-6":
  968. return("-6 fdopen() call failed");
  969. case "-7":
  970. return("-7 setvbuf() call failed");
  971. }
  972. return("could not connect to the host \"".$domain."\": ".$error);
  973. }
  974.  
  975. Function SASLAuthenticate($mechanisms, $credentials, &$authenticated, &$mechanism)
  976. {
  977. $authenticated=0;
  978. if(!function_exists("class_exists")
  979. || !class_exists("sasl_client_class"))
  980. {
  981. $this->error="it is not possible to authenticate using the specified mechanism because the SASL library class is not loaded";
  982. return(0);
  983. }
  984. $sasl=new sasl_client_class;
  985. $sasl->SetCredential("user",$credentials["user"]);
  986. $sasl->SetCredential("password",$credentials["password"]);
  987. if(IsSet($credentials["realm"]))
  988. $sasl->SetCredential("realm",$credentials["realm"]);
  989. if(IsSet($credentials["workstation"]))
  990. $sasl->SetCredential("workstation",$credentials["workstation"]);
  991. if(IsSet($credentials["mode"]))
  992. $sasl->SetCredential("mode",$credentials["mode"]);
  993. do
  994. {
  995. $status=$sasl->Start($mechanisms,$message,$interactions);
  996. }
  997. while($status==SASL_INTERACT);
  998. switch($status)
  999. {
  1000. case SASL_CONTINUE:
  1001. break;
  1002. case SASL_NOMECH:
  1003. if(strlen($this->authentication_mechanism))
  1004. {
  1005. $this->error="authenticated mechanism ".$this->authentication_mechanism." may not be used: ".$sasl->error;
  1006. return(0);
  1007. }
  1008. break;
  1009. default:
  1010. $this->error="Could not start the SASL authentication client: ".$sasl->error;
  1011. return(0);
  1012. }
  1013. if(strlen($mechanism=$sasl->mechanism))
  1014. {
  1015. if($this->PutLine("AUTH ".$sasl->mechanism.(IsSet($message) ? " ".base64_encode($message) : ""))==0)
  1016. {
  1017. $this->error="Could not send the AUTH command";
  1018. return(0);
  1019. }
  1020. if(!$this->VerifyResultLines(array("235","334"),$responses))
  1021. return(0);
  1022. switch($this->result_code)
  1023. {
  1024. case "235":
  1025. $response="";
  1026. $authenticated=1;
  1027. break;
  1028. case "334":
  1029. $response=base64_decode($responses[0]);
  1030. break;
  1031. default:
  1032. $this->error="Authentication error: ".$responses[0];
  1033. return(0);
  1034. }
  1035. for(;!$authenticated;)
  1036. {
  1037. do
  1038. {
  1039. $status=$sasl->Step($response,$message,$interactions);
  1040. }
  1041. while($status==SASL_INTERACT);
  1042. switch($status)
  1043. {
  1044. case SASL_CONTINUE:
  1045. if($this->PutLine(base64_encode($message))==0)
  1046. {
  1047. $this->error="Could not send the authentication step message";
  1048. return(0);
  1049. }
  1050. if(!$this->VerifyResultLines(array("235","334"),$responses))
  1051. return(0);
  1052. switch($this->result_code)
  1053. {
  1054. case "235":
  1055. $response="";
  1056. $authenticated=1;
  1057. break;
  1058. case "334":
  1059. $response=base64_decode($responses[0]);
  1060. break;
  1061. default:
  1062. $this->error="Authentication error: ".$responses[0];
  1063. return(0);
  1064. }
  1065. break;
  1066. default:
  1067. $this->error="Could not process the SASL authentication step: ".$sasl->error;
  1068. return(0);
  1069. }
  1070. }
  1071. }
  1072. return(1);
  1073. }
  1074.  
  1075. Function StartSMTP($localhost)
  1076. {
  1077. $success = 1;
  1078. $this->esmtp_extensions = array();
  1079. $fallback=1;
  1080. if($this->esmtp
  1081. || strlen($this->user))
  1082. {
  1083. if($this->PutLine('EHLO '.$localhost))
  1084. {
  1085. if(($success_code=$this->VerifyResultLines('250',$responses))>0)
  1086. {
  1087. $this->esmtp_host=$this->Tokenize($responses[0]," ");
  1088. for($response=1;$response<count($responses);$response++)
  1089. {
  1090. $extension=strtoupper($this->Tokenize($responses[$response]," "));
  1091. $this->esmtp_extensions[$extension]=$this->Tokenize("");
  1092. }
  1093. $success=1;
  1094. $fallback=0;
  1095. }
  1096. else
  1097. {
  1098. if($success_code==0)
  1099. {
  1100. $code=$this->Tokenize($this->error," -");
  1101. switch($code)
  1102. {
  1103. case "421":
  1104. $fallback=0;
  1105. break;
  1106. }
  1107. }
  1108. }
  1109. }
  1110. else
  1111. $fallback=0;
  1112. }
  1113. if($fallback)
  1114. {
  1115. if($this->PutLine("HELO $localhost")
  1116. && $this->VerifyResultLines("250",$responses)>0)
  1117. $success=1;
  1118. }
  1119. return($success);
  1120. }
  1121.  
  1122. /* Public methods */
  1123.  
  1124. /*
  1125. {metadocument}
  1126. <function>
  1127. <name>Connect</name>
  1128. <type>BOOLEAN</type>
  1129. <documentation>
  1130. <purpose>Connect to an SMTP server.</purpose>
  1131. <usage>Call this function as first step to send e-mail messages.</usage>
  1132. <returnvalue>The function returns
  1133. <tt><booleanvalue>1</booleanvalue></tt> if the connection is
  1134. successfully established.</returnvalue>
  1135. </documentation>
  1136. <argument>
  1137. <name>domain</name>
  1138. <type>STRING</type>
  1139. <defaultvalue></defaultvalue>
  1140. <documentation>
  1141. <purpose>Specify the domain of the recipient when using the direct
  1142. delivery mode.</purpose>
  1143. </documentation>
  1144. </argument>
  1145. <do>
  1146. {/metadocument}
  1147. */
  1148. Function Connect($domain="")
  1149. {
  1150. if(strcmp($this->state,"Disconnected"))
  1151. {
  1152. $this->error="connection is already established";
  1153. return(0);
  1154. }
  1155. $this->disconnected_error=0;
  1156. $this->error=$error="";
  1157. $this->esmtp_host="";
  1158. $this->esmtp_extensions=array();
  1159. $hosts=array();
  1160. if($this->direct_delivery)
  1161. {
  1162. if(strlen($domain)==0)
  1163. return(1);
  1164. $hosts=$weights=$mxhosts=array();
  1165. $getmxrr=$this->getmxrr;
  1166. if(function_exists($getmxrr)
  1167. && $getmxrr($domain,$hosts,$weights))
  1168. {
  1169. for($host=0;$host<count($hosts);$host++)
  1170. $mxhosts[$weights[$host]]=$hosts[$host];
  1171. KSort($mxhosts);
  1172. for(Reset($mxhosts),$host=0;$host<count($mxhosts);Next($mxhosts),$host++)
  1173. $hosts[$host]=$mxhosts[Key($mxhosts)];
  1174. }
  1175. else
  1176. {
  1177. if(strcmp(@gethostbyname($domain),$domain)!=0)
  1178. $hosts[]=$domain;
  1179. }
  1180. }
  1181. else
  1182. {
  1183. if(strlen($this->host_name))
  1184. $hosts[]=$this->host_name;
  1185. if(strlen($this->pop3_auth_host))
  1186. {
  1187. $user=$this->user;
  1188. if(strlen($user)==0)
  1189. {
  1190. $this->error="it was not specified the POP3 authentication user";
  1191. return(0);
  1192. }
  1193. $password=$this->password;
  1194. if(strlen($password)==0)
  1195. {
  1196. $this->error="it was not specified the POP3 authentication password";
  1197. return(0);
  1198. }
  1199. $domain=$this->pop3_auth_host;
  1200. $this->error=$this->ConnectToHost($domain, $this->pop3_auth_port, "Resolving POP3 authentication host \"".$domain."\"...");
  1201. if(strlen($this->error))
  1202. return(0);
  1203. if(strlen($response=$this->GetLine())==0)
  1204. return(0);
  1205. if(strcmp($this->Tokenize($response," "),"+OK"))
  1206. {
  1207. $this->error="POP3 authentication server greeting was not found";
  1208. return(0);
  1209. }
  1210. if(!$this->PutLine("USER ".$this->user)
  1211. || strlen($response=$this->GetLine())==0)
  1212. return(0);
  1213. if(strcmp($this->Tokenize($response," "),"+OK"))
  1214. {
  1215. $this->error="POP3 authentication user was not accepted: ".$this->Tokenize("\r\n");
  1216. return(0);
  1217. }
  1218. if(!$this->PutLine("PASS ".$password)
  1219. || strlen($response=$this->GetLine())==0)
  1220. return(0);
  1221. if(strcmp($this->Tokenize($response," "),"+OK"))
  1222. {
  1223. $this->error="POP3 authentication password was not accepted: ".$this->Tokenize("\r\n");
  1224. return(0);
  1225. }
  1226. fclose($this->connection);
  1227. $this->connection=0;
  1228. }
  1229. }
  1230. if(count($hosts)==0)
  1231. {
  1232. $this->error="could not determine the SMTP to connect";
  1233. return(0);
  1234. }
  1235. for($host=0, $error="not connected";strlen($error) && $host<count($hosts);$host++)
  1236. {
  1237. $domain=$hosts[$host];
  1238. $error=$this->ConnectToHost($domain, $this->host_port, "Resolving SMTP server domain \"$domain\"...");
  1239. }
  1240. if(strlen($error))
  1241. {
  1242. $this->error=$error;
  1243. return(0);
  1244. }
  1245. $timeout=($this->data_timeout ? $this->data_timeout : $this->timeout);
  1246. if($timeout
  1247. && function_exists("socket_set_timeout"))
  1248. socket_set_timeout($this->connection,$timeout,0);
  1249. if($this->debug)
  1250. $this->OutputDebug("Connected to SMTP server \"".$domain."\".");
  1251. if(!strcmp($localhost=$this->localhost,"")
  1252. && !strcmp($localhost=getenv("SERVER_NAME"),"")
  1253. && !strcmp($localhost=getenv("HOST"),""))
  1254. $localhost="localhost";
  1255. $success=0;
  1256.  
  1257. if ($this->ssl && strlen($this->socks_host_name))
  1258. {
  1259. stream_socket_enable_crypto($this->connection, 1,STREAM_CRYPTO_METHOD_SSLv23_CLIENT);
  1260. }
  1261.  
  1262.  
  1263. if($this->VerifyResultLines("220",$responses)>0)
  1264. {
  1265. $success = $this->StartSMTP($localhost);
  1266. if($this->start_tls)
  1267. {
  1268. if(!IsSet($this->esmtp_extensions["STARTTLS"]))
  1269. {
  1270. $this->error="server does not support starting TLS";
  1271. $success=0;
  1272. }
  1273. elseif(!function_exists('stream_socket_enable_crypto'))
  1274. {
  1275. $this->error="this PHP installation or version does not support starting TLS";
  1276. $success=0;
  1277. }
  1278. elseif($success = ($this->PutLine('STARTTLS')
  1279. && $this->VerifyResultLines('220',$responses)>0))
  1280. {
  1281. $this->OutputDebug('Starting TLS cryptograpic protocol');
  1282. if(!($success = stream_socket_enable_crypto($this->connection, 1, STREAM_CRYPTO_METHOD_TLS_CLIENT)))
  1283. $this->error = 'could not start TLS connection encryption protocol';
  1284. else
  1285. {
  1286. $this->OutputDebug('TLS started');
  1287. $success = $this->StartSMTP($localhost);
  1288. }
  1289. }
  1290. }
  1291. if($success
  1292. && strlen($this->user)
  1293. && strlen($this->pop3_auth_host)==0)
  1294. {
  1295. if(!IsSet($this->esmtp_extensions["AUTH"]))
  1296. {
  1297. $this->error="server does not require authentication";
  1298. if(IsSet($this->esmtp_extensions["STARTTLS"]))
  1299. $this->error .= ', it probably requires starting TLS';
  1300. $success=0;
  1301. }
  1302. else
  1303. {
  1304. if(strlen($this->authentication_mechanism))
  1305. $mechanisms=array($this->authentication_mechanism);
  1306. else
  1307. {
  1308. $mechanisms=array();
  1309. for($authentication=$this->Tokenize($this->esmtp_extensions["AUTH"]," ");strlen($authentication);$authentication=$this->Tokenize(" "))
  1310. $mechanisms[]=$authentication;
  1311. }
  1312. $credentials=array(
  1313. "user"=>$this->user,
  1314. "password"=>$this->password
  1315. );
  1316. if(strlen($this->realm))
  1317. $credentials["realm"]=$this->realm;
  1318. if(strlen($this->workstation))
  1319. $credentials["workstation"]=$this->workstation;
  1320. $success=$this->SASLAuthenticate($mechanisms,$credentials,$authenticated,$mechanism);
  1321. if(!$success
  1322. && !strcmp($mechanism,"PLAIN"))
  1323. {
  1324. /*
  1325. * Author: Russell Robinson, 25 May 2003, http://www.tectite.com/
  1326. * Purpose: Try various AUTH PLAIN authentication methods.
  1327. */
  1328. $mechanisms=array("PLAIN");
  1329. $credentials=array(
  1330. "user"=>$this->user,
  1331. "password"=>$this->password
  1332. );
  1333. if(strlen($this->realm))
  1334. {
  1335. /*
  1336. * According to: http://www.sendmail.org/~ca/email/authrealms.html#authpwcheck_method
  1337. * some sendmails won't accept the realm, so try again without it
  1338. */
  1339. $success=$this->SASLAuthenticate($mechanisms,$credentials,$authenticated,$mechanism);
  1340. }
  1341. if(!$success)
  1342. {
  1343. /*
  1344. * It was seen an EXIM configuration like this:
  1345. * user^password^unused
  1346. */
  1347. $credentials["mode"]=SASL_PLAIN_EXIM_DOCUMENTATION_MODE;
  1348. $success=$this->SASLAuthenticate($mechanisms,$credentials,$authenticated,$mechanism);
  1349. }
  1350. if(!$success)
  1351. {
  1352. /*
  1353. * ... though: http://exim.work.de/exim-html-3.20/doc/html/spec_36.html
  1354. * specifies: ^user^password
  1355. */
  1356. $credentials["mode"]=SASL_PLAIN_EXIM_MODE;
  1357. $success=$this->SASLAuthenticate($mechanisms,$credentials,$authenticated,$mechanism);
  1358. }
  1359. }
  1360. if($success
  1361. && strlen($mechanism)==0)
  1362. {
  1363. $this->error="it is not supported any of the authentication mechanisms required by the server";
  1364. $success=0;
  1365. }
  1366. }
  1367. }
  1368. }
  1369. if($success)
  1370. {
  1371. $this->state="Connected";
  1372. $this->connected_domain=$domain;
  1373. }
  1374. else
  1375. {
  1376. fclose($this->connection);
  1377. $this->connection=0;
  1378. }
  1379. return($success);
  1380. }
  1381. /*
  1382. {metadocument}
  1383. </do>
  1384. </function>
  1385. {/metadocument}
  1386. */
  1387.  
  1388. /*
  1389. {metadocument}
  1390. <function>
  1391. <name>MailFrom</name>
  1392. <type>BOOLEAN</type>
  1393. <documentation>
  1394. <purpose>Set the address of the message sender.</purpose>
  1395. <usage>Call this function right after establishing a connection with
  1396. the <functionlink>Connect</functionlink> function.</usage>
  1397. <returnvalue>The function returns
  1398. <tt><booleanvalue>1</booleanvalue></tt> if the sender address is
  1399. successfully set.</returnvalue>
  1400. </documentation>
  1401. <argument>
  1402. <name>sender</name>
  1403. <type>STRING</type>
  1404. <documentation>
  1405. <purpose>E-mail address of the sender.</purpose>
  1406. </documentation>
  1407. </argument>
  1408. <do>
  1409. {/metadocument}
  1410. */
  1411. Function MailFrom($sender)
  1412. {
  1413. if($this->direct_delivery)
  1414. {
  1415. switch($this->state)
  1416. {
  1417. case "Disconnected":
  1418. $this->direct_sender=$sender;
  1419. return(1);
  1420. case "Connected":
  1421. $sender=$this->direct_sender;
  1422. break;
  1423. default:
  1424. $this->error="direct delivery connection is already established and sender is already set";
  1425. return(0);
  1426. }
  1427. }
  1428. else
  1429. {
  1430. if(strcmp($this->state,"Connected"))
  1431. {
  1432. $this->error="connection is not in the initial state";
  1433. return(0);
  1434. }
  1435. }
  1436. $this->error="";
  1437. if(!$this->PutLine("MAIL FROM:<$sender>"))
  1438. return(0);
  1439. if(!IsSet($this->esmtp_extensions["PIPELINING"])
  1440. && $this->VerifyResultLines("250",$responses)<=0)
  1441. return(0);
  1442. $this->state="SenderSet";
  1443. if(IsSet($this->esmtp_extensions["PIPELINING"]))
  1444. $this->pending_sender=1;
  1445. $this->pending_recipients=0;
  1446. return(1);
  1447. }
  1448. /*
  1449. {metadocument}
  1450. </do>
  1451. </function>
  1452. {/metadocument}
  1453. */
  1454.  
  1455. /*
  1456. {metadocument}
  1457. <function>
  1458. <name>SetRecipient</name>
  1459. <type>BOOLEAN</type>
  1460. <documentation>
  1461. <purpose>Set the address of a message recipient.</purpose>
  1462. <usage>Call this function repeatedly for each recipient right after
  1463. setting the message sender with the
  1464. <functionlink>MailFrom</functionlink> function.</usage>
  1465. <returnvalue>The function returns
  1466. <tt><booleanvalue>1</booleanvalue></tt> if the recipient address is
  1467. successfully set.</returnvalue>
  1468. </documentation>
  1469. <argument>
  1470. <name>recipient</name>
  1471. <type>STRING</type>
  1472. <documentation>
  1473. <purpose>E-mail address of a recipient.</purpose>
  1474. </documentation>
  1475. </argument>
  1476. <do>
  1477. {/metadocument}
  1478. */
  1479. Function SetRecipient($recipient)
  1480. {
  1481. if($this->direct_delivery)
  1482. {
  1483. if(GetType($at=strrpos($recipient,"@"))!="integer")
  1484. return("it was not specified a valid direct recipient");
  1485. $domain=substr($recipient,$at+1);
  1486. switch($this->state)
  1487. {
  1488. case "Disconnected":
  1489. if(!$this->Connect($domain))
  1490. return(0);
  1491. if(!$this->MailFrom(""))
  1492. {
  1493. $error=$this->error;
  1494. $this->Disconnect();
  1495. $this->error=$error;
  1496. return(0);
  1497. }
  1498. break;
  1499. case "SenderSet":
  1500. case "RecipientSet":
  1501. if(strcmp($this->connected_domain,$domain))
  1502. {
  1503. $this->error="it is not possible to deliver directly to recipients of different domains";
  1504. return(0);
  1505. }
  1506. break;
  1507. default:
  1508. $this->error="connection is already established and the recipient is already set";
  1509. return(0);
  1510. }
  1511. }
  1512. else
  1513. {
  1514. switch($this->state)
  1515. {
  1516. case "SenderSet":
  1517. case "RecipientSet":
  1518. break;
  1519. default:
  1520. $this->error="connection is not in the recipient setting state";
  1521. return(0);
  1522. }
  1523. }
  1524. $this->error="";
  1525. if(!$this->PutLine("RCPT TO:<$recipient>"))
  1526. return(0);
  1527. if(IsSet($this->esmtp_extensions["PIPELINING"]))
  1528. {
  1529. $this->pending_recipients++;
  1530. if($this->pending_recipients>=$this->maximum_piped_recipients)
  1531. {
  1532. if(!$this->FlushRecipients())
  1533. return(0);
  1534. }
  1535. }
  1536. else
  1537. {
  1538. if($this->VerifyResultLines(array("250","251"),$responses)<=0)
  1539. return(0);
  1540. }
  1541. $this->state="RecipientSet";
  1542. return(1);
  1543. }
  1544. /*
  1545. {metadocument}
  1546. </do>
  1547. </function>
  1548. {/metadocument}
  1549. */
  1550.  
  1551. /*
  1552. {metadocument}
  1553. <function>
  1554. <name>StartData</name>
  1555. <type>BOOLEAN</type>
  1556. <documentation>
  1557. <purpose>Tell the SMTP server that the message data will start being
  1558. sent.</purpose>
  1559. <usage>Call this function right after you are done setting all the
  1560. message recipients with the
  1561. <functionlink>SetRecipient</functionlink> function.</usage>
  1562. <returnvalue>The function returns
  1563. <tt><booleanvalue>1</booleanvalue></tt> if the server is ready to
  1564. start receiving the message data.</returnvalue>
  1565. </documentation>
  1566. <do>
  1567. {/metadocument}
  1568. */
  1569. Function StartData()
  1570. {
  1571. if(strcmp($this->state,"RecipientSet"))
  1572. {
  1573. $this->error="connection is not in the start sending data state";
  1574. return(0);
  1575. }
  1576. $this->error="";
  1577. if(!$this->PutLine("DATA"))
  1578. return(0);
  1579. if($this->pending_recipients)
  1580. {
  1581. if(!$this->FlushRecipients())
  1582. return(0);
  1583. }
  1584. if($this->VerifyResultLines("354",$responses)<=0)
  1585. return(0);
  1586. $this->state="SendingData";
  1587. return(1);
  1588. }
  1589. /*
  1590. {metadocument}
  1591. </do>
  1592. </function>
  1593. {/metadocument}
  1594. */
  1595.  
  1596. /*
  1597. {metadocument}
  1598. <function>
  1599. <name>PrepareData</name>
  1600. <type>STRING</type>
  1601. <documentation>
  1602. <purpose>Prepare message data to normalize line breaks and escaping
  1603. lines that contain single dots.</purpose>
  1604. <usage>Call this function if the message data you want to send may
  1605. contain line breaks that are not the
  1606. <stringvalue>&#13;&#10;</stringvalue> sequence or it may contain
  1607. lines that just have a single dot.</usage>
  1608. <returnvalue>Resulting normalized messages data.</returnvalue>
  1609. </documentation>
  1610. <argument>
  1611. <name>data</name>
  1612. <type>STRING</type>
  1613. <documentation>
  1614. <purpose>Message data to be prepared.</purpose>
  1615. </documentation>
  1616. </argument>
  1617. <do>
  1618. {/metadocument}
  1619. */
  1620. Function PrepareData($data)
  1621. {
  1622. return(preg_replace(array("/\n\n|\r\r/","/(^|[^\r])\n/","/\r([^\n]|\$)/D","/(^|\n)\\./"),array("\r\n\r\n","\\1\r\n","\r\n\\1","\\1.."),$data));
  1623. }
  1624. /*
  1625. {metadocument}
  1626. </do>
  1627. </function>
  1628. {/metadocument}
  1629. */
  1630.  
  1631. /*
  1632. {metadocument}
  1633. <function>
  1634. <name>SendData</name>
  1635. <type>BOOLEAN</type>
  1636. <documentation>
  1637. <purpose>Send message data.</purpose>
  1638. <usage>Call this function repeatedly for all message data blocks
  1639. to be sent right after start sending message data with the
  1640. <functionlink>StartData</functionlink> function.</usage>
  1641. <returnvalue>The function returns
  1642. <tt><booleanvalue>1</booleanvalue></tt> if the message data was
  1643. sent to the SMTP server successfully.</returnvalue>
  1644. </documentation>
  1645. <argument>
  1646. <name>data</name>
  1647. <type>STRING</type>
  1648. <documentation>
  1649. <purpose>Message data to be sent.</purpose>
  1650. </documentation>
  1651. </argument>
  1652. <do>
  1653. {/metadocument}
  1654. */
  1655. Function SendData($data)
  1656. {
  1657. if(strcmp($this->state,"SendingData"))
  1658. {
  1659. $this->error="connection is not in the sending data state";
  1660. return(0);
  1661. }
  1662. $this->error="";
  1663. return($this->PutData($data));
  1664. }
  1665. /*
  1666. {metadocument}
  1667. </do>
  1668. </function>
  1669. {/metadocument}
  1670. */
  1671.  
  1672. /*
  1673. {metadocument}
  1674. <function>
  1675. <name>EndSendingData</name>
  1676. <type>BOOLEAN</type>
  1677. <documentation>
  1678. <purpose>Tell the server that all the message data was sent.</purpose>
  1679. <usage>Call this function when you are done with sending the message
  1680. data with the <functionlink>SendData</functionlink> function.</usage>
  1681. <returnvalue>The function returns
  1682. <tt><booleanvalue>1</booleanvalue></tt> if the server accepted the
  1683. message.</returnvalue>
  1684. </documentation>
  1685. <do>
  1686. {/metadocument}
  1687. */
  1688. Function EndSendingData()
  1689. {
  1690. if(strcmp($this->state,"SendingData"))
  1691. {
  1692. $this->error="connection is not in the sending data state";
  1693. return(0);
  1694. }
  1695. $this->error="";
  1696. if(!$this->PutLine("\r\n.")
  1697. || $this->VerifyResultLines("250",$responses)<=0)
  1698. return(0);
  1699. $this->state="Connected";
  1700. return(1);
  1701. }
  1702. /*
  1703. {metadocument}
  1704. </do>
  1705. </function>
  1706. {/metadocument}
  1707. */
  1708.  
  1709. /*
  1710. {metadocument}
  1711. <function>
  1712. <name>ResetConnection</name>
  1713. <type>BOOLEAN</type>
  1714. <documentation>
  1715. <purpose>Reset an already established SMTP connection to the initial
  1716. state.</purpose>
  1717. <usage>Call this function when there was an error sending a message
  1718. and you need to skip to sending another message without
  1719. disconnecting.</usage>
  1720. <returnvalue>The function returns
  1721. <tt><booleanvalue>1</booleanvalue></tt> if the connection was
  1722. resetted successfully.</returnvalue>
  1723. </documentation>
  1724. <do>
  1725. {/metadocument}
  1726. */
  1727. Function ResetConnection()
  1728. {
  1729. switch($this->state)
  1730. {
  1731. case "Connected":
  1732. return(1);
  1733. case "SendingData":
  1734. $this->error="can not reset the connection while sending data";
  1735. return(0);
  1736. case "Disconnected":
  1737. $this->error="can not reset the connection before it is established";
  1738. return(0);
  1739. }
  1740. $this->error="";
  1741. if(!$this->PutLine("RSET")
  1742. || $this->VerifyResultLines("250",$responses)<=0)
  1743. return(0);
  1744. $this->state="Connected";
  1745. return(1);
  1746. }
  1747. /*
  1748. {metadocument}
  1749. </do>
  1750. </function>
  1751. {/metadocument}
  1752. */
  1753.  
  1754. /*
  1755. {metadocument}
  1756. <function>
  1757. <name>Disconnect</name>
  1758. <type>BOOLEAN</type>
  1759. <documentation>
  1760. <purpose>Terminate a previously opened connection.</purpose>
  1761. <usage>Call this function after you are done sending your
  1762. messages.</usage>
  1763. <returnvalue>The function returns
  1764. <tt><booleanvalue>1</booleanvalue></tt> if the connection was
  1765. successfully closed.</returnvalue>
  1766. </documentation>
  1767. <argument>
  1768. <name>quit</name>
  1769. <type>BOOLEAN</type>
  1770. <defaultvalue>1</defaultvalue>
  1771. <documentation>
  1772. <purpose>Boolean option that tells whether the class should
  1773. perform the final connection quit handshake, or just close the
  1774. connection without waiting.</purpose>
  1775. </documentation>
  1776. </argument>
  1777. <do>
  1778. {/metadocument}
  1779. */
  1780. Function Disconnect($quit=1)
  1781. {
  1782. if(!strcmp($this->state,"Disconnected"))
  1783. {
  1784. $this->error="it was not previously established a SMTP connection";
  1785. return(0);
  1786. }
  1787. $this->error="";
  1788. if(!strcmp($this->state,"Connected")
  1789. && $quit
  1790. && (!$this->PutLine("QUIT")
  1791. || ($this->VerifyResultLines("221",$responses)<=0
  1792. && !$this->disconnected_error)))
  1793. return(0);
  1794. if($this->disconnected_error)
  1795. $this->disconnected_error=0;
  1796. else
  1797. fclose($this->connection);
  1798. $this->connection=0;
  1799. $this->state="Disconnected";
  1800. if($this->debug)
  1801. $this->OutputDebug("Disconnected.");
  1802. return(1);
  1803. }
  1804. /*
  1805. {metadocument}
  1806. </do>
  1807. </function>
  1808. {/metadocument}
  1809. */
  1810.  
  1811. /*
  1812. {metadocument}
  1813. <function>
  1814. <name>SendMessage</name>
  1815. <type>BOOLEAN</type>
  1816. <documentation>
  1817. <purpose>Send a message in a single call.</purpose>
  1818. <usage>Call this function if you want to send a single messages to a
  1819. small number of recipients in a single call.</usage>
  1820. <returnvalue>The function returns
  1821. <tt><booleanvalue>1</booleanvalue></tt> if the message was sent
  1822. successfully.</returnvalue>
  1823. </documentation>
  1824. <argument>
  1825. <name>sender</name>
  1826. <type>STRING</type>
  1827. <documentation>
  1828. <purpose>E-mail address of the sender.</purpose>
  1829. </documentation>
  1830. </argument>
  1831. <argument>
  1832. <name>recipients</name>
  1833. <type>STRING</type>
  1834. <documentation>
  1835. <purpose>Array with a list of the e-mail addresses of the
  1836. recipients of the message.</purpose>
  1837. </documentation>
  1838. </argument>
  1839. <argument>
  1840. <name>headers</name>
  1841. <type>ARRAY</type>
  1842. <documentation>
  1843. <purpose>Array with a list of the header lines of the message.</purpose>
  1844. </documentation>
  1845. </argument>
  1846. <argument>
  1847. <name>body</name>
  1848. <type>STRING</type>
  1849. <documentation>
  1850. <purpose>Body data of the message.</purpose>
  1851. </documentation>
  1852. </argument>
  1853. <do>
  1854. {/metadocument}
  1855. */
  1856.  
  1857. Function SendMessage_attach($sender,$recipients,$header_data)
  1858. {
  1859. if(($success=$this->Connect()))
  1860. {
  1861. if(($success=$this->MailFrom($sender)))
  1862. {
  1863. for($recipient=0;$recipient<count($recipients);$recipient++)
  1864. {
  1865. if(!($success=$this->SetRecipient($recipients[$recipient])))
  1866. break;
  1867. }
  1868. if($success
  1869. && ($success=$this->StartData()))
  1870. {
  1871. $success=(
  1872. $this->SendData($header_data."\r\n")
  1873.  
  1874. && $this->EndSendingData()
  1875.  
  1876. );
  1877. }
  1878. }
  1879. $error=$this->error;
  1880. $disconnect_success=$this->Disconnect($success);
  1881. if($success)
  1882. $success=$disconnect_success;
  1883. else
  1884. $this->error=$error;
  1885. }
  1886. return($success);
  1887. }
  1888.  
  1889.  
  1890. Function SendMessage($sender,$recipients,$headers,$body)
  1891. {
  1892. if(($success=$this->Connect()))
  1893. {
  1894. if(($success=$this->MailFrom($sender)))
  1895. {
  1896. for($recipient=0;$recipient<count($recipients);$recipient++)
  1897. {
  1898. if(!($success=$this->SetRecipient($recipients[$recipient])))
  1899. break;
  1900. }
  1901. if($success
  1902. && ($success=$this->StartData()))
  1903. {
  1904. for($header_data="",$header=0;$header<count($headers);$header++)
  1905. $header_data.=$headers[$header]."\r\n";
  1906. $success=($this->SendData($header_data."\r\n")
  1907. && $this->SendData($this->PrepareData($body))
  1908. && $this->EndSendingData());
  1909. }
  1910. }
  1911. $error=$this->error;
  1912. $disconnect_success=$this->Disconnect($success);
  1913. if($success)
  1914. $success=$disconnect_success;
  1915. else
  1916. $this->error=$error;
  1917. }
  1918. return($success);
  1919. }
  1920. /*
  1921. {metadocument}
  1922. </do>
  1923. </function>
  1924. {/metadocument}
  1925. */
  1926.  
  1927. };
  1928.  
  1929. /*
  1930.  
  1931. {metadocument}
  1932. </class>
  1933. {/metadocument}
  1934.  
  1935. */
  1936.  
  1937. ?>
Add Comment
Please, Sign In to add comment