Projet

Général

Profil

Télécharger (21,9 ko) Statistiques
| Branche: | Tag: | Révision:

univnautes / etc / inc / smtp.inc @ 36de334e

1
<?php
2
/*
3
 * smtp.php
4
 *
5
 * @(#) $Header$
6
 *
7
 */
8

    
9
/*
10
	pfSense_MODULE:	notifications
11
*/
12

    
13
class smtp_class
14
{
15
	var $user="";
16
	var $realm="";
17
	var $password="";
18
	var $workstation="";
19
	var $authentication_mechanism="";
20
	var $host_name="";
21
	var $host_port=25;
22
	var $ssl=0;
23
	var $tls=0;
24
	var $localhost="";
25
	var $timeout=0;
26
	var $data_timeout=0;
27
	var $direct_delivery=0;
28
	var $error="";
29
	var $debug=0;
30
	var $html_debug=0;
31
	var $esmtp=1;
32
	var $esmtp_host="";
33
	var $esmtp_extensions=array();
34
	var $maximum_piped_recipients=100;
35
	var $exclude_address="";
36
	var $getmxrr="GetMXRR";
37
	var $pop3_auth_host="";
38
	var $pop3_auth_port=110;
39

    
40
	/* private variables - DO NOT ACCESS */
41

    
42
	var $state="Disconnected";
43
	var $connection=0;
44
	var $pending_recipients=0;
45
	var $next_token="";
46
	var $direct_sender="";
47
	var $connected_domain="";
48
	var $result_code;
49
	var $disconnected_error=0;
50

    
51
	/* Private methods - DO NOT CALL */
52

    
53
	Function Tokenize($string,$separator="")
54
	{
55
		if(!strcmp($separator,""))
56
		{
57
			$separator=$string;
58
			$string=$this->next_token;
59
		}
60
		for($character=0;$character<strlen($separator);$character++)
61
		{
62
			if(GetType($position=strpos($string,$separator[$character]))=="integer")
63
				$found=(IsSet($found) ? min($found,$position) : $position);
64
		}
65
		if(IsSet($found))
66
		{
67
			$this->next_token=substr($string,$found+1);
68
			return(substr($string,0,$found));
69
		}
70
		else
71
		{
72
			$this->next_token="";
73
			return($string);
74
		}
75
	}
76

    
77
	Function OutputDebug($message)
78
	{
79
		$message.="\n";
80
		if($this->html_debug)
81
			$message=str_replace("\n","<br />\n",HtmlEntities($message));
82
		echo $message;
83
		flush();
84
	}
85

    
86
	Function SetDataAccessError($error)
87
	{
88
		$this->error=$error;
89
		if(function_exists("socket_get_status"))
90
		{
91
			$status=socket_get_status($this->connection);
92
			if($status["timed_out"])
93
				$this->error.=gettext(": data access time out");
94
			elseif($status["eof"])
95
			{
96
				$this->error.=gettext(": the server disconnected");
97
				$this->disconnected_error=1;
98
			}
99
		}
100
	}
101

    
102
	Function GetLine()
103
	{
104
		for($line="";;)
105
		{
106
			if(feof($this->connection))
107
			{
108
				$this->error=gettext("reached the end of data while reading from the SMTP server conection");
109
				return("");
110
			}
111
			if(GetType($data=@fgets($this->connection,100))!="string"
112
			|| strlen($data)==0)
113
			{
114
				$this->SetDataAccessError(gettext("it was not possible to read line from the SMTP server"));
115
				return("");
116
			}
117
			$line.=$data;
118
			$length=strlen($line);
119
			if($length>=2
120
			&& substr($line,$length-2,2)=="\r\n")
121
			{
122
				$line=substr($line,0,$length-2);
123
				if($this->debug)
124
					$this->OutputDebug("S $line");
125
				return($line);
126
			}
127
		}
128
	}
129

    
130
	Function PutLine($line)
131
	{
132
		if($this->debug)
133
			$this->OutputDebug("C $line");
134
		if(!@fputs($this->connection,"$line\r\n"))
135
		{
136
			$this->SetDataAccessError(gettext("it was not possible to send a line to the SMTP server"));
137
			return(0);
138
		}
139
		return(1);
140
	}
141

    
142
	Function PutData(&$data)
143
	{
144
		if(strlen($data))
145
		{
146
			if($this->debug)
147
				$this->OutputDebug("C $data");
148
			if(!@fputs($this->connection,$data))
149
			{
150
				$this->SetDataAccessError(gettext("it was not possible to send data to the SMTP server"));
151
				return(0);
152
			}
153
		}
154
		return(1);
155
	}
156

    
157
	Function VerifyResultLines($code,&$responses)
158
	{
159
		$responses=array();
160
		Unset($this->result_code);
161
		while(strlen($line=$this->GetLine($this->connection)))
162
		{
163
			if(IsSet($this->result_code))
164
			{
165
				if(strcmp($this->Tokenize($line," -"),$this->result_code))
166
				{
167
					$this->error=$line;
168
					return(0);
169
				}
170
			}
171
			else
172
			{
173
				$this->result_code=$this->Tokenize($line," -");
174
				if(GetType($code)=="array")
175
				{
176
					for($codes=0;$codes<count($code) && strcmp($this->result_code,$code[$codes]);$codes++);
177
					if($codes>=count($code))
178
					{
179
						$this->error=$line;
180
						return(0);
181
					}
182
				}
183
				else
184
				{
185
					if(strcmp($this->result_code,$code))
186
					{
187
						$this->error=$line;
188
						return(0);
189
					}
190
				}
191
			}
192
			$responses[]=$this->Tokenize("");
193
			if(!strcmp($this->result_code,$this->Tokenize($line," ")))
194
				return(1);
195
		}
196
		return(-1);
197
	}
198

    
199
	Function FlushRecipients()
200
	{
201
		if($this->pending_sender)
202
		{
203
			if($this->VerifyResultLines("250",$responses)<=0)
204
				return(0);
205
			$this->pending_sender=0;
206
		}
207
		for(;$this->pending_recipients;$this->pending_recipients--)
208
		{
209
			if($this->VerifyResultLines(array("250","251"),$responses)<=0)
210
				return(0);
211
		}
212
		return(1);
213
	}
214

    
215
	Function ConnectToHost($domain, $port, $resolve_message)
216
	{
217
		if($this->ssl || $this->tls)
218
		{
219
			$version=explode(".",function_exists("phpversion") ? phpversion() : "3.0.7");
220
			$php_version=intval($version[0])*1000000+intval($version[1])*1000+intval($version[2]);
221
			if($php_version<4003000)
222
				return(gettext("establishing SSL connections requires at least PHP version 4.3.0"));
223
			if(!function_exists("extension_loaded")
224
			|| !extension_loaded("openssl"))
225
				return(gettext("establishing SSL connections requires the OpenSSL extension enabled"));
226
		}
227
		if(preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/',$domain))
228
			$ip=$domain;
229
		else
230
		{
231
			if($this->debug)
232
				$this->OutputDebug($resolve_message);
233
			if(!strcmp($ip=@gethostbyname($domain),$domain))
234
				return(sprintf(gettext("could not resolve host \"%s\""), $domain));
235
		}
236
		if(strlen($this->exclude_address)
237
		&& !strcmp(@gethostbyname($this->exclude_address),$ip))
238
			return(sprintf(gettext("domain \"%s\" resolved to an address excluded to be valid"), $domain));
239
		if($this->debug)
240
			$this->OutputDebug(sprintf(gettext('Connecting to host address "%1$s" port %2$s...'), $ip, $port));
241
		if(($this->connection=($this->timeout ? @fsockopen(($this->ssl ? "ssl://" : "").$ip,$port,$errno,$error,$this->timeout) : @fsockopen(($this->ssl ? "ssl://" : "").$ip,$port))))
242
			return("");
243
		$error=($this->timeout ? strval($error) : "??");
244
		switch($error)
245
		{
246
			case "-3":
247
				return(gettext("-3 socket could not be created"));
248
			case "-4":
249
				return(sprintf(gettext("-4 dns lookup on hostname \"%s\" failed"), $domain));
250
			case "-5":
251
				return(gettext("-5 connection refused or timed out"));
252
			case "-6":
253
				return(gettext("-6 fdopen() call failed"));
254
			case "-7":
255
				return(gettext("-7 setvbuf() call failed"));
256
		}
257
		return(sprintf(gettext('could not connect to the host "%1$s": %2$s'), $domain, $error));
258
	}
259

    
260
	Function SASLAuthenticate($mechanisms, $credentials, &$authenticated, &$mechanism)
261
	{
262
		$authenticated=0;
263
		if(!function_exists("class_exists")
264
		|| !class_exists("sasl_client_class"))
265
		{
266
			$this->error=gettext("it is not possible to authenticate using the specified mechanism because the SASL library class is not loaded");
267
			return(0);
268
		}
269
		$sasl=new sasl_client_class;
270
		$sasl->SetCredential("user",$credentials["user"]);
271
		$sasl->SetCredential("password",$credentials["password"]);
272
		if(IsSet($credentials["realm"]))
273
			$sasl->SetCredential("realm",$credentials["realm"]);
274
		if(IsSet($credentials["workstation"]))
275
			$sasl->SetCredential("workstation",$credentials["workstation"]);
276
		if(IsSet($credentials["mode"]))
277
			$sasl->SetCredential("mode",$credentials["mode"]);
278
		do
279
		{
280
			$status=$sasl->Start($mechanisms,$message,$interactions);
281
		}
282
		while($status==SASL_INTERACT);
283
		switch($status)
284
		{
285
			case SASL_CONTINUE:
286
				break;
287
			case SASL_NOMECH:
288
				if(strlen($this->authentication_mechanism))
289
				{
290
					$this->error=printf(gettext('authenticated mechanism %1$s may not be used: %2$s'), $this->authentication_mechanism, $sasl->error);
291
					return(0);
292
				}
293
				break;
294
			default:
295
				$this->error=gettext("Could not start the SASL authentication client:") . " ".$sasl->error;
296
				return(0);
297
		}
298
		if(strlen($mechanism=$sasl->mechanism))
299
		{
300
			if($this->PutLine("AUTH ".$sasl->mechanism.(IsSet($message) ? " ".base64_encode($message) : ""))==0)
301
			{
302
				$this->error=gettext("Could not send the AUTH command");
303
				return(0);
304
			}
305
			if(!$this->VerifyResultLines(array("235","334"),$responses))
306
				return(0);
307
			switch($this->result_code)
308
			{
309
				case "235":
310
					$response="";
311
					$authenticated=1;
312
					break;
313
				case "334":
314
					$response=base64_decode($responses[0]);
315
					break;
316
				default:
317
					$this->error=gettext("Authentication error:") . " ".$responses[0];
318
					return(0);
319
			}
320
			for(;!$authenticated;)
321
			{
322
				do
323
				{
324
					$status=$sasl->Step($response,$message,$interactions);
325
				}
326
				while($status==SASL_INTERACT);
327
				switch($status)
328
				{
329
					case SASL_CONTINUE:
330
						if($this->PutLine(base64_encode($message))==0)
331
						{
332
							$this->error=gettext("Could not send the authentication step message");
333
							return(0);
334
						}
335
						if(!$this->VerifyResultLines(array("235","334"),$responses))
336
							return(0);
337
						switch($this->result_code)
338
						{
339
							case "235":
340
								$response="";
341
								$authenticated=1;
342
								break;
343
							case "334":
344
								$response=base64_decode($responses[0]);
345
								break;
346
							default:
347
								$this->error=gettext("Authentication error:") . " ".$responses[0];
348
								return(0);
349
						}
350
						break;
351
					default:
352
						$this->error=gettext("Could not process the SASL authentication step:") . " ".$sasl->error;
353
						return(0);
354
				}
355
			}
356
		}
357
		return(1);
358
	}
359

    
360
	/* Public methods */
361

    
362
	Function Connect($domain="")
363
	{
364
		if(strcmp($this->state,"Disconnected"))
365
		{
366
			$this->error=gettext("connection is already established");
367
			return(0);
368
		}
369
		$this->disconnected_error=0;
370
		$this->error=$error="";
371
		$this->esmtp_host="";
372
		$this->esmtp_extensions=array();
373
		$hosts=array();
374
		if($this->direct_delivery)
375
		{
376
			if(strlen($domain)==0)
377
				return(1);
378
			$hosts=$weights=$mxhosts=array();
379
			$getmxrr=$this->getmxrr;
380
			if(function_exists($getmxrr)
381
			&& $getmxrr($domain,$hosts,$weights))
382
			{
383
				for($host=0;$host<count($hosts);$host++)
384
					$mxhosts[$weights[$host]]=$hosts[$host];
385
				KSort($mxhosts);
386
				for(Reset($mxhosts),$host=0;$host<count($mxhosts);Next($mxhosts),$host++)
387
					$hosts[$host]=$mxhosts[Key($mxhosts)];
388
			}
389
			else
390
			{
391
				if(strcmp(@gethostbyname($domain),$domain)!=0)
392
					$hosts[]=$domain;
393
			}
394
		}
395
		else
396
		{
397
			if(strlen($this->host_name))
398
				$hosts[]=$this->host_name;
399
			if(strlen($this->pop3_auth_host))
400
			{
401
				$user=$this->user;
402
				if(strlen($user)==0)
403
				{
404
					$this->error=gettext("it was not specified the POP3 authentication user");
405
					return(0);
406
				}
407
				$password=$this->password;
408
				if(strlen($password)==0)
409
				{
410
					$this->error=gettext("it was not specified the POP3 authentication password");
411
					return(0);
412
				}
413
				$domain=$this->pop3_auth_host;
414
				$this->error=$this->ConnectToHost($domain, $this->pop3_auth_port, sprintf(gettext("Resolving POP3 authentication host \"%s\"..."), $domain));
415
				if(strlen($this->error))
416
					return(0);
417
				if(strlen($response=$this->GetLine())==0)
418
					return(0);
419
				if(strcmp($this->Tokenize($response," "),"+OK"))
420
				{
421
					$this->error=gettext("POP3 authentication server greeting was not found");
422
					return(0);
423
				}
424
				if(!$this->PutLine("USER ".$this->user)
425
				|| strlen($response=$this->GetLine())==0)
426
					return(0);
427
				if(strcmp($this->Tokenize($response," "),"+OK"))
428
				{
429
					$this->error=gettext("POP3 authentication user was not accepted:") . " ".$this->Tokenize("\r\n");
430
					return(0);
431
				}
432
				if(!$this->PutLine("PASS ".$password)
433
				|| strlen($response=$this->GetLine())==0)
434
					return(0);
435
				if(strcmp($this->Tokenize($response," "),"+OK"))
436
				{
437
					$this->error=gettext("POP3 authentication password was not accepted:") . " ".$this->Tokenize("\r\n");
438
					return(0);
439
				}
440
				fclose($this->connection);
441
				$this->connection=0;
442
			}
443
		}
444
		if(count($hosts)==0)
445
		{
446
			$this->error=gettext("could not determine the SMTP to connect");
447
			return(0);
448
		}
449
		for($host=0, $error="not connected";strlen($error) && $host<count($hosts);$host++)
450
		{
451
			$domain=$hosts[$host];
452
			$error=$this->ConnectToHost($domain, $this->host_port, sprintf(gettext("Resolving SMTP server domain \"%s\"..."), $domain));
453
		}
454
		if(strlen($error))
455
		{
456
			$this->error=$error;
457
			return(0);
458
		}
459
		$timeout=($this->data_timeout ? $this->data_timeout : $this->timeout);
460
		if($timeout
461
		&& function_exists("socket_set_timeout"))
462
			socket_set_timeout($this->connection,$timeout,0);
463
		if($this->debug)
464
			$this->OutputDebug(sprintf(gettext("Connected to SMTP server \"%s\"."), $domain));
465
		if($this->VerifyResultLines("220",$responses)>0)
466
		{
467
			// Send our HELLO
468
			$success = $this->hello($this->hostname());
469
			if ($this->tls)
470
				$success = $this->startTLS();
471

    
472
			if($success
473
			&& strlen($this->user)
474
			&& strlen($this->pop3_auth_host)==0)
475
			{
476
				if(!IsSet($this->esmtp_extensions["AUTH"]))
477
				{
478
					$this->error = gettext("server does not require authentication");
479
					$success=0;
480
				}
481
				else
482
				{
483
					if(strlen($this->authentication_mechanism))
484
						$mechanisms=array($this->authentication_mechanism);
485
					else
486
					{
487
						$mechanisms=array();
488
						for($authentication=$this->Tokenize($this->esmtp_extensions["AUTH"]," ");strlen($authentication);$authentication=$this->Tokenize(" "))
489
							$mechanisms[]=$authentication;
490
					}
491
					$credentials=array(
492
						"user"=>$this->user,
493
						"password"=>$this->password
494
					);
495
					if(strlen($this->realm))
496
						$credentials["realm"]=$this->realm;
497
					if(strlen($this->workstation))
498
						$credentials["workstation"]=$this->workstation;
499
					$success=$this->SASLAuthenticate($mechanisms,$credentials,$authenticated,$mechanism);
500
					if(!$success
501
					&& !strcmp($mechanism,"PLAIN"))
502
					{
503
						/*
504
						 * Author:  Russell Robinson, 25 May 2003, http://www.tectite.com/
505
						 * Purpose: Try various AUTH PLAIN authentication methods.
506
						 */
507
						$mechanisms=array("PLAIN");
508
						$credentials=array(
509
							"user"=>$this->user,
510
							"password"=>$this->password
511
						);
512
						if(strlen($this->realm))
513
						{
514
							/*
515
							 * According to: http://www.sendmail.org/~ca/email/authrealms.html#authpwcheck_method
516
							 * some sendmails won't accept the realm, so try again without it
517
							 */
518
							$success=$this->SASLAuthenticate($mechanisms,$credentials,$authenticated,$mechanism);
519
						}
520
						if(!$success)
521
						{
522
							/*
523
							 * It was seen an EXIM configuration like this:
524
							 * user^password^unused
525
							 */
526
							$credentials["mode"]=SASL_PLAIN_EXIM_DOCUMENTATION_MODE;
527
							$success=$this->SASLAuthenticate($mechanisms,$credentials,$authenticated,$mechanism);
528
						}
529
						if(!$success)
530
						{
531
							/*
532
							 * ... though: http://exim.work.de/exim-html-3.20/doc/html/spec_36.html
533
							 * specifies: ^user^password
534
							 */
535
							$credentials["mode"]=SASL_PLAIN_EXIM_MODE;
536
							$success=$this->SASLAuthenticate($mechanisms,$credentials,$authenticated,$mechanism);
537
						}
538
					}
539
					if($success
540
					&& strlen($mechanism)==0)
541
					{
542
						$this->error=gettext("it is not supported any of the authentication mechanisms required by the server");
543
						$success=0;
544
					}
545
				}
546
			}
547
		}
548
		if($success)
549
		{
550
			$this->state="Connected";
551
			$this->connected_domain=$domain;
552
		}
553
		else
554
		{
555
			fclose($this->connection);
556
			$this->connection=0;
557
		}
558
		return($success);
559
	}
560

    
561
	Function hostname() {
562
		if(!strcmp($localhost=$this->localhost,"")
563
		&& !strcmp($localhost=getenv("SERVER_NAME"),"")
564
		&& !strcmp($localhost=getenv("HOST"),"")
565
		&& !strcmp($localhost=getenv("HOSTNAME"),"")
566
		&& !strcmp($localhost=gethostname(),""))
567
			$localhost="localhost";
568

    
569
		return $localhost;
570
	}
571

    
572
	Function hello()
573
	{
574
		$success = 0;
575
		$fallback = 1;
576
		if ($this->esmtp || strlen($this->user)) {
577
			if ($this->PutLine("EHLO ".$this->hostname())) {
578
				if (($success_code = $this->VerifyResultLines("250",$responses)) > 0) {
579
					$this->esmtp_host = $this->Tokenize($responses[0]," ");
580
					for($response=1;$response<count($responses);$response++) {
581
						$extension = strtoupper($this->Tokenize($responses[$response]," "));
582
						$this->esmtp_extensions[$extension]=$this->Tokenize("");
583
					}
584
					$success = 1;
585
					$fallback = 0;
586
				} else {
587
					if ($success_code == 0) {
588
						$code = $this->Tokenize($this->error," -");
589
						switch($code) {
590
							case "421":
591
								$fallback=0;
592
								break;
593
						}
594
					}
595
				}
596
			} else
597
				$fallback=0;
598
		}
599

    
600
		if ($fallback) {
601
			if ($this->PutLine("HELO $localhost") && $this->VerifyResultLines("250",$responses)>0)
602
				$success=1;
603
		}
604
		return $success;
605
	}
606

    
607
	Function startTLS() {
608
		if ($this->PutLine("STARTTLS") && $this->VerifyResultLines("220",$responses)>0) {
609
			if (!stream_socket_enable_crypto($this->connection,true,STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
610
				return false;
611
			} else {
612
				// Resend HELO since session has been reset
613
				return $this->hello($this->hostname);
614
			}
615
		} else
616
			return false;
617
	}
618

    
619
	Function MailFrom($sender)
620
	{
621
		if($this->direct_delivery)
622
		{
623
			switch($this->state)
624
			{
625
				case "Disconnected":
626
					$this->direct_sender=$sender;
627
					return(1);
628
				case "Connected":
629
					$sender=$this->direct_sender;
630
					break;
631
				default:
632
					$this->error=gettext("direct delivery connection is already established and sender is already set");
633
					return(0);
634
			}
635
		}
636
		else
637
		{
638
			if(strcmp($this->state,"Connected"))
639
			{
640
				$this->error=gettext("connection is not in the initial state");
641
				return(0);
642
			}
643
		}
644
		$this->error="";
645
		if(!$this->PutLine("MAIL FROM:<$sender>"))
646
			return(0);
647
		if(!IsSet($this->esmtp_extensions["PIPELINING"])
648
		&& $this->VerifyResultLines("250",$responses)<=0)
649
			return(0);
650
		$this->state="SenderSet";
651
		if(IsSet($this->esmtp_extensions["PIPELINING"]))
652
			$this->pending_sender=1;
653
		$this->pending_recipients=0;
654
		return(1);
655
	}
656

    
657
	Function SetRecipient($recipient)
658
	{
659
		if($this->direct_delivery)
660
		{
661
			if(GetType($at=strrpos($recipient,"@"))!="integer")
662
				return(gettext("it was not specified a valid direct recipient"));
663
			$domain=substr($recipient,$at+1);
664
			switch($this->state)
665
			{
666
				case "Disconnected":
667
					if(!$this->Connect($domain))
668
						return(0);
669
					if(!$this->MailFrom(""))
670
					{
671
						$error=$this->error;
672
						$this->Disconnect();
673
						$this->error=$error;
674
						return(0);
675
					}
676
					break;
677
				case "SenderSet":
678
				case "RecipientSet":
679
					if(strcmp($this->connected_domain,$domain))
680
					{
681
						$this->error=gettext("it is not possible to deliver directly to recipients of different domains");
682
						return(0);
683
					}
684
					break;
685
				default:
686
					$this->error=gettext("connection is already established and the recipient is already set");
687
					return(0);
688
			}
689
		}
690
		else
691
		{
692
			switch($this->state)
693
			{
694
				case "SenderSet":
695
				case "RecipientSet":
696
					break;
697
				default:
698
					$this->error=gettext("connection is not in the recipient setting state");
699
					return(0);
700
			}
701
		}
702
		$this->error="";
703
		if(!$this->PutLine("RCPT TO:<$recipient>"))
704
			return(0);
705
		if(IsSet($this->esmtp_extensions["PIPELINING"]))
706
		{
707
			$this->pending_recipients++;
708
			if($this->pending_recipients>=$this->maximum_piped_recipients)
709
			{
710
				if(!$this->FlushRecipients())
711
					return(0);
712
			}
713
		}
714
		else
715
		{
716
			if($this->VerifyResultLines(array("250","251"),$responses)<=0)
717
				return(0);
718
		}
719
		$this->state="RecipientSet";
720
		return(1);
721
	}
722

    
723
	Function StartData()
724
	{
725
		if(strcmp($this->state,"RecipientSet"))
726
		{
727
			$this->error=gettext("connection is not in the start sending data state");
728
			return(0);
729
		}
730
		$this->error="";
731
		if(!$this->PutLine("DATA"))
732
			return(0);
733
		if($this->pending_recipients)
734
		{
735
			if(!$this->FlushRecipients())
736
				return(0);
737
		}
738
		if($this->VerifyResultLines("354",$responses)<=0)
739
			return(0);
740
		$this->state="SendingData";
741
		return(1);
742
	}
743

    
744
	Function PrepareData(&$data,&$output,$preg=1)
745
	{
746
		if($preg
747
		&& function_exists("preg_replace"))
748
			$output=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);
749
		else
750
			$output=ereg_replace("(^|\n)\\.","\\1..",ereg_replace("\r([^\n]|\$)","\r\n\\1",ereg_replace("(^|[^\r])\n","\\1\r\n",ereg_replace("\n\n|\r\r","\r\n\r\n",$data))));
751
	}
752

    
753
	Function SendData($data)
754
	{
755
		if(strcmp($this->state,"SendingData"))
756
		{
757
			$this->error=gettext("connection is not in the sending data state");
758
			return(0);
759
		}
760
		$this->error="";
761
		return($this->PutData($data));
762
	}
763

    
764
	Function EndSendingData()
765
	{
766
		if(strcmp($this->state,"SendingData"))
767
		{
768
			$this->error=gettext("connection is not in the sending data state");
769
			return(0);
770
		}
771
		$this->error="";
772
		if(!$this->PutLine("\r\n.")
773
		|| $this->VerifyResultLines("250",$responses)<=0)
774
			return(0);
775
		$this->state="Connected";
776
		return(1);
777
	}
778

    
779
	Function ResetConnection()
780
	{
781
		switch($this->state)
782
		{
783
			case "Connected":
784
				return(1);
785
			case "SendingData":
786
				$this->error="can not reset the connection while sending data";
787
				return(0);
788
			case "Disconnected":
789
				$this->error="can not reset the connection before it is established";
790
				return(0);
791
		}
792
		$this->error="";
793
		if(!$this->PutLine("RSET")
794
		|| $this->VerifyResultLines("250",$responses)<=0)
795
			return(0);
796
		$this->state="Connected";
797
		return(1);
798
	}
799

    
800
	Function Disconnect($quit=1)
801
	{
802
		if(!strcmp($this->state,"Disconnected"))
803
		{
804
			$this->error=gettext("it was not previously established a SMTP connection");
805
			return(0);
806
		}
807
		$this->error="";
808
		if(!strcmp($this->state,"Connected")
809
		&& $quit
810
		&& (!$this->PutLine("QUIT")
811
		|| ($this->VerifyResultLines("221",$responses)<=0
812
		&& !$this->disconnected_error)))
813
			return(0);
814
		if($this->disconnected_error)
815
			$this->disconnected_error=0;
816
		else
817
			fclose($this->connection);
818
		$this->connection=0;
819
		$this->state="Disconnected";
820
		if($this->debug)
821
			$this->OutputDebug("Disconnected.");
822
		return(1);
823
	}
824

    
825
	Function SendMessage($sender,$recipients,$headers,$body)
826
	{
827
		if(($success=$this->Connect()))
828
		{
829
			if(($success=$this->MailFrom($sender)))
830
			{
831
				for($recipient=0;$recipient<count($recipients);$recipient++)
832
				{
833
					if(!($success=$this->SetRecipient($recipients[$recipient])))
834
						break;
835
				}
836
				if($success
837
				&& ($success=$this->StartData()))
838
				{
839
					for($header_data="",$header=0;$header<count($headers);$header++)
840
						$header_data.=$headers[$header]."\r\n";
841
					if(($success=$this->SendData($header_data."\r\n")))
842
					{
843
						$this->PrepareData($body,$body_data);
844
						$success=$this->SendData($body_data);
845
					}
846
					if($success)
847
						$success=$this->EndSendingData();
848
				}
849
			}
850
			$error=$this->error;
851
			$disconnect_success=$this->Disconnect($success);
852
			if($success)
853
				$success=$disconnect_success;
854
			else
855
				$this->error=$error;
856
		}
857
		return($success);
858
	}
859

    
860
};
861

    
862
?>
(51-51/67)