PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.16
VikBooking Hotel Booking Engine & PMS v1.8.16
1.8.16 1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 All 37 releases
← All changes | site/class/email_message.php +3549 -0 1.6.3 → 1.8.16 View file →
@@ -1,0 +1,3549 @@
1 +<?php
2 +/**
3 + * @package VikBooking
4 + * @subpackage com_vikbooking
5 + * @author Alessio Gaggii - e4j - Extensionsforjoomla.com
6 + * @copyright Copyright (C) 2018 e4j - Extensionsforjoomla.com. All rights reserved.
7 + * @license GNU General Public License version 2 or later; see LICENSE
8 + * @link https://vikwp.com
9 + */
10 +
11 +defined('ABSPATH') or die('No script kiddies please!');
12 +
13 +class email_message_class
14 +{
15 + /* Private variables */
16 +
17 + var $headers=array("To"=>"","Subject"=>"");
18 + var $body=-1;
19 + var $body_parts=0;
20 + var $parts=array();
21 + var $total_parts=0;
22 + var $free_parts=array();
23 + var $total_free_parts=0;
24 + var $delivery=array("State"=>"");
25 + var $next_token="";
26 + var $php_version=0;
27 + var $mailings=array();
28 + var $last_mailing=0;
29 + var $header_length_limit=512;
30 + var $auto_message_id=1;
31 + var $mailing_path="";
32 + var $body_cache=array();
33 + var $line_break="\n";
34 + var $line_length=75;
35 + var $ruler="_";
36 + var $email_address_pattern="([-!#\$%&'*+./0-9=?A-Z^_`a-z{|}~])+@([-!#\$%&'*+/0-9=?A-Z^_`a-z{|}~]+\\.)+[a-zA-Z]{2,6}";
37 + var $bulk_mail=0;
38 +
39 + /* Public variables */
40 +
41 +/*
42 +{metadocument}
43 + <variable>
44 + <name>email_regular_expression</name>
45 + <type>STRING</type>
46 + <value>^([-!#$%&amp;'*+./0-9=?A-Z^_`a-z{|}~])+@([-!#$%&amp;'*+/0-9=?A-Z^_`a-z{|}~]+\.)+[a-zA-Z]{2,6}$</value>
47 + <documentation>
48 + <purpose>Specify the regular expression that is used by the
49 + <functionlink>ValidateEmailAddress</functionlink> function to
50 + verify whether a given e-mail address may be valid.</purpose>
51 + <usage>Do not change this variable unless you have reason to believe
52 + that it is rejecting existing e-mail addresses that are known to be
53 + valid.</usage>
54 + </documentation>
55 + </variable>
56 +{/metadocument}
57 +*/
58 + var $email_regular_expression="^([-!#\$%&'*+./0-9=?A-Z^_`a-z{|}~])+@([-!#\$%&'*+/0-9=?A-Z^_`a-z{|}~]+\\.)+[a-zA-Z]{2,6}\$";
59 +
60 +/*
61 +{metadocument}
62 + <variable>
63 + <name>mailer</name>
64 + <type>STRING</type>
65 + <value>http://www.phpclasses.org/mimemessage $Revision: 1.92 $</value>
66 + <documentation>
67 + <purpose>Specify the base text that is used identify the name and the
68 + version of the class that is used to send the message by setting an
69 + implicit the <tt>X-Mailer</tt> message header. This is meant
70 + mostly to assist on the debugging of delivery problems.</purpose>
71 + <usage>Change this to set another mailer identification string or
72 + leave it to an empty string to prevent that the <tt>X-Mailer</tt>
73 + header be added to the message.</usage>
74 + </documentation>
75 + </variable>
76 +{/metadocument}
77 +*/
78 + var $mailer='';
79 +
80 +/*
81 +{metadocument}
82 + <variable>
83 + <name>mailer_delivery</name>
84 + <type>STRING</type>
85 + <value>mail</value>
86 + <documentation>
87 + <purpose>Specify the text that is used to identify the mail
88 + delivery class or sub-class. This text is appended to the
89 + <tt>X-Mailer</tt> header text defined by the
90 + <variablelink>mailer</variablelink> variable.</purpose>
91 + <usage>This variable should only be redefined by the different mail
92 + delivery sub-classes.</usage>
93 + </documentation>
94 + </variable>
95 +{/metadocument}
96 +*/
97 + var $mailer_delivery='mail';
98 +
99 +/*
100 +{metadocument}
101 + <variable>
102 + <name>default_charset</name>
103 + <type>STRING</type>
104 + <value>ISO-8859-1</value>
105 + <documentation>
106 + <purpose>Specify the default character set to be assumed for the
107 + message headers and body text.</purpose>
108 + <usage>Change this variable to the correct character set name if it
109 + is different than the default.</usage>
110 + </documentation>
111 + </variable>
112 +{/metadocument}
113 +*/
114 + //var $default_charset="ISO-8859-1";
115 + var $default_charset="UTF-8";
116 +
117 +/*
118 +{metadocument}
119 + <variable>
120 + <name>line_quote_prefix</name>
121 + <type>STRING</type>
122 + <value>&gt; </value>
123 + <documentation>
124 + <purpose>Specify the default line quote prefix text used by the
125 + <functionlink>QuoteText</functionlink> function.</purpose>
126 + <usage>Change it only if you prefer to quote lines marking them with
127 + a different line prefix.</usage>
128 + </documentation>
129 + </variable>
130 +{/metadocument}
131 +*/
132 + var $line_quote_prefix="> ";
133 +
134 +/*
135 +{metadocument}
136 + <variable>
137 + <name>break_long_lines</name>
138 + <type>BOOLEAN</type>
139 + <value>1</value>
140 + <documentation>
141 + <purpose>Determine whether lines exceeding the length limit will be
142 + broken by the line break character when using the
143 + <functionlink>WrapText</functionlink> function.</purpose>
144 + <usage>Change it only if you to avoid breaking long lines without
145 + any space characters, like for instance of messages with long
146 + URLs.</usage>
147 + </documentation>
148 + </variable>
149 +{/metadocument}
150 +*/
151 + var $break_long_lines=1;
152 +
153 +/*
154 +{metadocument}
155 + <variable>
156 + <name>file_buffer_length</name>
157 + <type>INTEGER</type>
158 + <value>8000</value>
159 + <documentation>
160 + <purpose>Specify the length of the buffer that is used to read
161 + files in chunks of limited size.</purpose>
162 + <usage>The default value may be increased if you have plenty of
163 + memory and want to benefit from additional speed when processing
164 + the files that are used to compose messages.</usage>
165 + </documentation>
166 + </variable>
167 +{/metadocument}
168 +*/
169 + var $file_buffer_length=8000;
170 +
171 +/*
172 +{metadocument}
173 + <variable>
174 + <name>debug</name>
175 + <type>STRING</type>
176 + <value></value>
177 + <documentation>
178 + <purpose>Specify the name of a function that is called whenever an
179 + error occurs.</purpose>
180 + <usage>If you need to track the errors that may happen during the use
181 + of the class, set this variable to the name of a callback function.
182 + It should take only one argument that is the error message. When
183 + this variable is set to an empty string, no debug callback function
184 + is called.</usage>
185 + </documentation>
186 + </variable>
187 +{/metadocument}
188 +*/
189 + var $debug="";
190 +
191 +/*
192 +{metadocument}
193 + <variable>
194 + <name>cache_body</name>
195 + <type>BOOLEAN</type>
196 + <value>0</value>
197 + <documentation>
198 + <purpose>Specify whether the message bodies that are generated by the
199 + class before sending, should be cached in memory to be reused on
200 + the next message delivery.</purpose>
201 + <usage>Set this variable to <tt><booleanvalue>1</booleanvalue></tt>
202 + if you intend to send the a message with the same body to many
203 + recipients, so the class avoids the overhead of regenerating
204 + messages with the same content.</usage>
205 + </documentation>
206 + </variable>
207 +{/metadocument}
208 +*/
209 + var $cache_body=0;
210 +
211 +/*
212 +{metadocument}
213 + <variable>
214 + <name>error</name>
215 + <type>STRING</type>
216 + <value></value>
217 + <documentation>
218 + <purpose>Store the last error return by any function that may fail
219 + due to some error.</purpose>
220 + <usage>Do not change this variable value unless you intend to clear
221 + the error status by setting it to an empty string.</usage>
222 + </documentation>
223 + </variable>
224 +{/metadocument}
225 +*/
226 + var $error="";
227 +
228 +/*
229 +{metadocument}
230 + <variable>
231 + <name>localhost</name>
232 + <type>STRING</type>
233 + <value></value>
234 + <documentation>
235 + <purpose>Specify the domain name of the computer sending the
236 + message.</purpose>
237 + <usage>This value is used as default domain of the sender e-mail
238 + address when generating automatic <tt>Message-Id</tt>
239 + headers.</usage>
240 + </documentation>
241 + </variable>
242 +{/metadocument}
243 +*/
244 + var $localhost="";
245 +
246 + /* Private methods */
247 +
248 + Function Tokenize($string,$separator="")
249 + {
250 + if(!strcmp($separator,""))
251 + {
252 + $separator=$string;
253 + $string=$this->next_token;
254 + }
255 + for($character=0;$character<strlen($separator);++$character)
256 + {
257 + if(GetType($position=strpos($string,$separator[$character]))=="integer")
258 + $found=(IsSet($found) ? min($found,$position) : $position);
259 + }
260 + if(IsSet($found))
261 + {
262 + $this->next_token=substr($string,$found+1);
263 + return(substr($string,0,$found));
264 + }
265 + else
266 + {
267 + $this->next_token="";
268 + return($string);
269 + }
270 + }
271 +
272 + Function GetFilenameExtension($filename)
273 + {
274 + return(GetType($dot=strrpos($filename,"."))=="integer" ? substr($filename,$dot) : "");
275 + }
276 +
277 + Function OutputError($error)
278 + {
279 + if(strcmp($function=$this->debug,"")
280 + && strcmp($error,""))
281 + $function($error);
282 + return($this->error=$error);
283 + }
284 +
285 + Function OutputPHPError($error, &$php_error_message)
286 + {
287 + if(IsSet($php_error_message)
288 + && strlen($php_error_message))
289 + $error.=": ".$php_error_message;
290 + return($this->OutputError($error));
291 + }
292 +
293 + Function GetPHPVersion()
294 + {
295 + if($this->php_version==0)
296 + {
297 + $version=explode(".",function_exists("phpversion") ? phpversion() : "3.0.7");
298 + $this->php_version=$version[0]*1000000+$version[1]*1000+$version[2];
299 + }
300 + return($this->php_version);
301 + }
302 +
303 + Function EscapePattern($pattern)
304 + {
305 + return('/'.str_replace('/', '\\/', $pattern).'/');
306 + }
307 +
308 + Function GetRFC822Addresses($address,&$addresses)
309 + {
310 + if(function_exists("imap_rfc822_parse_adrlist"))
311 + {
312 + if(GetType($parsed_addresses=@imap_rfc822_parse_adrlist($address,$this->localhost))!="array")
313 + return("it was not specified a valid address list");
314 + for($entry=0;$entry<count($parsed_addresses);++$entry)
315 + {
316 + if(!IsSet($parsed_addresses[$entry]->host)
317 + || $parsed_addresses[$entry]->host==".SYNTAX-ERROR.")
318 + return($parsed_addresses[$entry]->mailbox." .SYNTAX-ERROR.");
319 + $parsed_address=$parsed_addresses[$entry]->mailbox."@".$parsed_addresses[$entry]->host;
320 + if(IsSet($addresses[$parsed_address]))
321 + ++$addresses[$parsed_address];
322 + else
323 + $addresses[$parsed_address]=1;
324 + }
325 + }
326 + else
327 + {
328 + $length=strlen($address);
329 + for($position=0;$position<$length;)
330 + {
331 + $match=preg_split($this->EscapePattern($this->email_address_pattern),strtolower(substr($address,$position)),2);
332 + if(count($match)<2)
333 + break;
334 + $position+=strlen($match[0]);
335 + $next_position=$length-strlen($match[1]);
336 + $found=substr($address,$position,$next_position-$position);
337 + if(!strcmp($found,""))
338 + break;
339 + if(IsSet($addresses[$found]))
340 + ++$addresses[$found];
341 + else
342 + $addresses[$found]=1;
343 + $position=$next_position;
344 + }
345 + }
346 + return("");
347 + }
348 +
349 + Function FormatHeader($header_name,$header_value)
350 + {
351 + $length=strlen($header_value);
352 + for($header_data="",$header_line=$header_name.": ",$line_length=strlen($header_line),$position=0;$position<$length;)
353 + {
354 + for($space=$position,$line_length=strlen($header_line);$space<$length;)
355 + {
356 + if(GetType($next=strpos($header_value," ",$space+1))!="integer")
357 + $next=$length;
358 + if($next-$position+$line_length>$this->header_length_limit)
359 + {
360 + if($space==$position)
361 + $space=$next;
362 + break;
363 + }
364 + $space=$next;
365 + }
366 + $header_data.=$header_line.substr($header_value,$position,$space-$position);
367 + if($space<$length)
368 + $header_line="";
369 + $position=$space;
370 + if($position<$length)
371 + $header_data.=$this->line_break;
372 + }
373 + return($header_data);
374 + }
375 +
376 + Function GenerateMessageID($sender)
377 + {
378 + $micros=$this->Tokenize(microtime()," ");
379 + $seconds=$this->Tokenize("");
380 + $local=$this->Tokenize($sender,"@");
381 + $host=$this->Tokenize(" @");
382 + if(strlen($host)
383 + && $host[strlen($host)-1]=="-")
384 + $host=substr($host,0,strlen($host)-1);
385 + return($this->FormatHeader("Message-ID", "<".strftime("%Y%m%d%H%M%S", $seconds).substr($micros,1,5).".".preg_replace('/[^A-Za-z]/', '-', $local)."@".preg_replace('/[^.A-Za-z_-]/', '', $host).">"));
386 + }
387 +
388 + Function SendMail($to,$subject,&$body,&$headers,$return_path)
389 + {
390 + if(!function_exists("mail"))
391 + return($this->OutputError("the mail() function is not available in this PHP installation"));
392 + if(strlen($return_path))
393 + {
394 + if(!defined("PHP_OS"))
395 + return($this->OutputError("it is not possible to set the Return-Path header with your PHP version"));
396 + if(!strcmp(substr(PHP_OS,0,3),"WIN"))
397 + return($this->OutputError("it is not possible to set the Return-Path header directly from a PHP script on Windows"));
398 + if($this->GetPHPVersion()<4000005)
399 + return($this->OutputError("it is not possible to set the Return-Path header in PHP version older than 4.0.5"));
400 + if(function_exists("ini_get")
401 + && ini_get("safe_mode"))
402 + return($this->OutputError("it is not possible to set the Return-Path header due to PHP safe mode restrictions"));
403 + $success=@mail($to,$subject,$body,$headers,"-f".$return_path);
404 + }
405 + else
406 + $success=@mail($to,$subject,$body,$headers);
407 + return($success ? "" : $this->OutputPHPError("it was not possible to send e-mail message", $php_errormsg));
408 + }
409 +
410 + Function StartSendingMessage()
411 + {
412 + if(strcmp($this->delivery["State"],""))
413 + return($this->OutputError("the message was already started to be sent"));
414 + $this->delivery=array("State"=>"SendingHeaders");
415 + return("");
416 + }
417 +
418 + Function SendMessageHeaders($headers)
419 + {
420 + if(strcmp($this->delivery["State"],"SendingHeaders"))
421 + {
422 + if(!strcmp($this->delivery["State"],""))
423 + return($this->OutputError("the message was not yet started to be sent"));
424 + else
425 + return($this->OutputError("the message headers were already sent"));
426 + }
427 + $this->delivery["Headers"]=$headers;
428 + $this->delivery["State"]="SendingBody";
429 + return("");
430 + }
431 +
432 + Function SendMessageBody($data)
433 + {
434 + if(strcmp($this->delivery["State"],"SendingBody"))
435 + return($this->OutputError("the message headers were not yet sent"));
436 + if(IsSet($this->delivery["Body"]))
437 + $this->delivery["Body"].=$data;
438 + else
439 + $this->delivery["Body"]=$data;
440 + return("");
441 + }
442 +
443 + Function EndSendingMessage()
444 + {
445 + if(strcmp($this->delivery["State"],"SendingBody"))
446 + return($this->OutputError("the message body data was not yet sent"));
447 + if(!IsSet($this->delivery["Headers"])
448 + || count($this->delivery["Headers"])==0)
449 + return($this->OutputError("message has no headers"));
450 + $line_break=((defined("PHP_OS") && !strcmp(substr(PHP_OS,0,3),"WIN")) ? "\r\n" : $this->line_break);
451 + $headers=$this->delivery["Headers"];
452 + for($has=array(),$headers_text="",$header=0,Reset($headers);$header<count($headers);Next($headers),++$header)
453 + {
454 + $header_name=Key($headers);
455 + switch(strtolower($header_name))
456 + {
457 + case "to":
458 + case "subject":
459 + $has[strtolower($header_name)]=$headers[$header_name];
460 + break;
461 + case "cc":
462 + case "bcc":
463 + case "from":
464 + case "return-path":
465 + case "message-id":
466 + $has[strtolower($header_name)]=$headers[$header_name];
467 + default:
468 + $header_line=$header_name.": ".$headers[$header_name];
469 + if(strlen($headers_text))
470 + $headers_text.=$this->line_break.$header_line;
471 + else
472 + $headers_text=$header_line;
473 + }
474 + }
475 + if(strlen($has["to"])==0
476 + && !IsSet($has["cc"])
477 + && !IsSet($has["bcc"]))
478 + return($this->OutputError("it were not specified a valid To:, Cc: or Bcc: headers"));
479 + if(!IsSet($has["subject"]))
480 + return($this->OutputError("it was not specified a valid Subject: header"));
481 + if(!IsSet($has["message-id"])
482 + && $this->auto_message_id)
483 + {
484 + $sender = array();
485 + if(IsSet($has["return-path"]))
486 + $sender[] = $has["return-path"];
487 + if(IsSet($has["from"]))
488 + $sender[] = $has["from"];
489 + $sender[] = $has["to"];
490 + $ts = count($sender);
491 + for($s = 0; $s < $ts; ++$s)
492 + {
493 + $error = $this->GetRFC822Addresses($sender[$s], $senders);
494 + if(strlen($error) == 0
495 + && count($senders))
496 + break;
497 + }
498 + if(count($senders) == 0)
499 + return('it was not specified a valid sender address'.(strlen($error) ? ': '.$error : ''));
500 + Reset($senders);
501 + $sender=Key($senders);
502 + $header_line=$this->GenerateMessageID($sender);
503 + if(strlen($headers_text))
504 + $headers_text.=$this->line_break.$header_line;
505 + else
506 + $headers_text=$header_line;
507 + }
508 + if(strcmp($error=$this->SendMail(strlen($has["to"]) ? $has["to"] : (IsSet($has["cc"]) ? "" : "undisclosed-recipients: ;"), $has["subject"], $this->delivery["Body"], $headers_text, IsSet($has["return-path"]) ? $has["return-path"] : ""),""))
509 + return($error);
510 + $this->delivery=array("State"=>"");
511 + return("");
512 + }
513 +
514 + Function StopSendingMessage()
515 + {
516 + $this->delivery=array("State"=>"");
517 + return("");
518 + }
519 +
520 + Function GetPartBoundary($part)
521 + {
522 + if(!IsSet($this->parts[$part]["BOUNDARY"]))
523 + $this->parts[$part]["BOUNDARY"]=md5(uniqid($part.time()));
524 + }
525 +
526 + Function GetPartHeaders(&$headers,$part)
527 + {
528 + if(IsSet($this->parts[$part]['CachedHeaders']))
529 + {
530 + $headers = $this->parts[$part]['CachedHeaders'];
531 + return('');
532 + }
533 + if(!IsSet($this->parts[$part]["Content-Type"]))
534 + return($this->OutputError("it was added a part without Content-Type: defined"));
535 + $type=$this->Tokenize($full_type=strtolower($this->parts[$part]["Content-Type"]),"/");
536 + $sub_type=$this->Tokenize("");
537 + switch($type)
538 + {
539 + case "text":
540 + case "image":
541 + case "audio":
542 + case "video":
543 + case "application":
544 + case "message":
545 + if(IsSet($this->parts[$part]["NAME"]))
546 + $filename = $this->QuotedPrintableEncode($this->parts[$part]["NAME"], $this->default_charset, 1, 1);
547 + $headers["Content-Type"]=$full_type.(IsSet($this->parts[$part]["CHARSET"]) ? "; charset=".$this->parts[$part]["CHARSET"] : "").(IsSet($this->parts[$part]["NAME"]) ? "; name=\"".$filename."\"" : "");
548 + if(IsSet($this->parts[$part]["Content-Transfer-Encoding"]))
549 + $headers["Content-Transfer-Encoding"]=$this->parts[$part]["Content-Transfer-Encoding"];
550 + if(IsSet($this->parts[$part]["DISPOSITION"])
551 + && strlen($this->parts[$part]["DISPOSITION"]))
552 + $headers["Content-Disposition"]=$this->parts[$part]["DISPOSITION"].(IsSet($this->parts[$part]["NAME"]) ? "; filename=\"".$filename."\"" : "");
553 + break;
554 + case "multipart":
555 + switch($sub_type)
556 + {
557 + case "alternative":
558 + case "related":
559 + case "mixed":
560 + case "parallel":
561 + $this->GetPartBoundary($part);
562 + $headers["Content-Type"]=$full_type."; boundary=\"".$this->parts[$part]["BOUNDARY"]."\"";
563 + break;
564 + default:
565 + return($this->OutputError("multipart Content-Type sub_type $sub_type not yet supported"));
566 + }
567 + break;
568 + default:
569 + return($this->OutputError("Content-Type: $full_type not yet supported"));
570 + }
571 + if(IsSet($this->parts[$part]["Content-ID"]))
572 + $headers["Content-ID"]="<".$this->parts[$part]["Content-ID"].">";
573 + if(IsSet($this->parts[$part]['Cache'])
574 + && $this->parts[$part]['Cache'])
575 + $this->parts[$part]['CachedHeaders'] = $headers;
576 + return("");
577 + }
578 +
579 + Function GetPartBody(&$body,$part)
580 + {
581 + if(IsSet($this->parts[$part]['CachedBody']))
582 + {
583 + $body = $this->parts[$part]['CachedBody'];
584 + return('');
585 + }
586 + if(!IsSet($this->parts[$part]["Content-Type"]))
587 + return($this->OutputError("it was added a part without Content-Type: defined"));
588 + $type=$this->Tokenize($full_type=strtolower($this->parts[$part]["Content-Type"]),"/");
589 + $sub_type=$this->Tokenize("");
590 + $body="";
591 + switch($type)
592 + {
593 + case "text":
594 + case "image":
595 + case "audio":
596 + case "video":
597 + case "application":
598 + case "message":
599 + if(IsSet($this->parts[$part]["FILENAME"]))
600 + {
601 + $size=@filesize($this->parts[$part]["FILENAME"]);
602 + if(!($file=@fopen($this->parts[$part]["FILENAME"],"rb")))
603 + return($this->OutputPHPError("could not open part file ".$this->parts[$part]["FILENAME"], $php_errormsg));
604 + while(!feof($file))
605 + {
606 + if(GetType($block=@fread($file,$this->file_buffer_length))!="string")
607 + {
608 + fclose($file);
609 + return($this->OutputPHPError("could not read part file", $php_errormsg));
610 + }
611 + $body.=$block;
612 + }
613 + fclose($file);
614 + if((GetType($size)=="integer"
615 + && strlen($body)>$size)
616 + || (function_exists("get_magic_quotes_runtime")
617 + && get_magic_quotes_runtime()))
618 + $body=StripSlashes($body);
619 + if(GetType($size)=="integer"
620 + && strlen($body)!=$size)
621 + return($this->OutputError("the length of the file that was read does not match the size of the part file ".$this->parts[$part]["FILENAME"]." due to possible data corruption"));
622 + }
623 + else
624 + {
625 + if(!IsSet($this->parts[$part]["DATA"]))
626 + return($this->OutputError("it was added a part without a body PART"));
627 + $body=$this->parts[$part]["DATA"];
628 + }
629 + $encoding=(IsSet($this->parts[$part]["Content-Transfer-Encoding"]) ? strtolower($this->parts[$part]["Content-Transfer-Encoding"]) : "");
630 + switch($encoding)
631 + {
632 + case "base64":
633 + $body=chunk_split(base64_encode($body));
634 + break;
635 + case "":
636 + case "quoted-printable":
637 + case "7bit":
638 + break;
639 + default:
640 + return($this->OutputError($encoding." is not yet a supported encoding type"));
641 + }
642 + break;
643 + case "multipart":
644 + switch($sub_type)
645 + {
646 + case "alternative":
647 + case "related":
648 + case "mixed":
649 + case "parallel":
650 + $this->GetPartBoundary($part);
651 + $boundary=$this->line_break."--".$this->parts[$part]["BOUNDARY"];
652 + $parts=count($this->parts[$part]["PARTS"]);
653 + for($multipart=0;$multipart<$parts;$multipart++)
654 + {
655 + $body.=$boundary.$this->line_break;
656 + $part_headers=array();
657 + $sub_part=$this->parts[$part]["PARTS"][$multipart];
658 + if(strlen($error=$this->GetPartHeaders($part_headers,$sub_part)))
659 + return($error);
660 + for($part_header=0,Reset($part_headers);$part_header<count($part_headers);$part_header++,Next($part_headers))
661 + {
662 + $header=Key($part_headers);
663 + $body.=$header.": ".$part_headers[$header].$this->line_break;
664 + }
665 + $body.=$this->line_break;
666 + if(strlen($error=$this->GetPartBody($part_body,$sub_part)))
667 + return($error);
668 + $body.=$part_body;
669 + }
670 + $body.=$boundary."--".$this->line_break;
671 + break;
672 + default:
673 + return($this->OutputError("multipart Content-Type sub_type $sub_type not yet supported"));
674 + }
675 + break;
676 + default:
677 + return($this->OutputError("Content-Type: $full_type not yet supported"));
678 + }
679 + if(IsSet($this->parts[$part]['Cache'])
680 + && $this->parts[$part]['Cache'])
681 + $this->parts[$part]['CachedBody'] = $body;
682 + return("");
683 + }
684 +
685 + /* Public functions */
686 +
687 +/*
688 +{metadocument}
689 + <function>
690 + <name>ValidateEmailAddress</name>
691 + <type>BOOLEAN</type>
692 + <documentation>
693 + <purpose>Determine whether a given e-mail address may be
694 + valid.</purpose>
695 + <usage>Just pass the e-mail <argumentlink>
696 + <function>ValidateEmailAddress</function>
697 + <argument>address</argument>
698 + </argumentlink> to be checked as function argument. This function
699 + uses the regular expression defined by the
700 + <variablelink>email_regular_expression</variablelink> variable to
701 + check the address.</usage>
702 + <returnvalue>The function returns
703 + <tt><booleanvalue>1</booleanvalue></tt> if the specified address
704 + may be valid.</returnvalue>
705 + </documentation>
706 + <argument>
707 + <name>address</name>
708 + <type>STRING</type>
709 + <documentation>
710 + <purpose>Specify the e-mail address to be validated.</purpose>
711 + </documentation>
712 + </argument>
713 + <do>
714 +{/metadocument}
715 +*/
716 + Function ValidateEmailAddress($address)
717 + {
718 + return(preg_match('/'.str_replace('/', '\\/'. $this->email_regular_expression).'/i',$address));
719 + }
720 +/*
721 +{metadocument}
722 + </do>
723 + </function>
724 +{/metadocument}
725 +*/
726 +
727 + Function QuotedPrintableEncode($text, $header_charset='', $break_lines=1, $email_header = 0)
728 + {
729 + $ln=strlen($text);
730 + $h=(strlen($header_charset)>0);
731 + if($h)
732 + {
733 + $encode = array(
734 + '='=>1,
735 + '?'=>1,
736 + '_'=>1,
737 + '('=>1,
738 + ')'=>1,
739 + '<'=>1,
740 + '>'=>1,
741 + '@'=>1,
742 + ','=>1,
743 + ';'=>1,
744 + '"'=>1,
745 + '\\'=>1,
746 + '['=>1,
747 + ']'=>1,
748 + ':'=>1,
749 +/*
750 + '/'=>1,
751 + '.'=>1,
752 +*/
753 + );
754 + $s=($email_header ? $encode : array());
755 + $b=$space=$break_lines=0;
756 + for($i=0; $i<$ln; ++$i)
757 + {
758 + $c = $text[$i];
759 + if(IsSet($s[$c]))
760 + {
761 + $b=1;
762 + break;
763 + }
764 + switch($o=Ord($c))
765 + {
766 + case 9:
767 + case 32:
768 + $space=$i+1;
769 + $b=1;
770 + break 2;
771 + case 10:
772 + case 13:
773 + break 2;
774 + default:
775 + if($o<32
776 + || $o>127)
777 + {
778 + $b=1;
779 + $s = $encode;
780 + break 2;
781 + }
782 + }
783 + }
784 + if($i==$ln)
785 + return($text);
786 + if($space>0)
787 + return(substr($text,0,$space).($space<$ln ? $this->QuotedPrintableEncode(substr($text,$space), $header_charset, $break_lines, $email_header) : ""));
788 + }
789 + for($w=$e='',$n=0, $l=0,$i=0;$i<$ln; ++$i)
790 + {
791 + $c = $text[$i];
792 + $o=Ord($c);
793 + $en=0;
794 + switch($o)
795 + {
796 + case 9:
797 + case 32:
798 + if(!$h)
799 + {
800 + $w=$c;
801 + $c='';
802 + }
803 + else
804 + {
805 + if($b)
806 + {
807 + if($o==32)
808 + $c='_';
809 + else
810 + $en=1;
811 + }
812 + }
813 + break;
814 + case 10:
815 + case 13:
816 + if(strlen($w))
817 + {
818 + if($break_lines
819 + && $l+3>75)
820 + {
821 + $e.='='.$this->line_break;
822 + $l=0;
823 + }
824 + $e.=sprintf('=%02X',Ord($w));
825 + $l+=3;
826 + $w='';
827 + }
828 + $e.=$c;
829 + if($h)
830 + $e.="\t";
831 + $l=0;
832 + continue 2;
833 + case 46:
834 + case 70:
835 + case 102:
836 + $en=(!$h && ($l==0 || $l+1>75));
837 + break;
838 + default:
839 + if($o>127
840 + || $o<32
841 + || !strcmp($c,'='))
842 + $en=1;
843 + elseif($h
844 + && IsSet($s[$c]))
845 + $en=1;
846 + break;
847 + }
848 + if(strlen($w))
849 + {
850 + if($break_lines
851 + && $l+1>75)
852 + {
853 + $e.='='.$this->line_break;
854 + $l=0;
855 + }
856 + $e.=$w;
857 + ++$l;
858 + $w='';
859 + }
860 + if(strlen($c))
861 + {
862 + if($en)
863 + {
864 + $c=sprintf('=%02X',$o);
865 + $el=3;
866 + $n=1;
867 + $b=1;
868 + }
869 + else
870 + $el=1;
871 + if($break_lines
872 + && $l+$el>75)
873 + {
874 + $e.='='.$this->line_break;
875 + $l=0;
876 + }
877 + $e.=$c;
878 + $l+=$el;
879 + }
880 + }
881 + if(strlen($w))
882 + {
883 + if($break_lines
884 + && $l+3>75)
885 + $e.='='.$this->line_break;
886 + $e.=sprintf('=%02X',Ord($w));
887 + }
888 + if($h
889 + && $n)
890 + return('=?'.$header_charset.'?q?'.$e.'?=');
891 + else
892 + return($e);
893 + }
894 +
895 +/*
896 +{metadocument}
897 + <function>
898 + <name>WrapText</name>
899 + <type>STRING</type>
900 + <documentation>
901 + <purpose>Split a text in lines that do not exceed the length limit
902 + avoiding to break it in the middle of any words.</purpose>
903 + <usage>Just pass the <argumentlink>
904 + <function>WrapText</function>
905 + <argument>text</argument>
906 + </argumentlink> to be wrapped.</usage>
907 + <returnvalue>The wrapped text eventually broken in multiple lines
908 + that do not exceed the line length limit.</returnvalue>
909 + </documentation>
910 + <argument>
911 + <name>text</name>
912 + <type>STRING</type>
913 + <documentation>
914 + <purpose>Text to be wrapped.</purpose>
915 + </documentation>
916 + </argument>
917 + <argument>
918 + <name>line_length</name>
919 + <type>INTEGER</type>
920 + <defaultvalue>0</defaultvalue>
921 + <documentation>
922 + <purpose>Line length limit. Pass a value different than
923 + <tt><integervalue>0</integervalue></tt> to use a line length
924 + limit other than the default of 75 characters.</purpose>
925 + </documentation>
926 + </argument>
927 + <argument>
928 + <name>line_break</name>
929 + <type>STRING</type>
930 + <defaultvalue></defaultvalue>
931 + <documentation>
932 + <purpose>Character sequence that is used to break the lines longer
933 + than the length limit. Pass a non-empty to use a line breaking
934 + sequence other than the default
935 + <tt><stringvalue>&#10;</stringvalue></tt>.</purpose>
936 + </documentation>
937 + </argument>
938 + <argument>
939 + <name>line_prefix</name>
940 + <type>STRING</type>
941 + <defaultvalue></defaultvalue>
942 + <documentation>
943 + <purpose>Character sequence that is used to insert in the beginning
944 + of all lines.</purpose>
945 + </documentation>
946 + </argument>
947 + <do>
948 +{/metadocument}
949 +*/
950 + Function WrapText($text,$line_length=0,$line_break="",$line_prefix="")
951 + {
952 + if(strlen($line_break)==0)
953 + $line_break=$this->line_break;
954 + if($line_length==0)
955 + $line_length=$this->line_length;
956 + $lines=explode("\n",str_replace("\r","\n",str_replace("\r\n","\n",$text)));
957 + for($wrapped="",$line=0;$line<count($lines);++$line)
958 + {
959 + if(strlen($text_line=$lines[$line]))
960 + {
961 + for(;strlen($text_line=$line_prefix.$text_line)>$line_length;)
962 + {
963 + if(GetType($cut=strrpos(substr($text_line,0,$line_length)," "))!="integer"
964 + || $cut<strlen($line_prefix))
965 + {
966 + if($this->break_long_lines)
967 + {
968 + $wrapped.=substr($text_line,0,$line_length).$line_break;
969 + $cut=$line_length;
970 + }
971 + elseif(GetType($cut=strpos($text_line," ",$line_length))=="integer")
972 + {
973 + $wrapped.=substr($text_line, 0, $cut).$line_break;
974 + ++$cut;
975 + }
976 + else
977 + {
978 + $wrapped.=$text_line.$line_break;
979 + $cut=strlen($text_line);
980 + }
981 + }
982 + else
983 + {
984 + $wrapped.=substr($text_line,0,$cut).$line_break;
985 + ++$cut;
986 + }
987 + $text_line=substr($text_line,$cut);
988 + }
989 + }
990 + $wrapped.=$text_line.$line_break;
991 + }
992 + return($wrapped);
993 + }
994 +/*
995 +{metadocument}
996 + </do>
997 + </function>
998 +{/metadocument}
999 +*/
1000 +
1001 +/*
1002 +{metadocument}
1003 + <function>
1004 + <name>CenterText</name>
1005 + <type>STRING</type>
1006 + <documentation>
1007 + <purpose>Center a text in the middle of line.</purpose>
1008 + <usage>Just pass the <argumentlink>
1009 + <function>CenterText</function>
1010 + <argument>text</argument>
1011 + </argumentlink> to be centered.</usage>
1012 + <returnvalue>The centered text.</returnvalue>
1013 + </documentation>
1014 + <argument>
1015 + <name>text</name>
1016 + <type>STRING</type>
1017 + <documentation>
1018 + <purpose>Text to be centered.</purpose>
1019 + </documentation>
1020 + </argument>
1021 + <argument>
1022 + <name>line_length</name>
1023 + <type>INTEGER</type>
1024 + <defaultvalue>0</defaultvalue>
1025 + <documentation>
1026 + <purpose>Line length limit. Pass a value different than
1027 + <tt><integervalue>0</integervalue></tt> to use a line length
1028 + limit other than the default of 75 characters.</purpose>
1029 + </documentation>
1030 + </argument>
1031 + <do>
1032 +{/metadocument}
1033 +*/
1034 + Function CenterText($text, $line_length=0)
1035 + {
1036 + if($line_length==0)
1037 + $line_length=$this->line_length;
1038 + $length = strlen($text);
1039 + if($length<$line_length)
1040 + $text = str_repeat(' ', ($line_length-$length)/2).$text;
1041 + return($text);
1042 + }
1043 +/*
1044 +{metadocument}
1045 + </do>
1046 + </function>
1047 +{/metadocument}
1048 +*/
1049 +
1050 +/*
1051 +{metadocument}
1052 + <function>
1053 + <name>Ruler</name>
1054 + <type>STRING</type>
1055 + <documentation>
1056 + <purpose>Generate a line with characters that can be displayed as a
1057 + separator ruler in a text message.</purpose>
1058 + <returnvalue>The ruler line string.</returnvalue>
1059 + </documentation>
1060 + <argument>
1061 + <name>line_length</name>
1062 + <type>INTEGER</type>
1063 + <defaultvalue>0</defaultvalue>
1064 + <documentation>
1065 + <purpose>Line length limit. Pass a value different than
1066 + <tt><integervalue>0</integervalue></tt> to use a line length
1067 + limit other than the default of 75 characters.</purpose>
1068 + </documentation>
1069 + </argument>
1070 + <do>
1071 +{/metadocument}
1072 +*/
1073 + Function Ruler($line_length=0)
1074 + {
1075 + if($line_length==0)
1076 + $line_length=$this->line_length;
1077 + return(str_repeat($this->ruler, $line_length));
1078 + }
1079 +/*
1080 +{metadocument}
1081 + </do>
1082 + </function>
1083 +{/metadocument}
1084 +*/
1085 +
1086 +/*
1087 +{metadocument}
1088 + <function>
1089 + <name>QuoteText</name>
1090 + <type>STRING</type>
1091 + <documentation>
1092 + <purpose>Mark a text block to appear like in reply messages composed
1093 + with common e-mail programs that include text from the original
1094 + message being replied.</purpose>
1095 + <usage>Just pass the <argumentlink>
1096 + <function>QuoteText</function>
1097 + <argument>text</argument>
1098 + </argumentlink> to be marked as a quote.</usage>
1099 + <returnvalue>The quoted text with all lines prefixed with a quote
1100 + prefix mark.</returnvalue>
1101 + </documentation>
1102 + <argument>
1103 + <name>text</name>
1104 + <type>STRING</type>
1105 + <documentation>
1106 + <purpose>Text to be quoted.</purpose>
1107 + </documentation>
1108 + </argument>
1109 + <argument>
1110 + <name>quote_prefix</name>
1111 + <type>STRING</type>
1112 + <defaultvalue></defaultvalue>
1113 + <documentation>
1114 + <purpose>Character sequence that is inserted in the beginning of
1115 + all lines as a quote mark. Set to an empty string to tell the
1116 + function to use the default specified by the
1117 + <variablelink>line_quote_prefix</variablelink> variable.</purpose>
1118 + </documentation>
1119 + </argument>
1120 + <do>
1121 +{/metadocument}
1122 +*/
1123 + Function QuoteText($text,$quote_prefix="")
1124 + {
1125 + if(strlen($quote_prefix)==0)
1126 + $quote_prefix=$this->line_quote_prefix;
1127 + return($this->WrapText($text,$line_length=0,$line_break="",$quote_prefix));
1128 + }
1129 +/*
1130 +{metadocument}
1131 + </do>
1132 + </function>
1133 +{/metadocument}
1134 +*/
1135 +
1136 +/*
1137 +{metadocument}
1138 + <function>
1139 + <name>SetHeader</name>
1140 + <type>STRING</type>
1141 + <documentation>
1142 + <purpose>Set the value of a message header.</purpose>
1143 + <usage>Use this function to set the values of the headers of the
1144 + message that may be needed. There are some message headers that are
1145 + automatically set by the class when the message is sent. Others
1146 + must be defined before sending. Here follows the list of the names
1147 + of the headers that must be set before sending:<paragraphbreak />
1148 + <paragraphbreak />
1149 + <b>Message subject</b> - <tt>Subject</tt><paragraphbreak />
1150 + <b>Sender address</b> - <tt>From</tt><paragraphbreak />
1151 + <b>Recipient addresses</b> - <tt>To</tt>, <tt>Cc</tt> and
1152 + <tt>Bcc</tt><paragraphbreak />
1153 + Each of the recipient address headers may contain one or more
1154 + addresses. Multiple addresses must be separated by a comma and a
1155 + space.<paragraphbreak />
1156 + <b>Return path address</b> - <tt>Return-Path</tt><paragraphbreak />
1157 + Optional header to specify the address where the message should be
1158 + bounced in case it is not possible to deliver it.<paragraphbreak />
1159 + In reality this is a virtual header. This means that adding this
1160 + header to a message will not do anything by itself. However, this
1161 + class looks for this header to adjust the message delivery
1162 + procedure in such way that the Message Transfer Agent (MTA) system
1163 + is hinted to direct any bounced messages to the address specified
1164 + by this header.<paragraphbreak />
1165 + Note that under some systems there is no way to set the return path
1166 + address programmatically. This is the case when using the PHP
1167 + <tt>mail()</tt> function under Windows where the return path
1168 + address should be set in the <tt>php.ini</tt> configuration
1169 + file.<paragraphbreak />
1170 + Keep in mind that even when it is possible to set the return path
1171 + address, the systems of some e-mail account providers may ignore
1172 + this address and send bounced messages to the sender address. This
1173 + is a bug of those systems. There is nothing that can be done other
1174 + than complain.</usage>
1175 + <returnvalue>An error message in case there was an error or an empty
1176 + string otherwise. This return value may be safely ignored if the
1177 + function parameters are set correctly.</returnvalue>
1178 + </documentation>
1179 + <argument>
1180 + <name>header</name>
1181 + <type>STRING</type>
1182 + <documentation>
1183 + <purpose>Name of the header.</purpose>
1184 + </documentation>
1185 + </argument>
1186 + <argument>
1187 + <name>value</name>
1188 + <type>STRING</type>
1189 + <documentation>
1190 + <purpose>Text value for the header.</purpose>
1191 + </documentation>
1192 + </argument>
1193 + <argument>
1194 + <name>encoding_charset</name>
1195 + <type>STRING</type>
1196 + <defaultvalue></defaultvalue>
1197 + <documentation>
1198 + <purpose>Character set used in the header value. If it is set to an
1199 + empty string, it is assumed the character set defined by the
1200 + <variablelink>default_charset</variablelink> variable.</purpose>
1201 + </documentation>
1202 + </argument>
1203 + <do>
1204 +{/metadocument}
1205 +*/
1206 + Function SetHeader($header, $value, $encoding_charset="")
1207 + {
1208 + if(strlen($this->error))
1209 + return($this->error);
1210 + $this->headers[strval($header)]=(!strcmp($encoding_charset,"") ? strval($value) : $this->QuotedPrintableEncode($value, $encoding_charset, 1, 0));
1211 + return("");
1212 + }
1213 +/*
1214 +{metadocument}
1215 + </do>
1216 + </function>
1217 +{/metadocument}
1218 +*/
1219 +
1220 +/*
1221 +{metadocument}
1222 + <function>
1223 + <name>SetEncodedHeader</name>
1224 + <type>STRING</type>
1225 + <documentation>
1226 + <purpose>The same as the <functionlink>SetHeader</functionlink>
1227 + function assuming the default character set specified by the
1228 + <variablelink>default_charset</variablelink> variable.</purpose>
1229 + <usage>See the <functionlink>SetHeader</functionlink> function.</usage>
1230 + <returnvalue>An error message in case there was an error or an empty
1231 + string otherwise. This return value may be safely ignored if the
1232 + function parameters are set correctly.</returnvalue>
1233 + </documentation>
1234 + <argument>
1235 + <name>header</name>
1236 + <type>STRING</type>
1237 + <documentation>
1238 + <purpose>Name of the header.</purpose>
1239 + </documentation>
1240 + </argument>
1241 + <argument>
1242 + <name>value</name>
1243 + <type>STRING</type>
1244 + <documentation>
1245 + <purpose>Text value for the header.</purpose>
1246 + </documentation>
1247 + </argument>
1248 + <argument>
1249 + <name>encoding_charset</name>
1250 + <type>STRING</type>
1251 + <defaultvalue></defaultvalue>
1252 + <documentation>
1253 + <purpose>Character set used in the header value. If it is set to an
1254 + empty string, it is assumed the character set defined by the
1255 + <variablelink>default_charset</variablelink> variable.</purpose>
1256 + </documentation>
1257 + </argument>
1258 + <do>
1259 +{/metadocument}
1260 +*/
1261 + Function SetEncodedHeader($header,$value, $encoding_charset = '')
1262 + {
1263 + return($this->SetHeader($header,$value,strlen($encoding_charset) ? $encoding_charset : $this->default_charset));
1264 + }
1265 +/*
1266 +{metadocument}
1267 + </do>
1268 + </function>
1269 +{/metadocument}
1270 +*/
1271 +
1272 +/*
1273 +{metadocument}
1274 + <function>
1275 + <name>SetEncodedEmailHeader</name>
1276 + <type>STRING</type>
1277 + <documentation>
1278 + <purpose>Set the value of an header that is meant to represent the
1279 + e-mail address of a person or entity with a known name. This is
1280 + meant mostly to set the <tt>From</tt>, <tt>To</tt>, <tt>Cc</tt> and
1281 + <tt>Bcc</tt> headers.</purpose>
1282 + <usage>Use this function like the
1283 + <functionlink>SetHeader</functionlink> specifying the e-mail
1284 + <argumentlink>
1285 + <function>SetEncodedEmailHeader</function>
1286 + <argument>address</argument>
1287 + </argumentlink> as header value and also specifying the
1288 + <argumentlink>
1289 + <function>SetEncodedEmailHeader</function>
1290 + <argument>name</argument>
1291 + </argumentlink> of the known person or entity.</usage>
1292 + <returnvalue>An error message in case there was an error or an empty
1293 + string otherwise. This return value may be safely ignored if the
1294 + function parameters are set correctly.</returnvalue>
1295 + </documentation>
1296 + <argument>
1297 + <name>header</name>
1298 + <type>STRING</type>
1299 + <documentation>
1300 + <purpose>Name of the header.</purpose>
1301 + </documentation>
1302 + </argument>
1303 + <argument>
1304 + <name>address</name>
1305 + <type>STRING</type>
1306 + <documentation>
1307 + <purpose>E-mail address value.</purpose>
1308 + </documentation>
1309 + </argument>
1310 + <argument>
1311 + <name>name</name>
1312 + <type>STRING</type>
1313 + <documentation>
1314 + <purpose>Person or entity name associated with the specified e-mail
1315 + address.</purpose>
1316 + </documentation>
1317 + </argument>
1318 + <argument>
1319 + <name>encoding_charset</name>
1320 + <type>STRING</type>
1321 + <defaultvalue></defaultvalue>
1322 + <documentation>
1323 + <purpose>Character set used in the header value. If it is set to an
1324 + empty string, it is assumed the character set defined by the
1325 + <variablelink>default_charset</variablelink> variable.</purpose>
1326 + </documentation>
1327 + </argument>
1328 + <do>
1329 +{/metadocument}
1330 +*/
1331 + Function SetEncodedEmailHeader($header, $address, $name, $encoding_charset = '')
1332 + {
1333 + return($this->SetHeader($header,$this->QuotedPrintableEncode($name, strlen($encoding_charset) ? $encoding_charset : $this->default_charset, 1, 1).' <'.$address.'>'));
1334 + }
1335 +/*
1336 +{metadocument}
1337 + </do>
1338 + </function>
1339 +{/metadocument}
1340 +*/
1341 +
1342 +/*
1343 +{metadocument}
1344 + <function>
1345 + <name>SetMultipleEncodedEmailHeader</name>
1346 + <type>STRING</type>
1347 + <documentation>
1348 + <purpose>Set the value of an header that is meant to represent a list
1349 + of e-mail addresses of names of people or entities. This is meant
1350 + mostly to set the <tt>To</tt>, <tt>Cc</tt> and <tt>Bcc</tt>
1351 + headers.</purpose>
1352 + <usage>Use this function specifying the <argumentlink>
1353 + <function>SetMultipleEncodedEmailHeader</function>
1354 + <argument>header</argument>
1355 + </argumentlink> and all the <argumentlink>
1356 + <function>SetMultipleEncodedEmailHeader</function>
1357 + <argument>addresses</argument>
1358 + </argumentlink> in an associative array that should have
1359 + the email addresses as entry indexes and the name of the respective
1360 + people or entities as entry values.</usage>
1361 + <returnvalue>An error message in case there was an error or an empty
1362 + string otherwise. This return value may be safely ignored if the
1363 + function parameters are set correctly.</returnvalue>
1364 + <example><pre>$message_object->SetMultipleEncodedEmailHeader('Bcc', array(
1365 + '[email protected]' =gt; 'Peter Gabriel',
1366 + '[email protected]' =gt; 'Paul Simon',
1367 + '[email protected]' =gt; 'Mary Chain'
1368 +));</pre></example>
1369 + </documentation>
1370 + <argument>
1371 + <name>header</name>
1372 + <type>STRING</type>
1373 + <documentation>
1374 + <purpose>Name of the header.</purpose>
1375 + </documentation>
1376 + </argument>
1377 + <argument>
1378 + <name>addresses</name>
1379 + <type>HASH</type>
1380 + <documentation>
1381 + <purpose>List of all email addresses and associated person or
1382 + entity names.</purpose>
1383 + </documentation>
1384 + </argument>
1385 + <argument>
1386 + <name>encoding_charset</name>
1387 + <type>STRING</type>
1388 + <defaultvalue></defaultvalue>
1389 + <documentation>
1390 + <purpose>Character set used in the header value. If it is set to an
1391 + empty string, it is assumed the character set defined by the
1392 + <variablelink>default_charset</variablelink> variable.</purpose>
1393 + </documentation>
1394 + </argument>
1395 + <do>
1396 +{/metadocument}
1397 +*/
1398 + Function SetMultipleEncodedEmailHeader($header,$addresses, $encoding_charset = '')
1399 + {
1400 + Reset($addresses);
1401 + $end=(GetType($address=Key($addresses))!="string");
1402 + for($value="";!$end;)
1403 + {
1404 + if(strlen($value))
1405 + $value.=", ";
1406 + $value.=$this->QuotedPrintableEncode($addresses[$address], strlen($encoding_charset) ? $encoding_charset : $this->default_charset, 1, 1).' <'.$address.'>';
1407 + Next($addresses);
1408 + $end=(GetType($address=Key($addresses))!="string");
1409 + }
1410 + return($this->SetHeader($header,$value));
1411 + }
1412 +/*
1413 +{metadocument}
1414 + </do>
1415 + </function>
1416 +{/metadocument}
1417 +*/
1418 +
1419 +/*
1420 +{metadocument}
1421 + <function>
1422 + <name>ResetMessage</name>
1423 + <type>VOID</type>
1424 + <documentation>
1425 + <purpose>Restore the content of the message to the initial state when
1426 + the class object is created, i.e. without any headers or body
1427 + parts.</purpose>
1428 + <usage>Use this function if you want to start composing a completely
1429 + new message.</usage>
1430 + </documentation>
1431 + <do>
1432 +{/metadocument}
1433 +*/
1434 + Function ResetMessage()
1435 + {
1436 + $this->headers=array();
1437 + $this->body=-1;
1438 + $this->body_parts=0;
1439 + $this->parts=array();
1440 + $this->total_parts=0;
1441 + $this->free_parts=array();
1442 + $this->total_free_parts=0;
1443 + $this->delivery=array("State"=>"");
1444 + $this->error="";
1445 + }
1446 +/*
1447 +{metadocument}
1448 + </do>
1449 + </function>
1450 +{/metadocument}
1451 +*/
1452 +
1453 + Function CreatePart(&$definition,&$part)
1454 + {
1455 + $part=-1;
1456 + if(strlen($this->error))
1457 + return($this->error);
1458 + if($this->total_free_parts)
1459 + {
1460 + $this->total_free_parts--;
1461 + $part=$this->free_parts[$this->total_free_parts];
1462 + Unset($this->free_parts[$this->total_free_parts]);
1463 + }
1464 + else
1465 + {
1466 + $part=$this->total_parts;
1467 + ++$this->total_parts;
1468 + }
1469 + $this->parts[$part]=$definition;
1470 + return("");
1471 + }
1472 +
1473 +/*
1474 +{metadocument}
1475 + <function>
1476 + <name>AddPart</name>
1477 + <type>STRING</type>
1478 + <documentation>
1479 + <purpose>Add a previously created part to the message.</purpose>
1480 + <usage>Use any of the functions to create standalone message parts
1481 + and then use this function to add them to the message.</usage>
1482 + <returnvalue>An error message in case there was an error or an empty
1483 + string otherwise. This return value may be safely ignored if the
1484 + function parameters are set correctly.</returnvalue>
1485 + </documentation>
1486 + <argument>
1487 + <name>part</name>
1488 + <type>INTEGER</type>
1489 + <documentation>
1490 + <purpose>Number of the part as returned by the function that
1491 + originally created it.</purpose>
1492 + </documentation>
1493 + </argument>
1494 + <do>
1495 +{/metadocument}
1496 +*/
1497 + Function AddPart($part)
1498 + {
1499 + if(strlen($this->error))
1500 + return($this->error);
1501 + switch($this->body_parts)
1502 + {
1503 + case 0;
1504 + $this->body=$part;
1505 + break;
1506 + case 1:
1507 + $parts=array(
1508 + $this->body,
1509 + $part
1510 + );
1511 + if(strlen($error=$this->CreateMixedMultipart($parts,$body)))
1512 + return($error);
1513 + $this->body=$body;
1514 + break;
1515 + default:
1516 + $this->parts[$this->body]["PARTS"][]=$part;
1517 + break;
1518 + }
1519 + ++$this->body_parts;
1520 + return("");
1521 + }
1522 +/*
1523 +{metadocument}
1524 + </do>
1525 + </function>
1526 +{/metadocument}
1527 +*/
1528 +
1529 +/*
1530 +{metadocument}
1531 + <function>
1532 + <name>ReplacePart</name>
1533 + <type>STRING</type>
1534 + <documentation>
1535 + <purpose>Replace a message part already added to the message with a
1536 + newly created part. The replaced part gets the definition of the
1537 + replacing part. The replacing part is discarded and its part number
1538 + becomes free for creation of a new part.</purpose>
1539 + <usage>Use one of the functions to create message parts and then pass
1540 + the returned part numbers to this function.</usage>
1541 + <returnvalue>An error message in case there was an error or an empty
1542 + string otherwise. This return value may be safely ignored if the
1543 + function parameters are set correctly.</returnvalue>
1544 + </documentation>
1545 + <argument>
1546 + <name>old_part</name>
1547 + <type>INTEGER</type>
1548 + <documentation>
1549 + <purpose>Number of the previously added part.</purpose>
1550 + </documentation>
1551 + </argument>
1552 + <argument>
1553 + <name>new_part</name>
1554 + <type>INTEGER</type>
1555 + <documentation>
1556 + <purpose>Number of the replacing part.</purpose>
1557 + </documentation>
1558 + </argument>
1559 + <do>
1560 +{/metadocument}
1561 +*/
1562 + Function ReplacePart($old_part,$new_part)
1563 + {
1564 + if(strlen($this->error))
1565 + return($this->error);
1566 + if(!IsSet($this->parts[$old_part]))
1567 + return($this->error="it was attempted to replace an invalid message part");
1568 + if(IsSet($this->parts[$old_part]["FREE"]))
1569 + return($this->error="it was attempted to replace a message part that is no longer valid");
1570 + if(!IsSet($this->parts[$new_part]))
1571 + return($this->error="it was attempted to use an invalid message replacecement part");
1572 + if(IsSet($this->parts[$new_part]["FREE"]))
1573 + return($this->error="it was attempted to use a message replacecement part that is no longer valid");
1574 + $this->parts[$old_part]=$this->parts[$new_part];
1575 + $this->parts[$new_part]=array("FREE"=>1);
1576 + $this->free_parts[$this->total_free_parts]=$new_part;
1577 + ++$this->total_free_parts;
1578 + return("");
1579 + }
1580 +/*
1581 +{metadocument}
1582 + </do>
1583 + </function>
1584 +{/metadocument}
1585 +*/
1586 +
1587 + Function CreateAndAddPart(&$definition)
1588 + {
1589 + if(strlen($error=$this->CreatePart($definition,$part))
1590 + || strlen($error=$this->AddPart($part)))
1591 + return($error);
1592 + return("");
1593 + }
1594 +
1595 +/*
1596 +{metadocument}
1597 + <function>
1598 + <name>CreatePlainTextPart</name>
1599 + <type>STRING</type>
1600 + <documentation>
1601 + <purpose>Create a plain text message part.</purpose>
1602 + <usage>Pass an ASCII (7 bits) <argumentlink>
1603 + <function>CreatePlainTextPart</function>
1604 + <argument>text</argument>
1605 + </argumentlink> string and get the created part number in the
1606 + <argumentlink>
1607 + <function>CreatePlainTextPart</function>
1608 + <argument>part</argument>
1609 + </argumentlink> that is returned by reference.</usage>
1610 + <returnvalue>An error message in case there was an error or an empty
1611 + string otherwise. This return value may be safely ignored if the
1612 + function parameters are set correctly.</returnvalue>
1613 + </documentation>
1614 + <argument>
1615 + <name>text</name>
1616 + <type>STRING</type>
1617 + <documentation>
1618 + <purpose>Text of the message part to create.</purpose>
1619 + </documentation>
1620 + </argument>
1621 + <argument>
1622 + <name>charset</name>
1623 + <type>STRING</type>
1624 + <documentation>
1625 + <purpose>Character set used in the part text. If it is set to an
1626 + empty string, it is assumed the character set defined by the
1627 + <variablelink>default_charset</variablelink> variable.</purpose>
1628 + </documentation>
1629 + </argument>
1630 + <argument>
1631 + <name>part</name>
1632 + <type>INTEGER</type>
1633 + <out />
1634 + <documentation>
1635 + <purpose>Number of the created part that is returned by reference.</purpose>
1636 + </documentation>
1637 + </argument>
1638 + <do>
1639 +{/metadocument}
1640 +*/
1641 + Function CreatePlainTextPart($text,$charset,&$part)
1642 + {
1643 + if(!strcmp($charset,""))
1644 + $charset=$this->default_charset;
1645 + $definition=array(
1646 + "Content-Type"=>"text/plain",
1647 + "DATA"=>$text
1648 + );
1649 + if(strcmp(strtoupper($charset),"ASCII"))
1650 + $definition["CHARSET"]=$charset;
1651 + return($this->CreatePart($definition,$part));
1652 + }
1653 +/*
1654 +{metadocument}
1655 + </do>
1656 + </function>
1657 +{/metadocument}
1658 +*/
1659 +
1660 +/*
1661 +{metadocument}
1662 + <function>
1663 + <name>AddPlainTextPart</name>
1664 + <type>STRING</type>
1665 + <documentation>
1666 + <purpose>Add a plain text part to the message.</purpose>
1667 + <usage>Pass an ASCII (7 bits) <argumentlink>
1668 + <function>AddPlainTextPart</function>
1669 + <argument>text</argument>
1670 + </argumentlink> string.</usage>
1671 + <returnvalue>An error message in case there was an error or an empty
1672 + string otherwise. This return value may be safely ignored if the
1673 + function parameters are set correctly.</returnvalue>
1674 + </documentation>
1675 + <argument>
1676 + <name>text</name>
1677 + <type>STRING</type>
1678 + <documentation>
1679 + <purpose>Text of the message part to add.</purpose>
1680 + </documentation>
1681 + </argument>
1682 + <argument>
1683 + <name>charset</name>
1684 + <type>STRING</type>
1685 + <defaultvalue></defaultvalue>
1686 + <documentation>
1687 + <purpose>Character set used in the part text. If it is set to an
1688 + empty string, it is assumed the character set defined by the
1689 + <variablelink>default_charset</variablelink> variable.</purpose>
1690 + </documentation>
1691 + </argument>
1692 + <do>
1693 +{/metadocument}
1694 +*/
1695 + Function AddPlainTextPart($text,$charset="")
1696 + {
1697 + if(strlen($error=$this->CreatePlainTextPart($text,$charset,$part))
1698 + || strlen($error=$this->AddPart($part)))
1699 + return($error);
1700 + return("");
1701 + }
1702 +/*
1703 +{metadocument}
1704 + </do>
1705 + </function>
1706 +{/metadocument}
1707 +*/
1708 +
1709 + Function CreateEncodedQuotedPrintableTextPart($text,$charset,&$part)
1710 + {
1711 + if(!strcmp($charset,""))
1712 + $charset=$this->default_charset;
1713 + $definition=array(
1714 + "Content-Type"=>"text/plain",
1715 + "Content-Transfer-Encoding"=>"quoted-printable",
1716 + "CHARSET"=>$charset,
1717 + "DATA"=>$text
1718 + );
1719 + return($this->CreatePart($definition,$part));
1720 + }
1721 +
1722 + Function AddEncodedQuotedPrintableTextPart($text,$charset="")
1723 + {
1724 + if(strlen($error=$this->CreateEncodedQuotedPrintableTextPart($text,$charset,$part))
1725 + || strlen($error=$this->AddPart($part)))
1726 + return($error);
1727 + return("");
1728 + }
1729 +
1730 +/*
1731 +{metadocument}
1732 + <function>
1733 + <name>CreateQuotedPrintableTextPart</name>
1734 + <type>STRING</type>
1735 + <documentation>
1736 + <purpose>Create a text message part that may contain non-ASCII
1737 + characters (8 bits or more).</purpose>
1738 + <usage>Pass a <argumentlink>
1739 + <function>CreateQuotedPrintableTextPart</function>
1740 + <argument>text</argument>
1741 + </argumentlink> string and get the created part number in the
1742 + <argumentlink>
1743 + <function>CreateQuotedPrintableTextPart</function>
1744 + <argument>part</argument>
1745 + </argumentlink> that is returned by reference.</usage>
1746 + <returnvalue>An error message in case there was an error or an empty
1747 + string otherwise. This return value may be safely ignored if the
1748 + function parameters are set correctly.</returnvalue>
1749 + </documentation>
1750 + <argument>
1751 + <name>text</name>
1752 + <type>STRING</type>
1753 + <documentation>
1754 + <purpose>Text of the message part to create.</purpose>
1755 + </documentation>
1756 + </argument>
1757 + <argument>
1758 + <name>charset</name>
1759 + <type>STRING</type>
1760 + <documentation>
1761 + <purpose>Character set used in the part text. If it is set to an
1762 + empty string, it is assumed the character set defined by the
1763 + <variablelink>default_charset</variablelink> variable.</purpose>
1764 + </documentation>
1765 + </argument>
1766 + <argument>
1767 + <name>part</name>
1768 + <type>INTEGER</type>
1769 + <out />
1770 + <documentation>
1771 + <purpose>Number of the created part that is returned by reference.</purpose>
1772 + </documentation>
1773 + </argument>
1774 + <do>
1775 +{/metadocument}
1776 +*/
1777 + Function CreateQuotedPrintableTextPart($text,$charset,&$part)
1778 + {
1779 + return($this->CreateEncodedQuotedPrintableTextPart($this->QuotedPrintableEncode($text),$charset,$part));
1780 + }
1781 +/*
1782 +{metadocument}
1783 + </do>
1784 + </function>
1785 +{/metadocument}
1786 +*/
1787 +
1788 +/*
1789 +{metadocument}
1790 + <function>
1791 + <name>AddQuotedPrintableTextPart</name>
1792 + <type>STRING</type>
1793 + <documentation>
1794 + <purpose>Add a text part to the message that may contain non-ASCII
1795 + characters (8 bits or more).</purpose>
1796 + <usage>Pass a <argumentlink>
1797 + <function>AddQuotedPrintableTextPart</function>
1798 + <argument>text</argument>
1799 + </argumentlink> string.</usage>
1800 + <returnvalue>An error message in case there was an error or an empty
1801 + string otherwise. This return value may be safely ignored if the
1802 + function parameters are set correctly.</returnvalue>
1803 + </documentation>
1804 + <argument>
1805 + <name>text</name>
1806 + <type>STRING</type>
1807 + <documentation>
1808 + <purpose>Text of the message part to create.</purpose>
1809 + </documentation>
1810 + </argument>
1811 + <argument>
1812 + <name>charset</name>
1813 + <type>STRING</type>
1814 + <defaultvalue></defaultvalue>
1815 + <documentation>
1816 + <purpose>Character set used in the part text. If it is set to an
1817 + empty string, it is assumed the character set defined by the
1818 + <variablelink>default_charset</variablelink> variable.</purpose>
1819 + </documentation>
1820 + </argument>
1821 + <do>
1822 +{/metadocument}
1823 +*/
1824 + Function AddQuotedPrintableTextPart($text,$charset="")
1825 + {
1826 + return($this->AddEncodedQuotedPrintableTextPart($this->QuotedPrintableEncode($text),$charset));
1827 + }
1828 +/*
1829 +{metadocument}
1830 + </do>
1831 + </function>
1832 +{/metadocument}
1833 +*/
1834 +
1835 +/*
1836 +{metadocument}
1837 + <function>
1838 + <name>CreateHTMLPart</name>
1839 + <type>STRING</type>
1840 + <documentation>
1841 + <purpose>Create an HTML message part only with ASCII characters (7 bit).</purpose>
1842 + <usage>Pass an ASCII (7 bits) <argumentlink>
1843 + <function>CreateHTMLPart</function>
1844 + <argument>html</argument>
1845 + </argumentlink> text string and get the created part number in the
1846 + <argumentlink>
1847 + <function>CreateHTMLPart</function>
1848 + <argument>part</argument>
1849 + </argumentlink> that is returned by reference.</usage>
1850 + <returnvalue>An error message in case there was an error or an empty
1851 + string otherwise. This return value may be safely ignored if the
1852 + function parameters are set correctly.</returnvalue>
1853 + </documentation>
1854 + <argument>
1855 + <name>html</name>
1856 + <type>STRING</type>
1857 + <documentation>
1858 + <purpose>HTML of the message part to create.</purpose>
1859 + </documentation>
1860 + </argument>
1861 + <argument>
1862 + <name>charset</name>
1863 + <type>STRING</type>
1864 + <documentation>
1865 + <purpose>Character set used in the part text. If it is set to an
1866 + empty string, it is assumed the character set defined by the
1867 + <variablelink>default_charset</variablelink> variable.</purpose>
1868 + </documentation>
1869 + </argument>
1870 + <argument>
1871 + <name>part</name>
1872 + <type>INTEGER</type>
1873 + <out />
1874 + <documentation>
1875 + <purpose>Number of the created part that is returned by reference.</purpose>
1876 + </documentation>
1877 + </argument>
1878 + <do>
1879 +{/metadocument}
1880 +*/
1881 + Function CreateHTMLPart($html,$charset,&$part)
1882 + {
1883 + if(!strcmp($charset,""))
1884 + $charset=$this->default_charset;
1885 + $definition=array(
1886 + "Content-Type"=>"text/html",
1887 + "CHARSET"=>$charset,
1888 + "DATA"=>$html
1889 + );
1890 + return($this->CreatePart($definition,$part));
1891 + }
1892 +/*
1893 +{metadocument}
1894 + </do>
1895 + </function>
1896 +{/metadocument}
1897 +*/
1898 +
1899 +/*
1900 +{metadocument}
1901 + <function>
1902 + <name>AddHTMLPart</name>
1903 + <type>STRING</type>
1904 + <documentation>
1905 + <purpose>Add an HTML part to the message only with ASCII characters.</purpose>
1906 + <usage>Pass an <argumentlink>
1907 + <function>AddHTMLPart</function>
1908 + <argument>html</argument>
1909 + </argumentlink> text string.</usage>
1910 + <returnvalue>An error message in case there was an error or an empty
1911 + string otherwise. This return value may be safely ignored if the
1912 + function parameters are set correctly.</returnvalue>
1913 + </documentation>
1914 + <argument>
1915 + <name>html</name>
1916 + <type>STRING</type>
1917 + <documentation>
1918 + <purpose>HTML of the message part to create.</purpose>
1919 + </documentation>
1920 + </argument>
1921 + <argument>
1922 + <name>charset</name>
1923 + <type>STRING</type>
1924 + <defaultvalue></defaultvalue>
1925 + <documentation>
1926 + <purpose>Character set used in the part text. If it is set to an
1927 + empty string, it is assumed the character set defined by the
1928 + <variablelink>default_charset</variablelink> variable.</purpose>
1929 + </documentation>
1930 + </argument>
1931 + <do>
1932 +{/metadocument}
1933 +*/
1934 + Function AddHTMLPart($html,$charset="")
1935 + {
1936 + if(strlen($error=$this->CreateHTMLPart($html,$charset,$part))
1937 + || strlen($error=$this->AddPart($part)))
1938 + return($error);
1939 + return("");
1940 + }
1941 +/*
1942 +{metadocument}
1943 + </do>
1944 + </function>
1945 +{/metadocument}
1946 +*/
1947 +
1948 + Function CreateEncodedQuotedPrintableHTMLPart($html,$charset,&$part)
1949 + {
1950 + if(!strcmp($charset,""))
1951 + $charset=$this->default_charset;
1952 + $definition=array(
1953 + "Content-Type"=>"text/html",
1954 + "Content-Transfer-Encoding"=>"quoted-printable",
1955 + "CHARSET"=>$charset,
1956 + "DATA"=>$html
1957 + );
1958 + return($this->CreatePart($definition,$part));
1959 + }
1960 +
1961 + Function AddEncodedQuotedPrintableHTMLPart($html,$charset="")
1962 + {
1963 + if(strlen($error=$this->CreateEncodedQuotedPrintableHTMLPart($html,$charset,$part))
1964 + || strlen($error=$this->AddPart($part)))
1965 + return($error);
1966 + return("");
1967 + }
1968 +
1969 +/*
1970 +{metadocument}
1971 + <function>
1972 + <name>CreateQuotedPrintableHTMLPart</name>
1973 + <type>STRING</type>
1974 + <documentation>
1975 + <purpose>Create an HTML message part that may contain non-ASCII
1976 + characters (8 bits or more).</purpose>
1977 + <usage>Pass a <argumentlink>
1978 + <function>CreateQuotedPrintableHTMLPart</function>
1979 + <argument>html</argument>
1980 + </argumentlink> text string and get the created part number in the
1981 + <argumentlink>
1982 + <function>CreateQuotedPrintableHTMLPart</function>
1983 + <argument>part</argument>
1984 + </argumentlink> that is returned by reference.</usage>
1985 + <returnvalue>An error message in case there was an error or an empty
1986 + string otherwise. This return value may be safely ignored if the
1987 + function parameters are set correctly.</returnvalue>
1988 + </documentation>
1989 + <argument>
1990 + <name>html</name>
1991 + <type>STRING</type>
1992 + <documentation>
1993 + <purpose>HTML of the message part to create.</purpose>
1994 + </documentation>
1995 + </argument>
1996 + <argument>
1997 + <name>charset</name>
1998 + <type>STRING</type>
1999 + <documentation>
2000 + <purpose>Character set used in the part text. If it is set to an
2001 + empty string, it is assumed the character set defined by the
2002 + <variablelink>default_charset</variablelink> variable.</purpose>
2003 + </documentation>
2004 + </argument>
2005 + <argument>
2006 + <name>part</name>
2007 + <type>INTEGER</type>
2008 + <out />
2009 + <documentation>
2010 + <purpose>Number of the created part that is returned by reference.</purpose>
2011 + </documentation>
2012 + </argument>
2013 + <do>
2014 +{/metadocument}
2015 +*/
2016 + Function CreateQuotedPrintableHTMLPart($html,$charset,&$part)
2017 + {
2018 + return($this->CreateEncodedQuotedPrintableHTMLPart($this->QuotedPrintableEncode($html),$charset,$part));
2019 + }
2020 +/*
2021 +{metadocument}
2022 + </do>
2023 + </function>
2024 +{/metadocument}
2025 +*/
2026 +
2027 +
2028 +/*
2029 +{metadocument}
2030 + <function>
2031 + <name>AddQuotedPrintableHTMLPart</name>
2032 + <type>STRING</type>
2033 + <documentation>
2034 + <purpose>Add an HTML part to the message that may contain non-ASCII
2035 + characters (8 bits or more).</purpose>
2036 + <usage>Pass a <argumentlink>
2037 + <function>AddQuotedPrintableHTMLPart</function>
2038 + <argument>html</argument>
2039 + </argumentlink> text string.</usage>
2040 + <returnvalue>An error message in case there was an error or an empty
2041 + string otherwise. This return value may be safely ignored if the
2042 + function parameters are set correctly.</returnvalue>
2043 + </documentation>
2044 + <argument>
2045 + <name>html</name>
2046 + <type>STRING</type>
2047 + <documentation>
2048 + <purpose>HTML of the message part to create.</purpose>
2049 + </documentation>
2050 + </argument>
2051 + <argument>
2052 + <name>charset</name>
2053 + <type>STRING</type>
2054 + <defaultvalue></defaultvalue>
2055 + <documentation>
2056 + <purpose>Character set used in the part text. If it is set to an
2057 + empty string, it is assumed the character set defined by the
2058 + <variablelink>default_charset</variablelink> variable.</purpose>
2059 + </documentation>
2060 + </argument>
2061 + <do>
2062 +{/metadocument}
2063 +*/
2064 + Function AddQuotedPrintableHTMLPart($html,$charset="")
2065 + {
2066 + return($this->AddEncodedQuotedPrintableHTMLPart($this->QuotedPrintableEncode($html),$charset));
2067 + }
2068 +/*
2069 +{metadocument}
2070 + </do>
2071 + </function>
2072 +{/metadocument}
2073 +*/
2074 +
2075 + Function GetFileDefinition($file, &$definition, $require_name=1)
2076 + {
2077 + if(strlen($this->error))
2078 + return($this->error);
2079 + $name="";
2080 + if(IsSet($file["FileName"]))
2081 + $name=basename($file["FileName"]);
2082 + else
2083 + {
2084 + if(!IsSet($file["Data"]))
2085 + return($this->OutputError("it was not specified the file part file name"));
2086 + }
2087 + if(IsSet($file["Name"]))
2088 + $name=$file["Name"];
2089 + if($require_name
2090 + && strlen($name)==0)
2091 + return($this->OutputError("it was not specified the file part name"));
2092 + $encoding="base64";
2093 + if(IsSet($file["Content-Type"]))
2094 + {
2095 + $content_type=$file["Content-Type"];
2096 + $type=$this->Tokenize(strtolower($content_type),"/");
2097 + $sub_type=$this->Tokenize("");
2098 + switch($type)
2099 + {
2100 + case "text":
2101 + case "image":
2102 + case "audio":
2103 + case "video":
2104 + case "application":
2105 + break;
2106 + case "message":
2107 + $encoding="7bit";
2108 + break;
2109 + case "automatic":
2110 + switch($sub_type)
2111 + {
2112 + case "name":
2113 + if(strlen($name)==0)
2114 + return($this->OutputError("it is not possible to determine content type from the name"));
2115 + switch(strtolower($this->GetFilenameExtension($name)))
2116 + {
2117 + case ".xls":
2118 + $content_type="application/excel";
2119 + break;
2120 + case ".hqx":
2121 + $content_type="application/macbinhex40";
2122 + break;
2123 + case ".doc":
2124 + case ".dot":
2125 + case ".wrd":
2126 + $content_type="application/msword";
2127 + break;
2128 + case ".pdf":
2129 + $content_type="application/pdf";
2130 + break;
2131 + case ".pgp":
2132 + $content_type="application/pgp";
2133 + break;
2134 + case ".ps":
2135 + case ".eps":
2136 + case ".ai":
2137 + $content_type="application/postscript";
2138 + break;
2139 + case ".ppt":
2140 + $content_type="application/powerpoint";
2141 + break;
2142 + case ".rtf":
2143 + $content_type="application/rtf";
2144 + break;
2145 + case ".tgz":
2146 + case ".gtar":
2147 + $content_type="application/x-gtar";
2148 + break;
2149 + case ".gz":
2150 + $content_type="application/x-gzip";
2151 + break;
2152 + case ".php":
2153 + case ".php3":
2154 + $content_type="application/x-httpd-php";
2155 + break;
2156 + case ".js":
2157 + $content_type="application/x-javascript";
2158 + break;
2159 + case ".ppd":
2160 + case ".psd":
2161 + $content_type="application/x-photoshop";
2162 + break;
2163 + case ".swf":
2164 + case ".swc":
2165 + case ".rf":
2166 + $content_type="application/x-shockwave-flash";
2167 + break;
2168 + case ".tar":
2169 + $content_type="application/x-tar";
2170 + break;
2171 + case ".zip":
2172 + $content_type="application/zip";
2173 + break;
2174 + case ".mid":
2175 + case ".midi":
2176 + case ".kar":
2177 + $content_type="audio/midi";
2178 + break;
2179 + case ".mp2":
2180 + case ".mp3":
2181 + case ".mpga":
2182 + $content_type="audio/mpeg";
2183 + break;
2184 + case ".ra":
2185 + $content_type="audio/x-realaudio";
2186 + break;
2187 + case ".wav":
2188 + $content_type="audio/wav";
2189 + break;
2190 + case ".bmp":
2191 + $content_type="image/bitmap";
2192 + break;
2193 + case ".gif":
2194 + $content_type="image/gif";
2195 + break;
2196 + case ".iff":
2197 + $content_type="image/iff";
2198 + break;
2199 + case ".jb2":
2200 + $content_type="image/jb2";
2201 + break;
2202 + case ".jpg":
2203 + case ".jpe":
2204 + case ".jpeg":
2205 + $content_type="image/jpeg";
2206 + break;
2207 + case ".jpx":
2208 + $content_type="image/jpx";
2209 + break;
2210 + case ".png":
2211 + $content_type="image/png";
2212 + break;
2213 + case ".tif":
2214 + case ".tiff":
2215 + $content_type="image/tiff";
2216 + break;
2217 + case ".wbmp":
2218 + $content_type="image/vnd.wap.wbmp";
2219 + break;
2220 + case ".xbm":
2221 + $content_type="image/xbm";
2222 + break;
2223 + case ".css":
2224 + $content_type="text/css";
2225 + break;
2226 + case ".txt":
2227 + $content_type="text/plain";
2228 + break;
2229 + case ".htm":
2230 + case ".html":
2231 + $content_type="text/html";
2232 + break;
2233 + case ".xml":
2234 + $content_type="text/xml";
2235 + break;
2236 + case ".mpg":
2237 + case ".mpe":
2238 + case ".mpeg":
2239 + $content_type="video/mpeg";
2240 + break;
2241 + case ".qt":
2242 + case ".mov":
2243 + $content_type="video/quicktime";
2244 + break;
2245 + case ".avi":
2246 + $content_type="video/x-ms-video";
2247 + break;
2248 + case ".eml":
2249 + $content_type="message/rfc822";
2250 + $encoding="7bit";
2251 + break;
2252 + default:
2253 + $content_type="application/octet-stream";
2254 + break;
2255 + }
2256 + break;
2257 + default:
2258 + return($this->OutputError($content_type." is not a supported automatic content type detection method"));
2259 + }
2260 + break;
2261 + default:
2262 + return($this->OutputError($content_type." is not a supported file content type"));
2263 + }
2264 + }
2265 + else
2266 + $content_type="application/octet-stream";
2267 + $definition=array(
2268 + "Content-Type"=>$content_type,
2269 + "Content-Transfer-Encoding"=>$encoding,
2270 + "NAME"=>$name
2271 + );
2272 + if(IsSet($file["Disposition"]))
2273 + {
2274 + switch(strtolower($file["Disposition"]))
2275 + {
2276 + case "inline":
2277 + case "attachment":
2278 + break;
2279 + default:
2280 + return($this->OutputError($file["Disposition"]." is not a supported message part content disposition"));
2281 + }
2282 + $definition["DISPOSITION"]=$file["Disposition"];
2283 + }
2284 + if(IsSet($file["FileName"]))
2285 + $definition["FILENAME"]=$file["FileName"];
2286 + else
2287 + {
2288 + if(IsSet($file["Data"]))
2289 + $definition["DATA"]=$file["Data"];
2290 + }
2291 + if(IsSet($file['Cache'])
2292 + && $file['Cache'])
2293 + $definition['Cache'] = 1;
2294 + return("");
2295 + }
2296 +
2297 +/*
2298 +{metadocument}
2299 + <function>
2300 + <name>CreateFilePart</name>
2301 + <type>STRING</type>
2302 + <documentation>
2303 + <purpose>Create a message part to be handled as a file.</purpose>
2304 + <usage>Pass a <argumentlink>
2305 + <function>CreateFilePart</function>
2306 + <argument>file</argument>
2307 + </argumentlink> definition associative array and get the created
2308 + part number in the <argumentlink>
2309 + <function>CreateFilePart</function>
2310 + <argument>part</argument>
2311 + </argumentlink> that is returned by reference.</usage>
2312 + <returnvalue>An error message in case there was an error or an empty
2313 + string otherwise. This return value may be safely ignored if the
2314 + function parameters are set correctly.</returnvalue>
2315 + </documentation>
2316 + <argument>
2317 + <name>file</name>
2318 + <type>HASH</type>
2319 + <documentation>
2320 + <purpose>Associative array to specify parameters that describe the
2321 + file part. Here follows the list of supported parameters that
2322 + should be used as indexes of the array:<paragraphbreak />
2323 + <tt>FileName</tt><paragraphbreak />
2324 + Name of the file from which the part data will be read when the
2325 + message is generated. It may be a remote URL as long as your PHP
2326 + installation is configured to allow accessing remote files with
2327 + the <tt>fopen()</tt> function.<paragraphbreak />
2328 + <tt>Data</tt><paragraphbreak />
2329 + String that specifies the data of the file. This should be used
2330 + as alternative data source to <tt>FileName</tt> for passing data
2331 + available in memory, like for instance files stored in a database
2332 + that was queried dynamically and the file contents was fetched
2333 + into a string variable.<paragraphbreak />
2334 + <tt>Name</tt><paragraphbreak />
2335 + Name of the file that will appear in the message. If this
2336 + parameter is missing the base name of the <tt>FileName</tt>
2337 + parameter is used, if present.<paragraphbreak />
2338 + <tt>Content-Type</tt><paragraphbreak />
2339 + Content type of the part: <tt>text/plain</tt> for text,
2340 + <tt>text/html</tt> for HTML, <tt>image/gif</tt> for GIF images,
2341 + etc..<paragraphbreak />
2342 + There is one special type named <tt>automatic/name</tt> that may
2343 + be used to tell the class to try to guess the content type from
2344 + the file name. Many file types are recognized from the file name
2345 + extension. If the file name extension is not recognized, the
2346 + default for binary data <tt>application/octet-stream</tt> is
2347 + assumed.<paragraphbreak />
2348 + <tt>Disposition</tt><paragraphbreak />
2349 + Information to whether this file part is meant to be used as a
2350 + file <tt>attachment</tt> or as a part meant to be displayed
2351 + <tt>inline</tt>, eventually integrated with another related
2352 + part.<paragraphbreak />
2353 + <tt>Cache</tt><paragraphbreak />
2354 + Boolean flag that indicates that this message part should be
2355 + cached when generating the message body. Use only when sending
2356 + many messages to multiple recipients, but this part does not
2357 + change between each of the messages that are sent.<paragraphbreak />
2358 + Note that it is also not worth using this option when setting the
2359 + <variablelink>cache_body</variablelink>, as that variable makes
2360 + the class cache the whole message body and the internal message
2361 + parts will not be rebuilt.</purpose>
2362 + </documentation>
2363 + </argument>
2364 + <argument>
2365 + <name>part</name>
2366 + <type>INTEGER</type>
2367 + <out />
2368 + <documentation>
2369 + <purpose>Number of the created part that is returned by reference.</purpose>
2370 + </documentation>
2371 + </argument>
2372 + <do>
2373 +{/metadocument}
2374 +*/
2375 + Function CreateFilePart(&$file,&$part)
2376 + {
2377 + if(strlen($this->GetFileDefinition($file,$definition)))
2378 + return($this->error);
2379 + return($this->CreatePart($definition,$part));
2380 + }
2381 +/*
2382 +{metadocument}
2383 + </do>
2384 + </function>
2385 +{/metadocument}
2386 +*/
2387 +
2388 +/*
2389 +{metadocument}
2390 + <function>
2391 + <name>AddFilePart</name>
2392 + <type>STRING</type>
2393 + <documentation>
2394 + <purpose>Add a message part to be handled as a file.</purpose>
2395 + <usage>Pass a <argumentlink>
2396 + <function>AddFilePart</function>
2397 + <argument>file</argument>
2398 + </argumentlink> definition associative array.</usage>
2399 + <returnvalue>An error message in case there was an error or an empty
2400 + string otherwise. This return value may be safely ignored if the
2401 + function parameters are set correctly.</returnvalue>
2402 + </documentation>
2403 + <argument>
2404 + <name>file</name>
2405 + <type>HASH</type>
2406 + <documentation>
2407 + <purpose>Associative array to specify parameters that describe the
2408 + file part. See the <argumentlink>
2409 + <function>CreateFilePart</function>
2410 + <argument>file</argument>
2411 + </argumentlink> argument description of the
2412 + <functionlink>CreateFilePart</functionlink> function for an
2413 + explanation about the supported file parameters.</purpose>
2414 + </documentation>
2415 + </argument>
2416 + <do>
2417 +{/metadocument}
2418 +*/
2419 + Function AddFilePart(&$file)
2420 + {
2421 + if(strlen($error=$this->CreateFilePart($file,$part))
2422 + || strlen($error=$this->AddPart($part)))
2423 + return($error);
2424 + return("");
2425 + }
2426 +/*
2427 +{metadocument}
2428 + </do>
2429 + </function>
2430 +{/metadocument}
2431 +*/
2432 +
2433 +/*
2434 +{metadocument}
2435 + <function>
2436 + <name>CreateMessagePart</name>
2437 + <type>STRING</type>
2438 + <documentation>
2439 + <purpose>Create a message part to encapsulate another message. This
2440 + is usually meant to create an attachment that contains a message
2441 + that was received and is being forwarded intact with the original
2442 + the headers and body data.</purpose>
2443 + <usage>This function should be used like the
2444 + <functionlink>CreateFilePart</functionlink> function, passing the
2445 + same parameters to the <argumentlink>
2446 + <function>CreateMessagePart</function>
2447 + <argument>message</argument>
2448 + </argumentlink> argument.<paragraphbreak />
2449 + The message to be encapsulated can be specified either as an
2450 + existing file with the <tt>FileName</tt> parameter, or as string
2451 + of data in memory with the <tt>Data</tt>
2452 + parameter.<paragraphbreak />
2453 + The <tt>Content-Type</tt> and <tt>Disposition</tt> file parameters
2454 + do not need to be specified because they are overridden by this
2455 + function.</usage>
2456 + <returnvalue>An error message in case there was an error or an empty
2457 + string otherwise. This return value may be safely ignored if the
2458 + function parameters are set correctly.</returnvalue>
2459 + </documentation>
2460 + <argument>
2461 + <name>message</name>
2462 + <type>HASH</type>
2463 + <documentation>
2464 + <purpose>Associative array that specifies definition parameters of
2465 + the message file part.</purpose>
2466 + </documentation>
2467 + </argument>
2468 + <argument>
2469 + <name>part</name>
2470 + <type>INTEGER</type>
2471 + <out />
2472 + <documentation>
2473 + <purpose>Number of the created part that is returned by reference.</purpose>
2474 + </documentation>
2475 + </argument>
2476 + <do>
2477 +{/metadocument}
2478 +*/
2479 + Function CreateMessagePart(&$message,&$part)
2480 + {
2481 + $message["Content-Type"]="message/rfc822";
2482 + $message["Disposition"]="inline";
2483 + if(strlen($this->GetFileDefinition($message,$definition)))
2484 + return($this->error);
2485 + return($this->CreatePart($definition,$part));
2486 + }
2487 +/*
2488 +{metadocument}
2489 + </do>
2490 + </function>
2491 +{/metadocument}
2492 +*/
2493 +
2494 +/*
2495 +{metadocument}
2496 + <function>
2497 + <name>AddMessagePart</name>
2498 + <type>STRING</type>
2499 + <documentation>
2500 + <purpose>Add a message part that encapsulates another message. This
2501 + is usually meant to add an attachment that contains a message that
2502 + was received and is being forwarded intact with the original the
2503 + headers and body data.</purpose>
2504 + <usage>This function should be used like the
2505 + <functionlink>AddFilePart</functionlink> function, passing the
2506 + same parameters to the <argumentlink>
2507 + <function>AddMessagePart</function>
2508 + <argument>message</argument>
2509 + </argumentlink> argument. See the
2510 + <functionlink>CreateFilePart</functionlink> function for more
2511 + details.</usage>
2512 + <returnvalue>An error message in case there was an error or an empty
2513 + string otherwise. This return value may be safely ignored if the
2514 + function parameters are set correctly.</returnvalue>
2515 + </documentation>
2516 + <argument>
2517 + <name>message</name>
2518 + <type>HASH</type>
2519 + <documentation>
2520 + <purpose>Associative array that specifies definition parameters of
2521 + the message file part.</purpose>
2522 + </documentation>
2523 + </argument>
2524 + <do>
2525 +{/metadocument}
2526 +*/
2527 + Function AddMessagePart(&$message)
2528 + {
2529 + if(strlen($error=$this->CreateMessagePart($message,$part))
2530 + || strlen($error=$this->AddPart($part)))
2531 + return($error);
2532 + return("");
2533 + }
2534 +/*
2535 +{metadocument}
2536 + </do>
2537 + </function>
2538 +{/metadocument}
2539 +*/
2540 +
2541 + Function CreateMultipart(&$parts,&$part,$type)
2542 + {
2543 + $definition=array(
2544 + "Content-Type"=>"multipart/".$type,
2545 + "PARTS"=>$parts
2546 + );
2547 + return($this->CreatePart($definition,$part));
2548 + }
2549 +
2550 + Function AddMultipart(&$parts,$type)
2551 + {
2552 + if(strlen($error=$this->CreateMultipart($parts,$part,$type))
2553 + || strlen($error=$this->AddPart($part)))
2554 + return($error);
2555 + return("");
2556 + }
2557 +
2558 +/*
2559 +{metadocument}
2560 + <function>
2561 + <name>CreateAlternativeMultipart</name>
2562 + <type>STRING</type>
2563 + <documentation>
2564 + <purpose>Create a message part composed of multiple parts that can be
2565 + displayed by the recipient e-mail program in alternative
2566 + formats.<paragraphbreak />
2567 + This is usually meant to create HTML messages with an alternative
2568 + text part to be displayed by programs that cannot display HTML
2569 + messages.</purpose>
2570 + <usage>Create all the alternative message parts that are going to be
2571 + sent and pass their numbers to the <argumentlink>
2572 + <function>CreateAlternativeMultipart</function>
2573 + <argument>parts</argument>
2574 + </argumentlink> array argument.<paragraphbreak />
2575 + The least sophisticated part, usually the text part, should appear
2576 + first in the parts array because the e-mail programs that support
2577 + displaying more sophisticated message parts will pick the last part
2578 + in the message that is supported.</usage>
2579 + <returnvalue>An error message in case there was an error or an empty
2580 + string otherwise. This return value may be safely ignored if the
2581 + function parameters are set correctly.</returnvalue>
2582 + </documentation>
2583 + <argument>
2584 + <name>parts</name>
2585 + <type>ARRAY</type>
2586 + <documentation>
2587 + <purpose>Array with the numbers with all the alternative parts.</purpose>
2588 + </documentation>
2589 + </argument>
2590 + <argument>
2591 + <name>part</name>
2592 + <type>INTEGER</type>
2593 + <out />
2594 + <documentation>
2595 + <purpose>Number of the created part that is returned by reference.</purpose>
2596 + </documentation>
2597 + </argument>
2598 + <do>
2599 +{/metadocument}
2600 +*/
2601 + Function CreateAlternativeMultipart(&$parts,&$part)
2602 + {
2603 + return($this->CreateMultiPart($parts,$part,"alternative"));
2604 + }
2605 +/*
2606 +{metadocument}
2607 + </do>
2608 + </function>
2609 +{/metadocument}
2610 +*/
2611 +
2612 +/*
2613 +{metadocument}
2614 + <function>
2615 + <name>AddAlternativeMultipart</name>
2616 + <type>STRING</type>
2617 + <documentation>
2618 + <purpose>Add a message part composed of multiple parts that can be
2619 + displayed by the recipient e-mail program in alternative
2620 + formats.<paragraphbreak />
2621 + This is usually meant to create HTML messages with an alternative
2622 + text part to be displayed by programs that cannot display HTML
2623 + messages.</purpose>
2624 + <usage>Create all the alternative message parts that are going to be
2625 + sent and pass their numbers to the <argumentlink>
2626 + <function>AddAlternativeMultipart</function>
2627 + <argument>parts</argument>
2628 + </argumentlink> array argument.<paragraphbreak />
2629 + The least sophisticated part, usually the text part, should appear
2630 + first in the parts array because the e-mail programs that support
2631 + displaying more sophisticated message parts will pick the last part
2632 + in the message that is supported.</usage>
2633 + <returnvalue>An error message in case there was an error or an empty
2634 + string otherwise. This return value may be safely ignored if the
2635 + function parameters are set correctly.</returnvalue>
2636 + </documentation>
2637 + <argument>
2638 + <name>parts</name>
2639 + <type>ARRAY</type>
2640 + <documentation>
2641 + <purpose>Array with the numbers with all the alternative parts.</purpose>
2642 + </documentation>
2643 + </argument>
2644 + <do>
2645 +{/metadocument}
2646 +*/
2647 + Function AddAlternativeMultipart(&$parts)
2648 + {
2649 + return($this->AddMultipart($parts,"alternative"));
2650 + }
2651 +/*
2652 +{metadocument}
2653 + </do>
2654 + </function>
2655 +{/metadocument}
2656 +*/
2657 +
2658 +/*
2659 +{metadocument}
2660 + <function>
2661 + <name>CreateRelatedMultipart</name>
2662 + <type>STRING</type>
2663 + <documentation>
2664 + <purpose>Create a message part that groups several related
2665 + parts.<paragraphbreak />
2666 + This is usually meant to group an HTML message part with images or
2667 + other types of files that should be embedded in the same message
2668 + and be displayed as a single part by the recipient e-mail
2669 + program.</purpose>
2670 + <usage>Create all the related message parts that are going to be
2671 + sent and pass their numbers to the <argumentlink>
2672 + <function>CreateRelatedMultipart</function>
2673 + <argument>parts</argument>
2674 + </argumentlink> array argument.<paragraphbreak />
2675 + When using this function to group an HTML message with embedded
2676 + images or other related files, make sure that the HTML part number
2677 + is the first listed in the <argumentlink>
2678 + <function>CreateRelatedMultipart</function>
2679 + <argument>parts</argument>
2680 + </argumentlink> array argument, or else the message may not appear
2681 + correctly.</usage>
2682 + <returnvalue>An error message in case there was an error or an empty
2683 + string otherwise. This return value may be safely ignored if the
2684 + function parameters are set correctly.</returnvalue>
2685 + </documentation>
2686 + <argument>
2687 + <name>parts</name>
2688 + <type>ARRAY</type>
2689 + <documentation>
2690 + <purpose>Array with the numbers with all the related parts.</purpose>
2691 + </documentation>
2692 + </argument>
2693 + <argument>
2694 + <name>part</name>
2695 + <type>INTEGER</type>
2696 + <out />
2697 + <documentation>
2698 + <purpose>Number of the created part that is returned by reference.</purpose>
2699 + </documentation>
2700 + </argument>
2701 + <do>
2702 +{/metadocument}
2703 +*/
2704 + Function CreateRelatedMultipart(&$parts,&$part)
2705 + {
2706 + return($this->CreateMultipart($parts,$part,"related"));
2707 + }
2708 +/*
2709 +{metadocument}
2710 + </do>
2711 + </function>
2712 +{/metadocument}
2713 +*/
2714 +
2715 +/*
2716 +{metadocument}
2717 + <function>
2718 + <name>AddRelatedMultipart</name>
2719 + <type>STRING</type>
2720 + <documentation>
2721 + <purpose>Add a message part that groups several related
2722 + parts.<paragraphbreak />
2723 + This is usually meant to group an HTML message part with images or
2724 + other types of files that should be embedded in the same message
2725 + and be displayed as a single part by the recipient e-mail
2726 + program.</purpose>
2727 + <usage>Create all the related message parts that are going to be
2728 + sent and pass their numbers to the <argumentlink>
2729 + <function>AddRelatedMultipart</function>
2730 + <argument>parts</argument>
2731 + </argumentlink> array argument.<paragraphbreak />
2732 + When using this function to group an HTML message with embedded
2733 + images or other related files, make sure that the HTML part number
2734 + is the first listed in the <argumentlink>
2735 + <function>AddRelatedMultipart</function>
2736 + <argument>parts</argument>
2737 + </argumentlink> array argument, or else the message may not appear
2738 + correctly.</usage>
2739 + <returnvalue>An error message in case there was an error or an empty
2740 + string otherwise. This return value may be safely ignored if the
2741 + function parameters are set correctly.</returnvalue>
2742 + </documentation>
2743 + <argument>
2744 + <name>parts</name>
2745 + <type>ARRAY</type>
2746 + <documentation>
2747 + <purpose>Array with the numbers with all the related parts.</purpose>
2748 + </documentation>
2749 + </argument>
2750 + <do>
2751 +{/metadocument}
2752 +*/
2753 + Function AddRelatedMultipart(&$parts)
2754 + {
2755 + return($this->AddMultipart($parts,"related"));
2756 + }
2757 +/*
2758 +{metadocument}
2759 + </do>
2760 + </function>
2761 +{/metadocument}
2762 +*/
2763 +
2764 +/*
2765 +{metadocument}
2766 + <function>
2767 + <name>CreateMixedMultipart</name>
2768 + <type>STRING</type>
2769 + <documentation>
2770 + <purpose>Create a message part that groups several independent
2771 + parts.<paragraphbreak />
2772 + Usually this is meant compose messages with one or more file
2773 + attachments. However, it is not necessary to use this function as
2774 + the class implicitly creates a <tt>multipart/mixed</tt> message
2775 + when more than one part is added to the message.</purpose>
2776 + <usage>Create all the independent message parts that are going to be
2777 + sent and pass their numbers to the <argumentlink>
2778 + <function>CreateMixedMultipart</function>
2779 + <argument>parts</argument>
2780 + </argumentlink> array argument.</usage>
2781 + <returnvalue>An error message in case there was an error or an empty
2782 + string otherwise. This return value may be safely ignored if the
2783 + function parameters are set correctly.</returnvalue>
2784 + </documentation>
2785 + <argument>
2786 + <name>parts</name>
2787 + <type>ARRAY</type>
2788 + <documentation>
2789 + <purpose>Array with the numbers with all the related parts.</purpose>
2790 + </documentation>
2791 + </argument>
2792 + <argument>
2793 + <name>part</name>
2794 + <type>INTEGER</type>
2795 + <out />
2796 + <documentation>
2797 + <purpose>Number of the created part that is returned by reference.</purpose>
2798 + </documentation>
2799 + </argument>
2800 + <do>
2801 +{/metadocument}
2802 +*/
2803 + Function CreateMixedMultipart(&$parts,&$part)
2804 + {
2805 + return($this->CreateMultipart($parts,$part,"mixed"));
2806 + }
2807 +/*
2808 +{metadocument}
2809 + </do>
2810 + </function>
2811 +{/metadocument}
2812 +*/
2813 +
2814 +/*
2815 +{metadocument}
2816 + <function>
2817 + <name>AddMixedMultipart</name>
2818 + <type>STRING</type>
2819 + <documentation>
2820 + <purpose>Add a message part that groups several independent
2821 + parts.<paragraphbreak />
2822 + Usually this is meant compose messages with one or more file
2823 + attachments. However, it is not necessary to use this function as
2824 + the class implicitly creates a <tt>multipart/mixed</tt> message
2825 + when more than one part is added to the message.</purpose>
2826 + <usage>Create all the independent message parts that are going to be
2827 + sent and pass their numbers to the <argumentlink>
2828 + <function>AddMixedMultipart</function>
2829 + <argument>parts</argument>
2830 + </argumentlink> array argument.</usage>
2831 + <returnvalue>An error message in case there was an error or an empty
2832 + string otherwise. This return value may be safely ignored if the
2833 + function parameters are set correctly.</returnvalue>
2834 + </documentation>
2835 + <argument>
2836 + <name>parts</name>
2837 + <type>ARRAY</type>
2838 + <documentation>
2839 + <purpose>Array with the numbers with all the related parts.</purpose>
2840 + </documentation>
2841 + </argument>
2842 + <do>
2843 +{/metadocument}
2844 +*/
2845 + Function AddMixedMultipart(&$parts)
2846 + {
2847 + return($this->AddMultipart($parts,"mixed"));
2848 + }
2849 +/*
2850 +{metadocument}
2851 + </do>
2852 + </function>
2853 +{/metadocument}
2854 +*/
2855 +
2856 + Function CreateParallelMultipart(&$parts,&$part)
2857 + {
2858 + return($this->CreateMultipart($parts,$part,"paralell"));
2859 + }
2860 +
2861 + Function AddParalellMultipart(&$parts)
2862 + {
2863 + return($this->AddMultipart($parts,"paralell"));
2864 + }
2865 +
2866 +/*
2867 +{metadocument}
2868 + <function>
2869 + <name>GetPartContentID</name>
2870 + <type>STRING</type>
2871 + <documentation>
2872 + <purpose>Retrieve the content identifier associated to a given
2873 + message part.</purpose>
2874 + <usage>Create a message part and pass its number to the <argumentlink>
2875 + <function>GetPartContentID</function>
2876 + <argument>part</argument>
2877 + </argumentlink> argument.<paragraphbreak />
2878 + This function is usually meant to create an URL that can be used
2879 + in an HTML message part to reference related parts like images, CSS
2880 + (Cascaded Style Sheets), or any other type of files related to the
2881 + HTML part that are embedded in the same message as part of a
2882 + <tt>multipart/related</tt> composite part.<paragraphbreak />
2883 + To use the part content identifier returned by this function you
2884 + need to prepend the string <tt><stringvalue>cid:</stringvalue></tt>
2885 + to form a special URL that can be used in the HTML document this
2886 + part file.<paragraphbreak />
2887 + You may read more about using this function in the class usage
2888 + section about <link>
2889 + <data>embedding images in HTML messages</data>
2890 + <name>embed-image</name>
2891 + </link>.</usage>
2892 + <returnvalue>The content identifier text string.<paragraphbreak />
2893 + If it is specified an invalid message part, this function returns
2894 + an empty string.</returnvalue>
2895 + </documentation>
2896 + <argument>
2897 + <name>part</name>
2898 + <type>INTEGER</type>
2899 + <documentation>
2900 + <purpose>Number of the part as returned by the function that
2901 + originally created it.</purpose>
2902 + </documentation>
2903 + </argument>
2904 + <do>
2905 +{/metadocument}
2906 +*/
2907 + Function GetPartContentID($part)
2908 + {
2909 + if(!IsSet($this->parts[$part]))
2910 + return("");
2911 + if(!IsSet($this->parts[$part]["Content-ID"]))
2912 + {
2913 + $extension=(IsSet($this->parts[$part]["NAME"]) ? $this->GetFilenameExtension($this->parts[$part]["NAME"]) : "");
2914 + $this->parts[$part]["Content-ID"]=md5(uniqid($part.time())).$extension;
2915 + }
2916 + return($this->parts[$part]["Content-ID"]);
2917 + }
2918 +/*
2919 +{metadocument}
2920 + </do>
2921 + </function>
2922 +{/metadocument}
2923 +*/
2924 +
2925 +/*
2926 +{metadocument}
2927 + <function>
2928 + <name>GetDataURL</name>
2929 + <type>STRING</type>
2930 + <documentation>
2931 + <purpose>Generate a <tt>data:</tt> URL according to the <link>
2932 + <data>RFC 2397</data>
2933 + <url>http://www.ietf.org/rfc/rfc2397.txt</url>
2934 + </link> suitable for using in HTML messages to represent an image
2935 + or other type of file on which the data is directly embedded in the
2936 + HTML code instead of being fetched from a separate file or remote
2937 + URL.<paragraphbreak />
2938 + Note that not all e-mail programs are capable of displaying images
2939 + or other types of files embedded in HTML messages this way.</purpose>
2940 + <usage>Pass a <argumentlink>
2941 + <function>GetDataURL</function>
2942 + <argument>file</argument>
2943 + </argumentlink> part definition array like for the
2944 + <functionlink>CreateFilePart</functionlink> function.</usage>
2945 + <returnvalue>The <tt>data:</tt> representing the described file or an
2946 + empty string in case there was an error.</returnvalue>
2947 + </documentation>
2948 + <argument>
2949 + <name>file</name>
2950 + <type>HASH</type>
2951 + <documentation>
2952 + <purpose>File definition.</purpose>
2953 + </documentation>
2954 + </argument>
2955 + <do>
2956 +{/metadocument}
2957 +*/
2958 + Function GetDataURL($file)
2959 + {
2960 + if(strlen($this->GetFileDefinition($file,$definition,0)))
2961 + return($this->error);
2962 + if(IsSet($definition["FILENAME"]))
2963 + {
2964 + $size=@filesize($definition["FILENAME"]);
2965 + if(!($file=@fopen($definition["FILENAME"],"rb")))
2966 + return($this->OutputPHPError("could not open data file ".$definition["FILENAME"], $php_errormsg));
2967 + for($body="";!feof($file);)
2968 + {
2969 + if(GetType($block=@fread($file,$this->file_buffer_length))!="string")
2970 + {
2971 + $this->OutputPHPError("could not read data file", $php_errormsg);
2972 + fclose($file);
2973 + return("");
2974 + }
2975 + $body.=$block;
2976 + }
2977 + fclose($file);
2978 + if(GetType($size)=="integer"
2979 + && strlen($body)!=$size)
2980 + {
2981 + $this->OutputError("the length of the file that was read does not match the size of the part file ".$definition["FILENAME"]." due to possible data corruption");
2982 + return("");
2983 + }
2984 + if(function_exists("ini_get")
2985 + && ini_get("magic_quotes_runtime"))
2986 + $body=StripSlashes($body);
2987 + $body=chunk_split(base64_encode($body));
2988 + }
2989 + else
2990 + {
2991 + if(!IsSet($definition["DATA"]))
2992 + {
2993 + $this->OutputError("it was not specified a file or data block");
2994 + return("");
2995 + }
2996 + $body=chunk_split(base64_encode($definition["DATA"]));
2997 + }
2998 + return("data:".$definition["Content-Type"].";base64,".$body);
2999 + }
3000 +/*
3001 +{metadocument}
3002 + </do>
3003 + </function>
3004 +{/metadocument}
3005 +*/
3006 +
3007 + Function GetHeadersAndBody(&$headers, &$body)
3008 + {
3009 + $headers=$this->headers;
3010 + if(strcmp($this->mailer,""))
3011 + {
3012 + $headers["X-Mailer"]=$this->mailer;
3013 + if(strlen($this->mailer_delivery))
3014 + $headers["X-Mailer"].=' ('.$this->mailer_delivery.')';
3015 + }
3016 + $headers["MIME-Version"]="1.0";
3017 + if($this->body_parts==0)
3018 + return($this->OutputError("message has no body parts"));
3019 + if(strlen($error=$this->GetPartHeaders($headers,$this->body)))
3020 + return($error);
3021 + if($this->cache_body
3022 + && IsSet($this->body_cache[$this->body]))
3023 + $body=$this->body_cache[$this->body];
3024 + else
3025 + {
3026 + if(strlen($error=$this->GetPartBody($body,$this->body)))
3027 + return($error);
3028 + if($this->cache_body)
3029 + $this->body_cache[$this->body]=$body;
3030 + }
3031 + return("");
3032 + }
3033 +
3034 +/*
3035 +{metadocument}
3036 + <function>
3037 + <name>Send</name>
3038 + <type>STRING</type>
3039 + <documentation>
3040 + <purpose>Send a composed message.</purpose>
3041 + <usage>Use this function after you have set the necessary message
3042 + headers and added the message body parts.</usage>
3043 + <returnvalue>An error message in case there was an error or an empty
3044 + string otherwise. This return value may be safely ignored if the
3045 + function parameters are set correctly.</returnvalue>
3046 + </documentation>
3047 + <do>
3048 +{/metadocument}
3049 +*/
3050 + Function Send()
3051 + {
3052 + if(strlen($this->error))
3053 + return($this->error);
3054 + if(strlen($error=$this->GetHeadersAndBody($headers, $body)))
3055 + return($error);
3056 + if(strcmp($error=$this->StartSendingMessage(),""))
3057 + return($error);
3058 + if(strlen($error=$this->SendMessageHeaders($headers))==0
3059 + && strlen($error=$this->SendMessageBody($body))==0)
3060 + $error=$this->EndSendingMessage();
3061 + $this->StopSendingMessage();
3062 + return($error);
3063 + }
3064 +/*
3065 +{metadocument}
3066 + </do>
3067 + </function>
3068 +{/metadocument}
3069 +*/
3070 +
3071 +/*
3072 +{metadocument}
3073 + <function>
3074 + <name>GetMessage</name>
3075 + <type>STRING</type>
3076 + <documentation>
3077 + <purpose>Get the whole message headers and body.</purpose>
3078 + <usage>Use this function to retrieve the message headers and body
3079 + without sending it.</usage>
3080 + <returnvalue>An error message in case there was an error or an empty
3081 + string otherwise. This return value may be safely ignored if the
3082 + function parameters are set correctly.</returnvalue>
3083 + </documentation>
3084 + <argument>
3085 + <name>message</name>
3086 + <type>STRING</type>
3087 + <out />
3088 + <documentation>
3089 + <purpose>Reference to a string variable to store the text of the
3090 + message headers and body.</purpose>
3091 + </documentation>
3092 + </argument>
3093 + <do>
3094 +{/metadocument}
3095 +*/
3096 + Function GetMessage(&$message)
3097 + {
3098 + if(strlen($this->error))
3099 + return($this->error);
3100 + if(strlen($error=$this->GetHeadersAndBody($headers, $body)))
3101 + return($error);
3102 + for($message="", $h=0, Reset($headers); $h<count($headers); ++$h, Next($headers))
3103 + {
3104 + $name=Key($headers);
3105 + $message.=$name.": ".$headers[$name].$this->line_break;
3106 + }
3107 + $message.=$this->line_break;
3108 + $message.=$body;
3109 + return("");
3110 + }
3111 +/*
3112 +{metadocument}
3113 + </do>
3114 + </function>
3115 +{/metadocument}
3116 +*/
3117 +
3118 +/*
3119 +{metadocument}
3120 + <function>
3121 + <name>GetMessageSize</name>
3122 + <type>STRING</type>
3123 + <documentation>
3124 + <purpose>Get the size of the whole message headers and body.</purpose>
3125 + <usage>Use this function to retrieve the size in bytes of the
3126 + message headers and body without sending it.</usage>
3127 + <returnvalue>An error message in case there was an error or an empty
3128 + string otherwise. This return value may be safely ignored if the
3129 + function parameters are set correctly.</returnvalue>
3130 + </documentation>
3131 + <argument>
3132 + <name>message</name>
3133 + <type>STRING</type>
3134 + <out />
3135 + <documentation>
3136 + <purpose>Reference to an integer variable to store the size of the
3137 + message headers and body.</purpose>
3138 + </documentation>
3139 + </argument>
3140 + <do>
3141 +{/metadocument}
3142 +*/
3143 + Function GetMessageSize(&$size)
3144 + {
3145 + if(strlen($error=$this->GetMessage($message)))
3146 + return($error);
3147 + $size=strlen($message);
3148 + return("");
3149 + }
3150 +/*
3151 +{metadocument}
3152 + </do>
3153 + </function>
3154 +{/metadocument}
3155 +*/
3156 +
3157 +/*
3158 +{metadocument}
3159 + <function>
3160 + <name>Mail</name>
3161 + <type>BOOLEAN</type>
3162 + <documentation>
3163 + <purpose>Emulate the PHP <tt>mail()</tt> function by composing and
3164 + sending a message given the same arguments.<paragraphbreak />
3165 + This is mostly meant to provide a solution for sending messages
3166 + with alternative delivery methods provided by this class
3167 + sub-classes. It uses the same arguments as the PHP <tt>mail()</tt>
3168 + function. Developers willing to use this alternative do not need to
3169 + change much their scripts that already use the <tt>mail()</tt>
3170 + function.</purpose>
3171 + <usage>Use this function passing the same arguments as to PHP
3172 + <tt><link>
3173 + <data>mail()</data>
3174 + <url>http://www.php.net/manual/en/function.mail.php</url>
3175 + </link></tt> function.</usage>
3176 + <returnvalue>If this function succeeds, it returns
3177 + <tt><booleanvalue>1</booleanvalue></tt>.</returnvalue>
3178 + </documentation>
3179 + <argument>
3180 + <name>to</name>
3181 + <type>STRING</type>
3182 + <documentation>
3183 + <purpose>Recipient e-mail address.</purpose>
3184 + </documentation>
3185 + </argument>
3186 + <argument>
3187 + <name>subject</name>
3188 + <type>STRING</type>
3189 + <documentation>
3190 + <purpose>Message subject.</purpose>
3191 + </documentation>
3192 + </argument>
3193 + <argument>
3194 + <name>message</name>
3195 + <type>STRING</type>
3196 + <documentation>
3197 + <purpose>Message body.</purpose>
3198 + </documentation>
3199 + </argument>
3200 + <argument>
3201 + <name>additional_headers</name>
3202 + <type>STRING</type>
3203 + <defaultvalue></defaultvalue>
3204 + <documentation>
3205 + <purpose>Text string headers and the respective values. There
3206 + should be one header and value per line with line breaks
3207 + separating each line.</purpose>
3208 + </documentation>
3209 + </argument>
3210 + <argument>
3211 + <name>additional_parameters</name>
3212 + <type>STRING</type>
3213 + <defaultvalue></defaultvalue>
3214 + <documentation>
3215 + <purpose>Text string with additional parameters. In the original
3216 + PHP <tt>mail()</tt> function these were actual switches to be
3217 + passed in the sendmail program invocation command line. This
3218 + function only supports the <tt>-f</tt> switch followed by an
3219 + e-mail address meant to specify the message bounce return path
3220 + address.</purpose>
3221 + </documentation>
3222 + </argument>
3223 + <do>
3224 +{/metadocument}
3225 +*/
3226 + Function Mail($to, $subject, $message, $additional_headers="", $additional_parameters="")
3227 + {
3228 + $this->ResetMessage();
3229 + $this->headers=array("To"=>$to,"Subject"=>$subject);
3230 + $content_type="";
3231 + while(strlen($additional_headers))
3232 + {
3233 + preg_match("/([^\r\n]+)(\r?\n)?(.*)\$/",$additional_headers,$matches);
3234 + $header=$matches[1];
3235 + $additional_headers=$matches[3];
3236 + if(!preg_match("/^([^:]+):[ \t]+(.+)\$/",$header,$matches))
3237 + {
3238 + $this->error="invalid header \"$header\"";
3239 + return(0);
3240 + }
3241 + if(strtolower($matches[1])=="content-type")
3242 + {
3243 + if(strlen($content_type))
3244 + {
3245 + $this->error="the content-type header was specified more than once.";
3246 + return(0);
3247 + }
3248 + $content_type=$matches[2];
3249 + }
3250 + else
3251 + $this->SetHeader($matches[1],$matches[2]);
3252 + }
3253 + if(strlen($additional_parameters))
3254 + {
3255 + if(preg_match("/^[ \t]*-f[ \t]*([^@]+@[^ \t]+)[ \t]*(.*)\$/", $additional_parameters, $matches))
3256 + {
3257 + if(!preg_match('/'.str_replace('/', '\\/', $this->email_regular_expression).'/i', $matches[1]))
3258 + {
3259 + $this->error="it was specified an invalid e-mail address for the additional parameter -f";
3260 + return(0);
3261 + }
3262 + if(strlen($matches[2]))
3263 + {
3264 + $this->error="it were specified some additional parameters after -f e-mail address parameter that are not supported";
3265 + return(0);
3266 + }
3267 + $this->SetHeader("Return-Path",$matches[1]);
3268 + }
3269 + else
3270 + {
3271 + $this->error="the additional parameters that were specified are not supported";
3272 + return(0);
3273 + }
3274 + }
3275 + if(strlen($content_type)==0)
3276 + $content_type="text/plain";
3277 + $definition=array(
3278 + "Content-Type"=>$content_type,
3279 + "DATA"=>$message
3280 + );
3281 + $this->CreateAndAddPart($definition);
3282 + $this->Send();
3283 + return(strlen($this->error)==0);
3284 + }
3285 +/*
3286 +{metadocument}
3287 + </do>
3288 + </function>
3289 +{/metadocument}
3290 +*/
3291 +
3292 + Function ChangeBulkMail($on)
3293 + {
3294 + return(1);
3295 + }
3296 +
3297 +/*
3298 +{metadocument}
3299 + <function>
3300 + <name>SetBulkMail</name>
3301 + <type>BOOLEAN</type>
3302 + <documentation>
3303 + <purpose>Hint the class to adjust itself in order to send individual
3304 + messages to many recipients more efficiently.</purpose>
3305 + <usage>Call this function before starting sending messages to many
3306 + recipients passing <booleanvalue>1</booleanvalue> to the
3307 + <argumentlink>
3308 + <function>SetBulkMail</function>
3309 + <argument>on</argument>
3310 + </argumentlink> argument. Then call this function again after the
3311 + bulk mailing delivery has ended passing passing
3312 + <booleanvalue>1</booleanvalue> to the <argumentlink>
3313 + <function>SetBulkMail</function>
3314 + <argument>on</argument>
3315 + </argumentlink> argument.</usage>
3316 + <returnvalue>If this function succeeds, it returns
3317 + <tt><booleanvalue>1</booleanvalue></tt>.</returnvalue>
3318 + </documentation>
3319 + <argument>
3320 + <name>on</name>
3321 + <type>BOOLEAN</type>
3322 + <documentation>
3323 + <purpose>Boolean flag that indicates whether a bulk delivery is
3324 + going to start if set to <booleanvalue>1</booleanvalue> or that
3325 + the bulk delivery has ended if set to
3326 + <booleanvalue>0</booleanvalue>.</purpose>
3327 + </documentation>
3328 + </argument>
3329 + <do>
3330 +{/metadocument}
3331 +*/
3332 + Function SetBulkMail($on)
3333 + {
3334 + if(strlen($this->error))
3335 + return(0);
3336 + if(!$this->bulk_mail==!$on)
3337 + return(1);
3338 + if(!$this->ChangeBulkMail($on))
3339 + return(0);
3340 + $this->bulk_mail=!!$on;
3341 + return(1);
3342 + }
3343 +/*
3344 +{metadocument}
3345 + </do>
3346 + </function>
3347 +{/metadocument}
3348 +*/
3349 +
3350 + Function OpenMailing(&$mailing,&$mailing_properties)
3351 + {
3352 + if(strlen($this->error))
3353 + return($this->error);
3354 + if(!IsSet($mailing_properties["Name"])
3355 + || strlen($mailing_properties["Name"])==0)
3356 + return($this->OutputError("it was not specified a valid mailing Name"));
3357 + if(!IsSet($mailing_properties["Return-Path"])
3358 + || strlen($mailing_properties["Return-Path"])==0)
3359 + return($this->OutputError("it was not specified a valid mailing Return-Path"));
3360 + $separator="";
3361 + $directory_separator=(defined("DIRECTORY_SEPARATOR") ? DIRECTORY_SEPARATOR : ((defined("PHP_OS") && !strcmp(substr(PHP_OS,0,3),"WIN")) ? "\\" : "/"));
3362 + $length=strlen($this->mailing_path);
3363 + if($length)
3364 + {
3365 + if($this->mailing_path[$length-1]!=$directory_separator)
3366 + $separator=$directory_separator;
3367 + }
3368 + $base_path=$this->mailing_path.$separator.$mailing_properties["Name"];
3369 + if($this->body_parts==0)
3370 + return($this->OutputError("message has no body parts"));
3371 + $line_break="\n";
3372 + $headers=$this->headers;
3373 + if(strlen($this->mailer))
3374 + $headers["X-Mailer"]=$this->mailer;
3375 + $headers["MIME-Version"]="1.0";
3376 + if(strlen($error=$this->GetPartHeaders($headers,$this->body)))
3377 + return($error);
3378 + if(!($header_file=@fopen($base_path.".h","wb")))
3379 + return($this->OutputPHPError("could not open mailing headers file ".$base_path.".h", $php_errormsg));
3380 + for($header=0,Reset($headers);$header<count($headers);Next($headers),++$header)
3381 + {
3382 + $header_name=Key($headers);
3383 + if(!@fwrite($header_file,$header_name.": ".$headers[$header_name].$line_break))
3384 + {
3385 + fclose($header_file);
3386 + return($this->OutputPHPError("could not write to the mailing headers file ".$base_path.".h", $php_errormsg));
3387 + }
3388 + }
3389 + if(!@fflush($header_file))
3390 + {
3391 + fclose($header_file);
3392 + @unlink($base_path.".h");
3393 + return($this->OutputPHPError("could not write to the mailing headers file ".$base_path.".h", $php_errormsg));
3394 + }
3395 + fclose($header_file);
3396 + if(strlen($error=$this->GetPartBody($body,$this->body)))
3397 + {
3398 + @unlink($base_path.".h");
3399 + return($error);
3400 + }
3401 + if(!($body_file=@fopen($base_path.".b","wb")))
3402 + {
3403 + @unlink($base_path.".h");
3404 + return($this->OutputPHPError("could not open mailing body file ".$base_path.".b", $php_errormsg));
3405 + }
3406 + if(!@fwrite($body_file,$body)
3407 + || !@fflush($body_file))
3408 + {
3409 + fclose($body_file);
3410 + @unlink($base_path.".b");
3411 + @unlink($base_path.".h");
3412 + return($this->OutputPHPError("could not write to the mailing body file ".$base_path.".b", $php_errormsg));
3413 + }
3414 + fclose($body_file);
3415 + if(!($envelope=@fopen($base_path.".e","wb")))
3416 + {
3417 + @unlink($base_path.".b");
3418 + @unlink($base_path.".h");
3419 + return($this->OutputPHPError("could not open mailing envelope file ".$base_path.".e", $php_errormsg));
3420 + }
3421 + if(!@fwrite($envelope,"F".$mailing_properties["Return-Path"].chr(0))
3422 + || !@fflush($envelope))
3423 + {
3424 + @fclose($envelope);
3425 + @unlink($base_path.".e");
3426 + @unlink($base_path.".b");
3427 + @unlink($base_path.".h");
3428 + return($this->OutputPHPError("could not write to the return path to the mailing envelope file ".$base_path.".e", $php_errormsg));
3429 + }
3430 + $mailing=++$this->last_mailing;
3431 + $this->mailings[$mailing]=array(
3432 + "Envelope"=>$envelope,
3433 + "BasePath"=>$base_path
3434 + );
3435 + return("");
3436 + }
3437 +
3438 + Function AddMailingRecipient($mailing,&$recipient_properties)
3439 + {
3440 + if(strlen($this->error))
3441 + return($this->error);
3442 + if(!IsSet($this->mailings[$mailing]))
3443 + return($this->OutputError("it was not specified a valid mailing"));
3444 + if(!IsSet($recipient_properties["Address"])
3445 + || strlen($recipient_properties["Address"])==0)
3446 + return($this->OutputError("it was not specified a valid mailing recipient Address"));
3447 + if(!@fwrite($this->mailings[$mailing]["Envelope"],"T".$recipient_properties["Address"].chr(0)))
3448 + return($this->OutputPHPError("could not write recipient address to the mailing envelope file", $php_errormsg));
3449 + return("");
3450 + }
3451 +
3452 + Function EndMailing($mailing)
3453 + {
3454 + if(strlen($this->error))
3455 + return($this->error);
3456 + if(!IsSet($this->mailings[$mailing]))
3457 + return($this->OutputError("it was not specified a valid mailing"));
3458 + if(!IsSet($this->mailings[$mailing]["Envelope"]))
3459 + return($this->OutputError("the mailing was already ended"));
3460 + if(!@fwrite($this->mailings[$mailing]["Envelope"],chr(0))
3461 + || !@fflush($this->mailings[$mailing]["Envelope"]))
3462 + return($this->OutputPHPError("could not end writing to the mailing envelope file", $php_errormsg));
3463 + fclose($this->mailings[$mailing]["Envelope"]);
3464 + Unset($this->mailings[$mailing]["Envelope"]);
3465 + return("");
3466 + }
3467 +
3468 + Function SendMailing($mailing)
3469 + {
3470 + if(strlen($this->error))
3471 + return($this->error);
3472 + if(!IsSet($this->mailings[$mailing]))
3473 + return($this->OutputError("it was not specified a valid mailing"));
3474 + if(IsSet($this->mailings[$mailing]["Envelope"]))
3475 + return($this->OutputError("the mailing was not yet ended"));
3476 + $this->ResetMessage();
3477 + $base_path=$this->mailings[$mailing]["BasePath"];
3478 + if(GetType($header_lines=@File($base_path.".h"))!="array")
3479 + return($this->OutputPHPError("could not read the mailing headers file ".$base_path.".h", $php_errormsg));
3480 + for($line=0;$line<count($header_lines);++$line)
3481 + {
3482 + $header_name=$this->Tokenize($header_lines[$line],": ");
3483 + $this->headers[$header_name]=trim($this->Tokenize("\n"));
3484 + }
3485 + if(!($envelope_file=@fopen($base_path.".e","rb")))
3486 + return($this->OutputPHPError("could not open the mailing envelope file ".$base_path.".e", $php_errormsg));
3487 + for($bcc=$data="",$position=0;!feof($envelope_file) || strlen($data);)
3488 + {
3489 + if(GetType($break=strpos($data,chr(0),$position))!="integer")
3490 + {
3491 + if(GetType($chunk=@fread($envelope_file,$this->file_buffer_length))!="string")
3492 + {
3493 + fclose($envelope_file);
3494 + return($this->OutputPHPError("could not read the mailing envelop file ".$base_path.".e", $php_errormsg));
3495 + }
3496 + $data=substr($data,$position).$chunk;
3497 + $position=0;
3498 + continue;
3499 + }
3500 + if($break==$position)
3501 + break;
3502 + switch($data[$position])
3503 + {
3504 + case "F":
3505 + $this->headers["Return-Path"]=substr($data,$position+1,$break-$position-1);
3506 + break;
3507 + case "T":
3508 + $bcc.=(strlen($bcc)==0 ? "" : ", ").substr($data,$position+1,$break-$position-1);
3509 + break;
3510 + default:
3511 + return($this->OutputError("invalid mailing envelope file ".$base_path.".e"));
3512 + }
3513 + $position=$break+1;
3514 + }
3515 + fclose($envelope_file);
3516 + if(strlen($bcc)==0)
3517 + return($this->OutputError("the mailing envelop file ".$base_path.".e does not contain any recipients"));
3518 + $this->headers["Bcc"]=$bcc;
3519 + if(!($body_file=@fopen($base_path.".b","rb")))
3520 + return($this->OutputPHPError("could not open the mailing body file ".$base_path.".b", $php_errormsg));
3521 + for($data="";!feof($body_file);)
3522 + {
3523 + if(GetType($chunk=@fread($body_file,$this->file_buffer_length))!="string")
3524 + {
3525 + fclose($body_file);
3526 + return($this->OutputPHPError("could not read the mailing body file ".$base_path.".b", $php_errormsg));
3527 + }
3528 + $data.=$chunk;
3529 + }
3530 + fclose($body_file);
3531 + if(strlen($error=$this->StartSendingMessage()))
3532 + return($error);
3533 + if(strlen($error=$this->SendMessageHeaders($this->headers))==0
3534 + && strlen($error=$this->SendMessageBody($data))==0)
3535 + $error=$this->EndSendingMessage();
3536 + $this->StopSendingMessage();
3537 + return($error);
3538 + }
3539 +};
3540 +
3541 +/*
3542 +
3543 +{metadocument}
3544 +</class>
3545 +{/metadocument}
3546 +
3547 +*/
3548 +
3549 +?>