1<?php
2
3/**
4 * Swift Mailer Message Component
5 * Composes MIME 1.0 messages meeting various RFC standards
6 * Deals with attachments, embedded images, multipart bodies, forwarded messages...
7 * Please read the LICENSE file
8 * @copyright Chris Corbyn <chris@w3style.co.uk>
9 * @author Chris Corbyn <chris@w3style.co.uk>
10 * @package Swift_Message
11 * @license GNU Lesser General Public License
12 */
13
14require_once dirname(__FILE__) . "/ClassLoader.php";
15Swift_ClassLoader::load("Swift_Address");
16Swift_ClassLoader::load("Swift_Message_Mime");
17Swift_ClassLoader::load("Swift_Message_Image");
18Swift_ClassLoader::load("Swift_Message_Part");
19
20
21/**
22 * Swift Message class
23 * @package Swift_Message
24 * @author Chris Corbyn <chris@w3style.co.uk>
25 */
26class Swift_Message extends Swift_Message_Mime
27{
28  /**
29   * Constant from a high priority message (pretty meaningless)
30   */
31  const PRIORITY_HIGH = 1;
32  /**
33   * Constant for a low priority message
34   */
35  const PRIORITY_LOW = 5;
36  /**
37   * Constant for a normal priority message
38   */
39  const PRIORITY_NORMAL = 3;
40  /**
41   * The MIME warning for client not supporting multipart content
42   * @var string
43   */
44  protected $mimeWarning = null;
45  /**
46   * The version of the library (Swift) if known.
47   * @var string
48   */
49  protected $libVersion = "";
50  /**
51   * A container for references to other objects.
52   * This is used in some very complex logic when sub-parts get shifted around.
53   * @var array
54   */
55  protected $references = array(
56    "parent" => array("alternative" => null, "mixed" => null, "related" => null),
57    "alternative" => array(),
58    "mixed" => array(),
59    "related" => array()
60  );
61
62  /**
63   * Ctor.
64   * @param string Message subject
65   * @param string Body
66   * @param string Content-type
67   * @param string Encoding
68   * @param string Charset
69   */
70  public function __construct($subject="", $body=null, $type="text/plain", $encoding=null, $charset=null)
71  {
72    parent::__construct();
73    if (function_exists("date_default_timezone_set") && function_exists("date_default_timezone_get"))
74    {
75      date_default_timezone_set(@date_default_timezone_get());
76    }
77    $this->setReturnPath(null);
78    $this->setTo("");
79    $this->setFrom("");
80    $this->setCc(null);
81    $this->setBcc(null);
82    $this->setReplyTo(null);
83    $this->setSubject($subject);
84    $this->setDate(time());
85    if (defined("Swift::VERSION"))
86    {
87      $this->libVersion = Swift::VERSION;
88      $this->headers->set("X-LibVersion", $this->libVersion);
89    }
90    $this->headers->set("MIME-Version", "1.0");
91    $this->setContentType($type);
92    $this->setCharset($charset);
93    $this->setFlowed(true);
94    $this->setEncoding($encoding);
95
96    foreach (array_keys($this->references["parent"]) as $key)
97    {
98      $this->setReference("parent", $key, $this);
99    }
100
101    $this->setMimeWarning(
102    "This is a message in multipart MIME format.  Your mail client should not be displaying this. " .
103    "Consider upgrading your mail client to view this message correctly."
104    );
105
106    if ($body !== null)
107    {
108      $this->setData($body);
109      if ($charset === null)
110      {
111        Swift_ClassLoader::load("Swift_Message_Encoder");
112        if (Swift_Message_Encoder::instance()->isUTF8($body)) $this->setCharset("utf-8");
113        else $this->setCharset("iso-8859-1");
114      }
115    }
116  }
117  /**
118   * Sets a reference so when nodes are nested, operations can be redirected.
119   * This really should be refactored to use just one array rather than dynamic variables.
120   * @param string Key 1
121   * @param string Key 2
122   * @param Object Reference
123   */
124  protected function setReference($where, $key, $ref)
125  {
126    if ($ref === $this) $this->references[$where][$key] = false;
127    else $this->references[$where][$key] = $ref;
128  }
129  /**
130   * Get a reference to an object (for complex reasons).
131   * @param string Key 1
132   * @param string Key 2
133   * @return Object
134   */
135  protected function getReference($where, $key)
136  {
137    if (!$this->references[$where][$key]) return $this;
138    else return $this->references[$where][$key];
139  }
140  /**
141   * Get the level in the MIME hierarchy at which this section should appear.
142   * @return string
143   */
144  public function getLevel()
145  {
146    return Swift_Message_Mime::LEVEL_TOP;
147  }
148  /**
149   * Set the message id literally.
150   * Unless you know what you are doing you should be using generateId() rather than this method,
151   * otherwise you may break compliancy with RFC 2822.
152   * @param string The message ID string.
153   */
154  public function setId($id)
155  {
156    $this->headers->set("Message-ID", $id);
157  }
158  /**
159   * Create a RFC 2822 compliant message id, optionally based upon $idstring.
160   * The message ID includes information about the current time, the server and some random characters.
161   * @param string An optional string the base the ID on
162   * @return string The generated message ID, including the <> quotes.
163   * @author Cristian Rodriguez <judas.iscariote@flyspray.org>
164   */
165  public function generateId($idstring=null)
166  {
167    $midparams =  array(
168      "utctime" => gmstrftime("%Y%m%d%H%M%S"),
169      "pid" => getmypid(),
170      "randint" => mt_rand(),
171      "customstr" => (preg_match("/^(?<!\\.)[a-z0-9\\.]+(?!\\.)\$/iD", $idstring) ? $idstring : "swift") ,
172      "hostname" => (isset($_SERVER["SERVER_NAME"]) ? $_SERVER["SERVER_NAME"] : php_uname("n")),
173    );
174    $this->setId(vsprintf("<%s.%d.%d.%s@%s>", $midparams));
175    return $this->getId();
176  }
177  /**
178   * Get the generated message ID for this message, including the <> quotes.
179   * If generated automatically, or using generateId() this method returns a RFC2822 compliant Message-ID.
180   * @return string
181   * @author Cristian Rodriguez <judas.iscariote@flyspray.org>
182   */
183  public function getId()
184  {
185    return $this->headers->has("Message-ID") ? $this->headers->get("Message-ID") : null;
186  }
187  /**
188   * Set the address in the Return-Path: header
189   * @param string The bounce-detect address
190   */
191  public function setReturnPath($address)
192  {
193    if ($address instanceof Swift_Address) $address = $address->build(true);
194    $this->headers->set("Return-Path", $address);
195  }
196  /**
197   * Return the address used in the Return-Path: header
198   * @return string
199   * @param boolean Return the address for SMTP command
200   */
201  public function getReturnPath($smtp=false)
202  {
203    if ($this->headers->has("Return-Path"))
204    {
205      if (!$smtp) return $this->headers->get("Return-Path");
206      else
207      {
208        $path = $this->headers->get("Return-Path");
209        if (strpos($path, ">") > strpos($path, "<")) return substr($path, ($start = strpos($path, "<")), ($start + strrpos($path, ">") + 1));
210        else return "<" . $path . ">";
211      }
212    }
213  }
214  /**
215   * Set the address in the From: header
216   * @param string The address to set as From
217   */
218  public function setFrom($from)
219  {
220    if ($from instanceof Swift_Address) $from = $from->build();
221    $this->headers->set("From", $from);
222  }
223  /**
224   * Get the address used in the From: header
225   * @return string
226   */
227  public function getFrom()
228  {
229    if ($this->headers->has("From")) return $this->headers->get("From");
230  }
231  /**
232   * Set the list of recipients in the To: header
233   * @param mixed An array or a string
234   */
235  public function setTo($to)
236  {
237    if ($to)
238    {
239      if (!is_array($to)) $to = array($to);
240      foreach ($to as $key => $value)
241      {
242        if ($value instanceof Swift_Address) $to[$key] = $value->build();
243      }
244    }
245    $this->headers->set("To", $to);
246  }
247  /**
248   * Return the list of recipients in the To: header
249   * @return array
250   */
251  public function getTo()
252  {
253    if ($this->headers->has("To"))
254    {
255      $to = $this->headers->get("To");
256      if ($to == "") return array();
257      else return (array) $to;
258    }
259  }
260  /**
261   * Set the list of recipients in the Reply-To: header
262   * @param mixed An array or a string
263   */
264  public function setReplyTo($replyto)
265  {
266    if ($replyto)
267    {
268      if (!is_array($replyto)) $replyto = array($replyto);
269      foreach ($replyto as $key => $value)
270      {
271        if ($value instanceof Swift_Address) $replyto[$key] = $value->build();
272      }
273    }
274    $this->headers->set("Reply-To", $replyto);
275  }
276  /**
277   * Return the list of recipients in the Reply-To: header
278   * @return array
279   */
280  public function getReplyTo()
281  {
282    if ($this->headers->has("Reply-To"))
283    {
284      $reply_to = $this->headers->get("Reply-To");
285      if ($reply_to == "") return array();
286      else return (array) $reply_to;
287    }
288  }
289  /**
290   * Set the list of recipients in the Cc: header
291   * @param mixed An array or a string
292   */
293  public function setCc($cc)
294  {
295    if ($cc)
296    {
297      if (!is_array($cc)) $cc = array($cc);
298      foreach ($cc as $key => $value)
299      {
300        if ($value instanceof Swift_Address) $cc[$key] = $value->build();
301      }
302    }
303    $this->headers->set("Cc", $cc);
304  }
305  /**
306   * Return the list of recipients in the Cc: header
307   * @return array
308   */
309  public function getCc()
310  {
311    if ($this->headers->has("Cc"))
312    {
313      $cc = $this->headers->get("Cc");
314      if ($cc == "") return array();
315      else return (array) $cc;
316    }
317  }
318  /**
319   * Set the list of recipients in the Bcc: header
320   * @param mixed An array or a string
321   */
322  public function setBcc($bcc)
323  {
324    if ($bcc)
325    {
326      if (!is_array($bcc)) $bcc = array($bcc);
327      foreach ($bcc as $key => $value)
328      {
329        if ($value instanceof Swift_Address) $bcc[$key] = $value->build();
330      }
331    }
332    $this->headers->set("Bcc", $bcc);
333  }
334  /**
335   * Return the list of recipients in the Bcc: header
336   * @return array
337   */
338  public function getBcc()
339  {
340    if ($this->headers->has("Bcc"))
341    {
342      $bcc = $this->headers->get("Bcc");
343      if ($bcc == "") return array();
344      else return (array) $bcc;
345    }
346  }
347  /**
348   * Set the subject in the headers
349   * @param string The subject of the email
350   */
351  public function setSubject($subject)
352  {
353    $this->headers->set("Subject", $subject);
354  }
355  /**
356   * Get the current subject used in the headers
357   * @return string
358   */
359  public function getSubject()
360  {
361    return $this->headers->get("Subject");
362  }
363  /**
364   * Set the date in the headers in RFC 2822 format
365   * @param int The time as a UNIX timestamp
366   */
367  public function setDate($date)
368  {
369    $this->headers->set("Date", date("r", $date));
370  }
371  /**
372   * Get the date as it looks in the headers
373   * @return string
374   */
375  public function getDate()
376  {
377    return strtotime($this->headers->get("Date"));
378  }
379  /**
380   * Set the charset of the document
381   * @param string The charset used
382   */
383  public function setCharset($charset)
384  {
385    $this->headers->setAttribute("Content-Type", "charset", $charset);
386    if (($this->getEncoding() == "7bit") && (strtolower($charset) == "utf-8" || strtolower($charset) == "utf8")) $this->setEncoding("8bit");
387  }
388  /**
389   * Get the charset used in the document
390   * Returns null if none is set
391   * @return string
392   */
393  public function getCharset()
394  {
395    if ($this->headers->hasAttribute("Content-Type", "charset"))
396    {
397      return $this->headers->getAttribute("Content-Type", "charset");
398    }
399    else
400    {
401      return null;
402    }
403  }
404  /**
405   * Set the "format" attribute to flowed
406   * @param boolean On or Off
407   */
408  public function setFlowed($flowed=true)
409  {
410    $value = null;
411    if ($flowed) $value = "flowed";
412    $this->headers->setAttribute("Content-Type", "format", $value);
413  }
414  /**
415   * Check if the message format is set as flowed
416   * @return boolean
417   */
418  public function isFlowed()
419  {
420    if ($this->headers->hasAttribute("Content-Type", "format")
421      && $this->headers->getAttribute("Content-Type", "format") == "flowed")
422    {
423      return true;
424    }
425    else return false;
426  }
427  /**
428   * Set the message prioirty in the mail client (don't rely on this)
429   * @param int The priority as a value between 1 (high) and 5 (low)
430   */
431  public function setPriority($priority)
432  {
433    $priority = (int) $priority;
434    if ($priority > self::PRIORITY_LOW) $priority = self::PRIORITY_LOW;
435    if ($priority < self::PRIORITY_HIGH) $priority = self::PRIORITY_HIGH;
436    $label = array(1 => "High", 2 => "High", 3 => "Normal", 4 => "Low", 5 => "Low");
437    $this->headers->set("X-Priority", $priority);
438    $this->headers->set("X-MSMail-Priority", $label[$priority]);
439    $this->headers->set("X-MimeOLE", "Produced by SwiftMailer " . $this->libVersion);
440  }
441  /**
442   * Request that the client send back a read-receipt (don't rely on this!)
443   * @param string Request address
444   */
445  public function requestReadReceipt($request)
446  {
447    if ($request instanceof Swift_Address) $request = $request->build();
448    if (!$request)
449    {
450      $this->headers->set("Disposition-Notification-To", null);
451      $this->headers->set("X-Confirm-Reading-To", null);
452      $this->headers->set("Return-Receipt-To", null);
453    }
454    else
455    {
456      $this->headers->set("Disposition-Notification-To", $request);
457      $this->headers->set("X-Confirm-Reading-To", $request);
458      $this->headers->set("Return-Receipt-To", $request);
459    }
460  }
461  /**
462   * Check if a read receipt has been requested for this message
463   * @return boolean
464   */
465  public function wantsReadReceipt()
466  {
467    return $this->headers->has("Disposition-Notification-To");
468  }
469  /**
470   * Get the current message priority
471   * Returns NULL if none set
472   * @return int
473   */
474  public function getPriority()
475  {
476    if ($this->headers->has("X-Priority")) return $this->headers->get("X-Priority");
477    else return null;
478  }
479  /**
480   * Alias for setData()
481   * @param mixed Body
482   */
483  public function setBody($body)
484  {
485    $this->setData($body);
486  }
487  /**
488   * Alias for getData()
489   * @return mixed The document body
490   */
491  public function getBody()
492  {
493    return $this->getData();
494  }
495  /**
496   * Set the MIME warning message which is displayed to old clients
497   * @var string The full warning message (in 7bit ascii)
498   */
499  public function setMimeWarning($text)
500  {
501    $this->mimeWarning = (string) $text;
502  }
503  /**
504   * Get the MIME warning which is displayed to old clients
505   * @return string
506   */
507  public function getMimeWarning()
508  {
509    return $this->mimeWarning;
510  }
511  /**
512   * Attach a mime part or an attachment of some sort
513   * Any descendant of Swift_Message_Mime can be added safely (including other Swift_Message objects for mail forwarding!!)
514   * @param Swift_Message_Mime The document to attach
515   * @param string An identifier to use (one is returned otherwise)
516   * @return string The identifier for the part
517   */
518  public function attach(Swift_Message_Mime $child, $id=null)
519  {
520    try {
521      switch ($child->getLevel())
522      {
523        case Swift_Message_Mime::LEVEL_ALTERNATIVE:
524          $sign = (strtolower($child->getContentType()) == "text/plain") ? -1 : 1;
525          $id = $this->getReference("parent", "alternative")->addChild($child, $id, $sign);
526          $this->setReference("alternative", $id, $child);
527          break;
528        case Swift_Message_Mime::LEVEL_RELATED:
529          $id = "cid:" . $child->getContentId();
530          $id = $this->getReference("parent", "related")->addChild($child, $id, 1);
531          $this->setReference("related", $id, $child);
532          break;
533        case Swift_Message_Mime::LEVEL_MIXED: default:
534          $id = $this->getReference("parent", "mixed")->addChild($child, $id, 1);
535          $this->setReference("mixed", $id, $child);
536          break;
537      }
538      $this->postAttachFixStructure();
539      $this->fixContentType();
540      return $id;
541    } catch (Swift_Message_MimeException $e) {
542      throw new Swift_Message_MimeException("Something went wrong whilst trying to move some MIME parts during an attach(). " .
543        "The MIME component threw an exception:<br />" . $e->getMessage());
544    }
545  }
546  /**
547   * Remove a nested MIME part
548   * @param string The ID of the attached part
549   * @throws Swift_Message_MimeException If no such part exists
550   */
551  public function detach($id)
552  {
553    try {
554      switch (true)
555      {
556        case array_key_exists($id, $this->references["alternative"]):
557          $this->getReference("parent", "alternative")->removeChild($id);
558          unset($this->references["alternative"][$id]);
559          break;
560        case array_key_exists($id, $this->references["related"]):
561          $this->getReference("parent", "related")->removeChild($id);
562          unset($this->references["related"][$id]);
563          break;
564        case array_key_exists($id, $this->references["mixed"]):
565          $this->getReference("parent", "mixed")->removeChild($id);
566          unset($this->references["mixed"][$id]);
567          break;
568        default:
569          throw new Swift_Message_MimeException("Unable to detach part identified by ID '" . $id . "' since it's not registered.");
570          break;
571      }
572      $this->postDetachFixStructure();
573      $this->fixContentType();
574    } catch (Swift_Message_MimeException $e) {
575      throw new Swift_Message_MimeException("Something went wrong whilst trying to move some MIME parts during a detach(). " .
576        "The MIME component threw an exception:<br />" . $e->getMessage());
577    }
578  }
579  /**
580   * Sets the correct content type header by looking at what types of data we have set
581   */
582  protected function fixContentType()
583  {
584    if (!empty($this->references["mixed"])) $this->setContentType("multipart/mixed");
585    elseif (!empty($this->references["related"])) $this->setContentType("multipart/related");
586    elseif (!empty($this->references["alternative"])) $this->setContentType("multipart/alternative");
587  }
588  /**
589   * Move a branch of the tree, containing all it's MIME parts onto another branch
590   * @param string The content type on the branch itself
591   * @param string The content type which may exist in the branch's parent
592   * @param array The array containing all the nodes presently
593   * @param string The location of the branch now
594   * @param string The location of the branch after moving
595   * @param string The key to identify the branch by in it's new location
596   */
597  protected function moveBranchIn($type, $nested_type, $from, $old_branch, $new_branch, $tag)
598  {
599    $new = new Swift_Message_Part();
600    $new->setContentType($type);
601    $this->getReference("parent", $new_branch)->addChild($new, $tag, -1);
602
603    switch ($new_branch)
604    {
605      case "related": $this->setReference("related", $tag, $new);//relatedRefs[$tag] = $new;
606        break;
607      case "mixed": $this->setReference("mixed", $tag, $new);//mixedRefs[$tag] = $new;
608        break;
609    }
610
611    foreach ($from as $id => $ref)
612    {
613      if (!$ref) $ref = $this;
614      $sign = (strtolower($ref->getContentType()) == "text/plain"
615        || strtolower($ref->getContentType()) == $nested_type) ? -1 : 1;
616      switch ($new_branch)
617      {
618        case "related": $this->getReference("related", $tag)->addChild($ref, $id, $sign);
619          break;
620        case "mixed": $this->getReference("mixed", $tag)->addChild($ref, $id, $sign);
621          break;
622      }
623      $this->getReference("parent", $old_branch)->removeChild($id);
624    }
625    $this->setReference("parent", $old_branch, $new); //parentRefs[$old_branch] = $new;
626  }
627  /**
628   * Analyzes the mixing of MIME types in a mulitpart message an re-arranges if needed
629   * It looks complicated and long winded but the concept is pretty simple, even if putting it
630   * in code does me make want to cry!
631   */
632  protected function postAttachFixStructure()
633  {
634    switch (true)
635    {
636      case (!empty($this->references["mixed"]) && !empty($this->references["related"]) && !empty($this->references["alternative"])):
637        if (!isset($this->references["related"]["_alternative"]))
638        {
639          $this->moveBranchIn(
640            "multipart/alternative", "multipart/alternative", $this->references["alternative"], "alternative", "related", "_alternative");
641        }
642        if (!isset($this->references["mixed"]["_related"]))
643        {
644          $this->moveBranchIn(
645            "multipart/related", "multipart/alternative", $this->references["related"], "related", "mixed", "_related");
646        }
647        break;
648      case (!empty($this->references["mixed"]) && !empty($this->references["related"])):
649        if (!isset($this->references["mixed"]["_related"]))
650        {
651          $this->moveBranchIn(
652            "multipart/related", "multipart/related", $this->references["related"], "related", "mixed", "_related");
653        }
654        break;
655      case (!empty($this->references["mixed"]) && !empty($this->references["alternative"])):
656        if (!isset($this->references["mixed"]["_alternative"]))
657        {
658          $this->moveBranchIn(
659            "multipart/alternative", null, $this->references["alternative"], "alternative", "mixed", "_alternative");
660        }
661        break;
662      case (!empty($this->references["related"]) && !empty($this->references["alternative"])):
663        if (!isset($this->references["related"]["_alternative"]))
664        {
665          $this->moveBranchIn(
666            "multipart/alternative", "multipart/alternative", $this->references["alternative"], "alternative", "related", "_alternative");
667        }
668        break;
669    }
670  }
671  /**
672   * Move a branch further toward the top of the tree
673   * @param array The array containing MIME parts from the old branch
674   * @param string The name of the old branch
675   * @param string The name of the new branch
676   * @param string The key of the branch being moved
677   */
678  protected function moveBranchOut($from, $old_branch, $new_branch, $tag)
679  {
680    foreach ($from as $id => $ref)
681    {
682      if (!$ref) $ref = $this;
683      $sign = (strtolower($ref->getContentType()) == "text/html"
684        || strtolower($ref->getContentType()) == "multipart/alternative") ? -1 : 1;
685      $this->getReference("parent", $new_branch)->addChild($ref, $id, $sign);
686      switch ($new_branch)
687      {
688        case "related": $this->getReference("related", $tag)->removeChild($id);
689          break;
690        case "mixed": $this->getReference("parent", $old_branch)->removeChild($id);
691          break;
692      }
693    }
694    $this->getReference("parent", $new_branch)->removeChild($tag);
695    $mixed = $this->getReference("parent", $new_branch);//parentRefs[$new_branch];
696    $this->setReference("parent", $old_branch, $mixed);//parentRefs[$old_branch] = $mixed;
697    switch ($new_branch)
698    {
699      case "related": unset($this->references["related"][$tag]);
700        break;
701      case "mixed": unset($this->references["mixed"][$tag]);
702        break;
703    }
704  }
705  /**
706   * Analyzes the mixing of MIME types in a mulitpart message an re-arranges if needed
707   * It looks complicated and long winded but the concept is pretty simple, even if putting it
708   * in code does me make want to cry!
709   */
710  protected function postDetachFixStructure()
711  {
712    switch (true)
713    {
714      case (!empty($this->references["mixed"]) && !empty($this->references["related"]) && !empty($this->references["alternative"])):
715        if (array_keys($this->references["related"]) == array("_alternative"))
716        {
717          $alt = $this->getReference("parent", "related")->getChild("_alternative");
718          $this->getReference("parent", "mixed")->addChild($alt, "_alternative", -1);
719          $this->setReference("mixed", "_alternative", $alt);//mixedRefs["_alternative"] = $alt;
720          $this->getReference("parent", "related")->removeChild("_alternative");
721          unset($this->references["related"]["_alternative"]);
722          $this->getReference("parent", "mixed")->removeChild("_related");
723          unset($this->references["mixed"]["_related"]);
724        }
725        if (array_keys($this->references["mixed"]) == array("_related"))
726        {
727          $this->moveBranchOut($this->references["related"], "related", "mixed", "_related");
728        }
729        break;
730      case (!empty($this->references["mixed"]) && !empty($this->references["related"])):
731        if (array_keys($this->references["mixed"]) == array("_related"))
732        {
733          $this->moveBranchOut($this->references["related"], "related", "mixed", "_related");
734        }
735        if (isset($this->references["related"]["_alternative"]))
736        {
737          $this->detach("_alternative");
738        }
739        break;
740      case (!empty($this->references["mixed"]) && !empty($this->references["alternative"])):
741        if (array_keys($this->references["mixed"]) == array("_alternative"))
742        {
743          $this->moveBranchOut($this->references["alternative"], "alternative", "mixed", "_alternative");
744        }
745        break;
746      case (!empty($this->references["related"]) && !empty($this->references["alternative"])):
747        if (array_keys($this->references["related"]) == array("_alternative"))
748        {
749          $this->moveBranchOut($this->references["alternative"], "alternative", "related", "_alternative");
750        }
751        break;
752      case (!empty($this->references["mixed"])):
753        if (isset($this->references["mixed"]["_related"])) $this->detach("_related");
754      case (!empty($this->references["related"])):
755        if (isset($this->references["related"]["_alternative"]) || isset($this->references["mixed"]["_alternative"]))
756          $this->detach("_alternative");
757        break;
758    }
759  }
760  /**
761   * Execute needed logic prior to compilation
762   */
763  public function preBuild()
764  {
765    $data = $this->getData();
766    if (!($enc = $this->getEncoding()))
767    {
768      $this->setEncoding("8bit");
769    }
770    if ($this->getCharset() === null && !$this->numChildren())
771    {
772      Swift_ClassLoader::load("Swift_Message_Encoder");
773      if (is_string($data) && Swift_Message_Encoder::instance()->isUTF8($data))
774      {
775        $this->setCharset("utf-8");
776      }
777      elseif(is_string($data) && Swift_Message_Encoder::instance()->is7BitAscii($data))
778      {
779        $this->setCharset("us-ascii");
780        if (!$enc) $this->setEncoding("7bit");
781      }
782      else $this->setCharset("iso-8859-1");
783    }
784    elseif ($this->numChildren())
785    {
786      if (!$this->getData())
787      {
788        $this->setData($this->getMimeWarning());
789        $this->setLineWrap(76);
790      }
791
792      if ($this->getCharset() !== null) $this->setCharset(null);
793      if ($this->isFlowed()) $this->setFlowed(false);
794      $this->setEncoding("7bit");
795    }
796  }
797}
798