--- /dev/null
+<?php
+/*
+ * Plugin Facteur 2
+ * (c) 2009-2011 Collectif SPIP
+ * Distribue sous licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Transformer un mail texte ou HTML simplifie en mail HTML complet avec le wrapper emails/texte.html
+ * Si le mail est un mail texte :
+ * la premiere ligne est le sujet
+ * le reste est le corps du mail
+ *
+ * Si le mail est un mail HTML simplifie :
+ * le sujet est entre <title></title>
+ * le corps est entre <body></body>
+ * une eventuelle intro peut etre fournie entre <intro></intro>
+ *
+ * @param string $texte_ou_html
+ * @return string
+ */
+function facteur_email_wrap_to_html($texte_ou_html){
+ $texte_ou_html = trim($texte_ou_html);
+ // attention : si pas de contenu on renvoi du vide aussi (mail vide = mail vide)
+ if (!strlen(trim($texte_ou_html)))
+ return $texte_ou_html;
+
+ $contexte = array("sujet"=>"","texte"=>"","intro"=>"");
+
+ // tester si le mail est en html (simplifie)
+ if (substr($texte_ou_html,0,1)=="<"
+ AND substr($texte_ou_html,-1,1)==">"
+ AND stripos($texte_ou_html,"</body>")!==false){
+
+ // dans ce cas on ruse un peu : extraire le sujet du title
+ $sujet = "";
+ if (preg_match(",<title>(.*)</title>,Uims",$texte_ou_html,$m)){
+ $contexte['sujet'] = $m[1];
+ $texte_ou_html = preg_replace(",<title>(.*)</title>,Uims","",$texte_ou_html,1);
+ $texte_ou_html = trim($texte_ou_html);
+ }
+ if (preg_match(",<intro>(.*)</intro>,Uims",$texte_ou_html,$m)){
+ $contexte['intro'] = $m[1];
+ $texte_ou_html = preg_replace(",<intro>(.*)</intro>,Uims","",$texte_ou_html,1);
+ $texte_ou_html = trim($texte_ou_html);
+ }
+ $contexte['html'] = preg_replace(",</?body>,ims","",$texte_ou_html);
+ }
+ else {
+ // la premiere ligne est toujours le sujet
+ $texte_ou_html = explode("\n",$texte_ou_html);
+ $contexte['sujet'] = trim(array_shift($texte_ou_html));
+ $contexte['texte'] = trim(implode("\n",$texte_ou_html));
+ }
+
+ // attention : si pas de contenu on renvoi du vide aussi (mail vide = mail vide)
+ if (!strlen(trim(implode("",$contexte))))
+ return "";
+
+ return recuperer_fond("emails/texte",$contexte);
+}
+
+ /*
+
+ Written by Eric Dols - edols@auditavenue.com
+
+ You may freely use or modify this, provided
+ you leave credits to the original coder.
+ Feedback about (un)successfull uses, bugs and improvements done
+ are much appreciated, but don't expect actual support.
+
+ PURPOSE OF THIS FUNCTION
+ It is designed to process html emails relying
+ on a css stylesheet placed in the <head> for layout in
+ order to enhance compatibility with email clients,
+ including webmail services.
+ Provided you use minimal css, you can keep styling separate
+ from the content in your email template, and let this function
+ "inject" those styles inline in your email html tags on-the-fly,
+ just before sending.
+ Technically, it grabs the style declarations found in the
+ <head> section and inserts each declaration inline,
+ inside the corresponding html tags in the email message.
+
+ Supports both HTML and XHTML markup seamlessly. Thus
+ tolerant to email message writers using non-xhtml tag,
+ even when template is xhtml compliant (e.g. they would
+ add <img ...> instead of a xhtml compliant <img ... />).
+
+ NEW 10 dec. 2003:
+ - code revised, including a few regexp bugs fixed.
+ - multiple class for a tag are now allowed <p class="firstclass secondclass">
+ - all unsupported css styles are now moved to the body section (not just a:hover etc...)
+
+ USE
+ Add this function to a function library include, like "inline.inc"
+ and include it near the beginning of your php page:
+ require ("inline.inc");
+
+ load the html source of message into a variable
+ like $html_source and process it using:
+ $html_source = sheet2inline($html_source)
+
+
+ STYLE DEFINITIONS SUPPORTED
+ TAG { ... }
+ TAG1, TAG2, ... { ... }
+ TAG.class { ... }
+ .class { ...)
+ TAG:pseudo { ... }
+
+
+ CSS definitions may be freely formatted (spaces, tabs, linefeeds...),
+ they are converted to oneliners before inserting them inline in the html tags.
+
+ .class definitions are processed AFTER tag definitions,
+ thus appended inline after any existing tag styling to
+ preserve the normal css priority behavior.
+
+ Existing style="..." attributes in tags are NOT stripped. However they MUST
+ be with double quotes. If not, an addtional style="..." attribute will be added
+
+
+ KNOWN LIMITATIONS
+ - style info should be placed in <head> section. I believe
+ it shouldnt be too hard to modify to point to an external
+ stylesheet instead.
+ - no support (yet?):
+ * chains like P UL LI { .... } or P UL LI.class { .... }
+ * #divname p { ... } and <tag id="...">
+ * a:hover, a:visited {...} multiple class:pseudo
+ They require a significantly more complicated processing likely
+ based on stylesheet and document trees parsing.
+ Many email clients don't handle more than what is supported
+ by this script anyway.
+ - pseudo-classes like a:hover {...} can't be inserted inline
+ in the html tags: they are moved to a <style> declaration in
+ the <body> instead. This is a limitation from html, not this script.
+ - It is still up to you to check if target email clients render
+ your css styled templates correctly, especially webmail services
+ like Hotmail, in which the email becomes a sub-part of an html page,
+ with styles already in place.
+ */
+function facteur_convertir_styles_inline($body){
+ // variables to be accessed in the callback sub-function too
+ global $styledefinition, $styletag, $styleclass;
+
+ // Let's first load the stylesheet information in a $styles array using a regexp
+ preg_match_all ( "/^[ \t]*([.]?)([\w, #]+)([.:])?(\S*)\s+{([^}]+)}/mi", $body , $styles);
+ /*
+ $styles[1] = . or '' => .class or tag (empty)
+ $styles[2] = name of class or tag(s)
+ $styles[3] = : . or '' => followed by pseudo-element, class separator or nothing (empty)
+ $styles[4] = name of pseudo-element after a tag, if any
+ $styles[5] = the style definition itself, i.e. what's between the { }
+ */
+
+ // Now loop through the styles found and act accordingly;
+
+ // process TAG {...} & TAG1, TAG2,... {...} definitions only first by order of appearance
+ foreach ($styles[1] as $i => $type) {
+ if ($type=="" && $styles[3][$i]=="") {
+ $styledefinition = trim($styles[5][$i]);
+ $styletag = preg_replace("/ *, */", "|", trim($styles[2][$i])); //echo $styletag."<br />";
+ $styleclass = "";
+ // process TAG {...} and TAG1, TAG2 {...} but not TAG1 TAG2 {...} or #divname styles
+ if (!preg_match("/ /", $styletag) && !preg_match("/#/", $styletag)) {
+ $pattern = "!<(".$styletag.")([^>]*(?= /)|[^>]*)( /)?>!mi";
+ $body = preg_replace_callback ($pattern, 'facteur_addstyle' , $body);
+ $styles[6][$i]=1; // mark as injected inline
+ }
+ }
+ }
+
+ // append additional .CLASS {...} and TAG.CLASS {...} styling by order of appearance
+ // important to do so after TAG {...} definitions, so that class attributes override TAG styles when needed
+ foreach ($styles[1] as $i => $type) {
+ if ($type!="." && $styles[3][$i]=="." ) { // class definition for a specific tag
+ $styledefinition = trim($styles[5][$i]);
+ $styletag = trim($styles[2][$i]);
+ $styleclass = trim($styles[4][$i]);
+ $pattern = "!<(".$styletag.")([^>]* class\=['\"][^'\"]*".$styleclass."[^'\"]*['\"][^>]*(?= /)|[^>]* class\=['\"][^'\"]*".$styleclass."[^'\"]*['\"][^>]*)( />)?>!mi";
+ $body = preg_replace_callback ($pattern, 'facteur_addstyle' , $body);
+ $styles[6][$i]=1; // mark as injected inline
+
+ }
+ elseif ($type=="." && $styles[3][$i]=="" ) { // general class definition for any tag
+ $styledefinition = trim($styles[5][$i]);
+ $styletag = "";
+ $styleclass = trim($styles[2][$i]);
+ $pattern = "!<(\w+)([^>]* class\=['\"]".$styleclass."['\"][^>]*(?= /)|[^>]* class\=['\"]".$styleclass."['\"][^>]*)( />)?>!mi";
+ $body = preg_replace_callback ($pattern, 'facteur_addstyle' , $body);
+ $styles[6][$i]=1; // mark as injected inline
+ }
+ }
+
+
+ /* move all style declarations that weren't injected from <head> to a <body> <style> section,
+ including but not limited to:
+ - pseudo-classes like a:hover {...} as they can't be set inline
+ - declaration chains like UL LI {...}
+ - #divname {...}. These are not supported by email clients like Mac/Entourage anyway, it seems. */
+ foreach ($styles[1] as $i => $type) {
+ if ($styles[6][$i]=="") {
+ // add a <style type="text/css"> section after <body> if there's isn't one yet
+ if (preg_match ("!<body[^>]*>\s*<style!mi", $body)==0) {
+ $body = preg_replace ("/(<body[^>]*>)/i", "\n\$1\n".'<style type="text/css">'."\n<!--\n-->\n</style>\n", $body);
+ }
+ // append a copy of the pseudo-element declaration to that body style section
+ $styledefinition = trim($styles[5][$i]);
+ $styledefinition = preg_replace ("!\s+!mi", " ", $styledefinition ); // convert style definition to a one-liner (optional)
+ $declaration = $styles[1][$i].trim($styles[2][$i]).$styles[3][$i].trim($styles[4][$i])." { ".$styledefinition." }";
+ $body = preg_replace ("!(<body[^>]*>\s*<style[^>]*>\s*<\!\-\-[^>]*)"."(\s*\-\->\s*</style>)!si", "\$1".$declaration."\n\$2", $body);
+ $styles[6][$i]= 2; // mark as moved to <style> section in <body>
+ }
+ }
+
+ // remove stylesheet declaration(s) from <head> section (comment following line out if not wanted)
+ //$body = preg_replace ("!(<head>.*)<style type.*</style>(.*</head>)!si", "\$1\$2" , $body);
+
+ // check what styles have been injected
+# print_r($styles);
+
+ return $body;
+}
+
+/**
+ * facteur_addstyle
+ * @author Eric Dols
+ *
+ * @param $matches
+ * @return string
+ */
+function facteur_addstyle($matches) {
+
+ // $matches[1]=tag, $matches[2]=tag attributes (if any), $matches[3]=xhtml closing (if any)
+
+ // variables values set in calling function
+ global $styledefinition, $styletag, $styleclass;
+
+ // convert the style definition to a one-liner
+ $styledefinition = preg_replace ("!\s+!mi", " ", $styledefinition );
+ // convert all double-quotes to single-quotes
+ $styledefinition = preg_replace ('/"/','\'', $styledefinition );
+
+ if (preg_match ("/style\=/i", $matches[2])) {
+ // add styles to existing style attribute if any already in the tag
+ $pattern = "!(.* style\=)[\"]([^\"]*)[\"](.*)!mi";
+ $replacement = "\$1".'"'."\$2 ".$styledefinition.'"'."\$3";
+ $attributes = preg_replace ($pattern, $replacement , $matches[2]);
+ } else {
+ // otherwise add new style attribute to tag (none was present)
+ $attributes = $matches[2].' style="'.$styledefinition.'"';
+ }
+
+ if ($styleclass!="") {
+ // if we were injecting a class style, remove the now useless class attribute from the html tag
+
+ // Single class in tag case (class="classname"): remove class attribute altogether
+ $pattern = "!(.*) class\=['\"]".$styleclass."['\"](.*)!mi";
+ $replacement = "\$1\$2";
+ $attributes = preg_replace ( $pattern, $replacement, $attributes);
+
+ // Multiple classes in tag case (class="classname anotherclass..."): remove class name from class attribute.
+ // classes are injected inline and removed by order of appearance in <head> stylesheet
+ // exact same behavior as where last declared class attributes in <style> take over (IE6 tested only)
+ $pattern = "!(.* class\=['\"][^\"]*)(".$styleclass." | ".$styleclass.")([^\"]*['\"].*)!mi";
+ $replacement = "\$1\$3";
+ $attributes = preg_replace ( $pattern, $replacement, $attributes);
+
+ }
+
+ return "<".$matches[1].$attributes.$matches[3].">";
+}
+
+/**
+ * Un filtre pour transformer les retour ligne texte en br si besoin (si pas autobr actif)
+ *
+ * @param string $texte
+ * @return string
+ */
+function facteur_nl2br_si_pas_autobr($texte){
+ return (_AUTOBR?$texte:nl2br($texte));
+}
+
+/**
+ * Transformer un mail HTML en mail Texte proprement :
+ * - les tableaux de mise en page sont utilisés pour structurer le mail texte
+ * - le reste du HTML est markdownifie car c'est un format texte lisible et conventionnel
+ *
+ * @param string $html
+ * @return string
+ */
+function facteur_mail_html2text($html){
+ // nettoyer les balises de mise en page html
+ $html = preg_replace(",</(td|th)>,Uims","<br/>",$html);
+ $html = preg_replace(",</(table)>,Uims","@@@hr@@@",$html);
+ $html = preg_replace(",</?(html|body|table|td|th|tbody|thead|center|article|section|span)[^>]*>,Uims","\n\n",$html);
+
+ // commentaires html et conditionnels
+ $html = preg_replace(",<!--.*-->,Uims","\n",$html);
+ $html = preg_replace(",<!\[.*\]>,Uims","\n",$html);
+
+ $html = preg_replace(",<(/?)(div|tr|caption)([^>]*>),Uims","<\\1p>",$html);
+ $html = preg_replace(",(<p>\s*)+,ims","<p>",$html);
+ $html = preg_replace(",<br/?>\s*</p>,ims","</p>",$html);
+ $html = preg_replace(",</p>\s*<br/?>,ims","</p>",$html);
+ $html = preg_replace(",(</p>\s*(@@@hr@@@)?\s*)+,ims","</p>\\2",$html);
+ $html = preg_replace(",(<p>\s*</p>),ims","",$html);
+
+ // succession @@@hr@@@<hr> et <hr>@@@hr@@@
+ $html = preg_replace(",@@@hr@@@\s*(<[^>]*>\s*)?<hr[^>]*>,ims","@@@hr@@@\n",$html);
+ $html = preg_replace(",<hr[^>]*>\s*(<[^>]*>\s*)?@@@hr@@@,ims","\n@@@hr@@@",$html);
+
+ $html = preg_replace(",<textarea[^>]*spip_cadre[^>]*>(.*)</textarea>,Uims","<code>\n\\1\n</code>",$html);
+
+ // vider le contenu de qqunes :
+ $html = preg_replace(",<head[^>]*>.*</head>,Uims","\n",$html);
+
+ // Liens :
+ // Nettoyage des liens des notes de bas de page
+ $html = preg_replace("@<a href=\"#n(b|h)[0-9]+-[0-9]+\" name=\"n(b|h)[0-9]+-[0-9]+\" class=\"spip_note\">([0-9]+)</a>@", "\\3", $html);
+ // Supprimer tous les liens internes
+ $html = preg_replace("/\<a href=['\"]#(.*?)['\"][^>]*>(.*?)<\/a>/ims","\\2", $html);
+ // Remplace tous les liens
+ preg_match_all("/\<a href=['\"](.*?)['\"][^>]*>(.*?)<\/a>/ims", $html,$matches,PREG_SET_ORDER);
+ $prelinks = $postlinks = array();
+ foreach ($matches as $k => $match){
+ $link = "@@@link$k@@@";
+ $url = str_replace("&","&",$match[1]);
+ if ($match[2]==$match[1] OR $match[2]==$url){
+ // si le texte est l'url :
+ $prelinks[$match[0]] = "$link";
+ }
+ else {
+ // texte + url
+ $prelinks[$match[0]] = $match[2] . " ($link)";
+ }
+ $postlinks[$link] = $url;
+ }
+ $html = str_replace(array_keys($prelinks), array_values($prelinks),$html);
+
+ // les images par leur alt ?
+ // au moins les puces
+ $html = preg_replace(',<img\s[^>]*alt="-"[^>]*>,Uims','-',$html);
+ // les autres
+ $html = preg_replace(',<img\s[^>]*alt=[\'"]([^\'"]*)[\'"][^>]*>,Uims',"\\1",$html);
+ // on vire celles sans alt
+ $html = preg_replace(",</?(img)[^>]*>,Uims","\n",$html);
+
+ // espaces
+ $html = str_replace(" "," ",$html);
+ $html = preg_replace(",<p>\s+,ims","<p>",$html);
+
+ #return $html;
+ include_spip("lib/markdownify/markdownify");
+ $parser = new Markdownify('inline',false,false);
+ $texte = $parser->parseString($html);
+
+ $texte = str_replace(array_keys($postlinks), array_values($postlinks),$texte);
+
+
+ // trim et sauts de ligne en trop ou pas assez
+ $texte = trim($texte);
+ $texte = str_replace("<br />\n","\n",$texte);
+ $texte = preg_replace(",(@@@hr@@@\s*)+\Z,ims","",$texte);
+ $texte = preg_replace(",(@@@hr@@@\s*\n)+,ims","\n\n\n".str_pad("-",75,"-")."\n\n\n",$texte);
+ $texte = preg_replace(",(\n#+\s),ims","\n\n\\1",$texte);
+ $texte = preg_replace(",(\n\s*)(\n\s*)+(\n)+,ims","\n\n\n",$texte);
+
+
+ // <p> et </p> restants
+ $texte = str_replace(array("<p>","</p>"),array("",""),$texte);
+
+ // entites restantes ? (dans du code...)
+ include_spip('inc/charsets');
+ $texte = unicode2charset($texte);
+ $texte = str_replace(array(''', '"'),array("'",'"'), $texte);
+
+
+ // Faire des lignes de 75 caracteres maximum
+ return trim(wordwrap($texte));
+}
+?>