summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Gohr <andi@splitbrain.org>2012-04-20 21:44:48 +0200
committerAndreas Gohr <andi@splitbrain.org>2012-04-20 21:44:48 +0200
commit73d2d14ce0b465ec7117c8dc6ab39a59f6ed7b5a (patch)
tree6f051c557dd65b39b71a77e47dca695d31c9c4df
parentf64856ce8e8057c67c211aadd41ff22ec10f2bb0 (diff)
parent8a803cae76e430dc0f358986db3420ef45049370 (diff)
downloadrpg-73d2d14ce0b465ec7117c8dc6ab39a59f6ed7b5a.tar.gz
rpg-73d2d14ce0b465ec7117c8dc6ab39a59f6ed7b5a.tar.bz2
Merge branch 'master' into phpunit
* master: (29 commits) some edge case checking in search result highlighting Resolve empty page ID to configured start page Added more detail error code for unauthorized calls in xmlrpc interface. changed internal Mailer members from private to protected made it possible to disable HTML mails in the config removed commented code left from the quoted_printable days add missing table tags for HTML diff mails fixed subscriber mail signatures use real HRs in HTML mails Add various headers to the mails FS#2247. pull request #83 closed removed footer image from HTML mails use inlinestyles for diffs in HTML mails fixed signature stripping fixed mailprefix handling fixed missing replacement for HTML notify mails allow image embeds in HTML mail templates Added HTML wrapper for mails allow non-txt extensions when accessing locales added Mailer class to autoloader Replaced mail_send calls with new Mailer class ...
-rw-r--r--conf/dokuwiki.php1
-rw-r--r--inc/DifferenceEngine.php61
-rw-r--r--inc/Mailer.class.php652
-rw-r--r--inc/RemoteAPICore.php28
-rw-r--r--inc/auth.php50
-rw-r--r--inc/common.php90
-rw-r--r--inc/fulltext.php2
-rw-r--r--inc/html.php7
-rw-r--r--inc/lang/en/mailwrap.html13
-rw-r--r--inc/lang/en/subscr_digest.txt2
-rw-r--r--inc/lang/en/subscr_list.txt2
-rw-r--r--inc/lang/en/subscr_single.txt2
-rw-r--r--inc/load.php3
-rw-r--r--inc/media.php34
-rw-r--r--inc/pageutils.php12
-rw-r--r--inc/subscription.php22
-rw-r--r--lib/exe/xmlrpc.php3
-rw-r--r--lib/plugins/config/lang/en/lang.php1
-rw-r--r--lib/plugins/config/settings/config.metadata.php1
19 files changed, 848 insertions, 138 deletions
diff --git a/conf/dokuwiki.php b/conf/dokuwiki.php
index 4ca29b461..35f946b10 100644
--- a/conf/dokuwiki.php
+++ b/conf/dokuwiki.php
@@ -110,6 +110,7 @@ $conf['notify'] = ''; //send change info to this email (leave
$conf['registernotify'] = ''; //send info about newly registered users to this email (leave blank for nobody)
$conf['mailfrom'] = ''; //use this email when sending mails
$conf['mailprefix'] = ''; //use this as prefix of outgoing mails
+$conf['htmlmail'] = 1; //send HTML multipart mails
/* Syndication Settings */
$conf['sitemap'] = 0; //Create a google sitemap? How often? In days.
diff --git a/inc/DifferenceEngine.php b/inc/DifferenceEngine.php
index 01926b20c..0a7ce8e7c 100644
--- a/inc/DifferenceEngine.php
+++ b/inc/DifferenceEngine.php
@@ -818,6 +818,39 @@ class DiffFormatter {
}
}
+/**
+ * Utilityclass for styling HTML formatted diffs
+ *
+ * Depends on global var $DIFF_INLINESTYLES, if true some minimal predefined
+ * inline styles are used. Useful for HTML mails and RSS feeds
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+class HTMLDiff {
+ /**
+ * Holds the style names and basic CSS
+ */
+ static public $styles = array(
+ 'diff-addedline' => 'background-color: #ddffdd;',
+ 'diff-deletedline' => 'background-color: #ffdddd;',
+ 'diff-context' => 'background-color: #f5f5f5;',
+ 'diff-mark' => 'color: #ff0000;',
+ );
+
+ /**
+ * Return a class or style parameter
+ */
+ static function css($classname){
+ global $DIFF_INLINESTYLES;
+
+ if($DIFF_INLINESTYLES){
+ if(!isset(self::$styles[$classname])) return '';
+ return 'style="'.self::$styles[$classname].'"';
+ }else{
+ return 'class="'.$classname.'"';
+ }
+ }
+}
/**
* Additions by Axel Boldt follow, partly taken from diff.php, phpwiki-1.3.3
@@ -838,11 +871,11 @@ class _HWLDF_WordAccumulator {
function _flushGroup($new_tag) {
if ($this->_group !== '') {
if ($this->_tag == 'mark')
- $this->_line .= '<strong>'.$this->_group.'</strong>';
+ $this->_line .= '<strong '.HTMLDiff::css('diff-mark').'>'.$this->_group.'</strong>';
elseif ($this->_tag == 'add')
- $this->_line .= '<span class="diff-addedline">'.$this->_group.'</span>';
+ $this->_line .= '<span '.HTMLDiff::css('diff-addedline').'>'.$this->_group.'</span>';
elseif ($this->_tag == 'del')
- $this->_line .= '<span class="diff-deletedline"><del>'.$this->_group.'</del></span>';
+ $this->_line .= '<span '.HTMLDiff::css('diff-deletedline').'><del>'.$this->_group.'</del></span>';
else
$this->_line .= $this->_group;
}
@@ -1020,8 +1053,8 @@ class TableDiffFormatter extends DiffFormatter {
global $lang;
$l1 = $lang['line'].' '.$xbeg;
$l2 = $lang['line'].' '.$ybeg;
- $r = '<tr><td class="diff-blockheader" colspan="2">'.$l1.":</td>\n".
- '<td class="diff-blockheader" colspan="2">'.$l2.":</td>\n".
+ $r = '<tr><td '.HTMLDiff::css('diff-blockheader').' colspan="2">'.$l1.":</td>\n".
+ '<td '.HTMLDiff::css('diff-blockheader').' colspan="2">'.$l2.":</td>\n".
"</tr>\n";
return $r;
}
@@ -1037,11 +1070,11 @@ class TableDiffFormatter extends DiffFormatter {
}
function addedLine($line) {
- return '<td>+</td><td class="diff-addedline">' . $line.'</td>';
+ return '<td>+</td><td '.HTMLDiff::css('diff-addedline').'>' . $line.'</td>';
}
function deletedLine($line) {
- return '<td>-</td><td class="diff-deletedline">' . $line.'</td>';
+ return '<td>-</td><td '.HTMLDiff::css('diff-deletedline').'>' . $line.'</td>';
}
function emptyLine() {
@@ -1049,7 +1082,7 @@ class TableDiffFormatter extends DiffFormatter {
}
function contextLine($line) {
- return '<td> </td><td class="diff-context">'.$line.'</td>';
+ return '<td> </td><td '.HTMLDiff::css('diff-context').'>'.$line.'</td>';
}
function _added($lines) {
@@ -1115,9 +1148,9 @@ class InlineDiffFormatter extends DiffFormatter {
$xbeg .= "," . $xlen;
if ($ylen != 1)
$ybeg .= "," . $ylen;
- $r = '<tr><td colspan="'.$this->colspan.'" class="diff-blockheader">@@ '.$lang['line']." -$xbeg +$ybeg @@";
- $r .= ' <span class="diff-deletedline"><del>'.$lang['deleted'].'</del></span>';
- $r .= ' <span class="diff-addedline">'.$lang['created'].'</span>';
+ $r = '<tr><td colspan="'.$this->colspan.'" '.HTMLDiff::css('diff-blockheader').'>@@ '.$lang['line']." -$xbeg +$ybeg @@";
+ $r .= ' <span '.HTMLDiff::css('diff-deletedline').'><del>'.$lang['deleted'].'</del></span>';
+ $r .= ' <span '.HTMLDiff::css('diff-addedline').'>'.$lang['created'].'</span>';
$r .= "</td></tr>\n";
return $r;
}
@@ -1134,19 +1167,19 @@ class InlineDiffFormatter extends DiffFormatter {
function _added($lines) {
foreach ($lines as $line) {
- print('<tr><td colspan="'.$this->colspan.'" class="diff-addedline">'. $line . "</td></tr>\n");
+ print('<tr><td colspan="'.$this->colspan.'" '.HTMLDiff::css('diff-addedline').'>'. $line . "</td></tr>\n");
}
}
function _deleted($lines) {
foreach ($lines as $line) {
- print('<tr><td colspan="'.$this->colspan.'" class="diff-deletedline"><del>' . $line . "</del></td></tr>\n");
+ print('<tr><td colspan="'.$this->colspan.'" '.HTMLDiff::css('diff-deletedline').'><del>' . $line . "</del></td></tr>\n");
}
}
function _context($lines) {
foreach ($lines as $line) {
- print('<tr><td colspan="'.$this->colspan.'" class="diff-context">'.$line."</td></tr>\n");
+ print('<tr><td colspan="'.$this->colspan.'" '.HTMLDiff::css('diff-context').'>'.$line."</td></tr>\n");
}
}
diff --git a/inc/Mailer.class.php b/inc/Mailer.class.php
new file mode 100644
index 000000000..507150d00
--- /dev/null
+++ b/inc/Mailer.class.php
@@ -0,0 +1,652 @@
+<?php
+/**
+ * A class to build and send multi part mails (with HTML content and embedded
+ * attachments). All mails are assumed to be in UTF-8 encoding.
+ *
+ * Attachments are handled in memory so this shouldn't be used to send huge
+ * files, but then again mail shouldn't be used to send huge files either.
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+
+// end of line for mail lines - RFC822 says CRLF but postfix (and other MTAs?)
+// think different
+if(!defined('MAILHEADER_EOL')) define('MAILHEADER_EOL',"\n");
+#define('MAILHEADER_ASCIIONLY',1);
+
+class Mailer {
+
+ protected $headers = array();
+ protected $attach = array();
+ protected $html = '';
+ protected $text = '';
+
+ protected $boundary = '';
+ protected $partid = '';
+ protected $sendparam= null;
+
+ protected $validator = null;
+ protected $allowhtml = true;
+
+ /**
+ * Constructor
+ *
+ * Initializes the boundary strings and part counters
+ */
+ public function __construct(){
+ global $conf;
+
+ $server = parse_url(DOKU_URL,PHP_URL_HOST);
+
+ $this->partid = md5(uniqid(rand(),true)).'@'.$server;
+ $this->boundary = '----------'.md5(uniqid(rand(),true));
+
+ $listid = join('.',array_reverse(explode('/',DOKU_BASE))).$server;
+ $listid = strtolower(trim($listid,'.'));
+
+ $this->allowhtml = (bool) $conf['htmlmail'];
+
+ // add some default headers for mailfiltering FS#2247
+ $this->setHeader('X-Mailer','DokuWiki '.getVersion());
+ $this->setHeader('X-DokuWiki-User', $_SERVER['REMOTE_USER']);
+ $this->setHeader('X-DokuWiki-Title', $conf['title']);
+ $this->setHeader('X-DokuWiki-Server', $server);
+ $this->setHeader('X-Auto-Response-Suppress', 'OOF');
+ $this->setHeader('List-Id',$conf['title'].' <'.$listid.'>');
+ }
+
+ /**
+ * Attach a file
+ *
+ * @param $path Path to the file to attach
+ * @param $mime Mimetype of the attached file
+ * @param $name The filename to use
+ * @param $embed Unique key to reference this file from the HTML part
+ */
+ public function attachFile($path,$mime,$name='',$embed=''){
+ if(!$name){
+ $name = basename($path);
+ }
+
+ $this->attach[] = array(
+ 'data' => file_get_contents($path),
+ 'mime' => $mime,
+ 'name' => $name,
+ 'embed' => $embed
+ );
+ }
+
+ /**
+ * Attach a file
+ *
+ * @param $path The file contents to attach
+ * @param $mime Mimetype of the attached file
+ * @param $name The filename to use
+ * @param $embed Unique key to reference this file from the HTML part
+ */
+ public function attachContent($data,$mime,$name='',$embed=''){
+ if(!$name){
+ list($junk,$ext) = split('/',$mime);
+ $name = count($this->attach).".$ext";
+ }
+
+ $this->attach[] = array(
+ 'data' => $data,
+ 'mime' => $mime,
+ 'name' => $name,
+ 'embed' => $embed
+ );
+ }
+
+ /**
+ * Callback function to automatically embed images referenced in HTML templates
+ */
+ protected function autoembed_cb($matches){
+ static $embeds = 0;
+ $embeds++;
+
+ // get file and mime type
+ $media = cleanID($matches[1]);
+ list($ext, $mime) = mimetype($media);
+ $file = mediaFN($media);
+ if(!file_exists($file)) return $matches[0]; //bad reference, keep as is
+
+ // attach it and set placeholder
+ $this->attachFile($file,$mime,'','autoembed'.$embeds);
+ return '%%autoembed'.$embeds.'%%';
+ }
+
+ /**
+ * Add an arbitrary header to the mail
+ *
+ * If an empy value is passed, the header is removed
+ *
+ * @param string $header the header name (no trailing colon!)
+ * @param string $value the value of the header
+ * @param bool $clean remove all non-ASCII chars and line feeds?
+ */
+ public function setHeader($header,$value,$clean=true){
+ $header = str_replace(' ','-',ucwords(strtolower(str_replace('-',' ',$header)))); // streamline casing
+ if($clean){
+ $header = preg_replace('/[^\w \-\.\+\@]+/','',$header);
+ $value = preg_replace('/[^\w \-\.\+\@<>]+/','',$value);
+ }
+
+ // empty value deletes
+ $value = trim($value);
+ if($value === ''){
+ if(isset($this->headers[$header])) unset($this->headers[$header]);
+ }else{
+ $this->headers[$header] = $value;
+ }
+ }
+
+ /**
+ * Set additional parameters to be passed to sendmail
+ *
+ * Whatever is set here is directly passed to PHP's mail() command as last
+ * parameter. Depending on the PHP setup this might break mailing alltogether
+ */
+ public function setParameters($param){
+ $this->sendparam = $param;
+ }
+
+ /**
+ * Set the text and HTML body and apply replacements
+ *
+ * This function applies a whole bunch of default replacements in addition
+ * to the ones specidifed as parameters
+ *
+ * If you pass the HTML part or HTML replacements yourself you have to make
+ * sure you encode all HTML special chars correctly
+ *
+ * @param string $text plain text body
+ * @param array $textrep replacements to apply on the text part
+ * @param array $htmlrep replacements to apply on the HTML part, leave null to use $textrep
+ * @param array $html the HTML body, leave null to create it from $text
+ * @param bool $wrap wrap the HTML in the default header/Footer
+ */
+ public function setBody($text, $textrep=null, $htmlrep=null, $html=null, $wrap=true){
+ global $INFO;
+ global $conf;
+ $htmlrep = (array) $htmlrep;
+ $textrep = (array) $textrep;
+
+ // create HTML from text if not given
+ if(is_null($html)){
+ $html = $text;
+ $html = hsc($html);
+ $html = preg_replace('/^-----*$/m','<hr >',$html);
+ $html = nl2br($html);
+ }
+ if($wrap){
+ $wrap = rawLocale('mailwrap','html');
+ $html = preg_replace('/\n-- <br \/>.*$/s','',$html); //strip signature
+ $html = str_replace('@HTMLBODY@',$html,$wrap);
+ }
+
+ // copy over all replacements missing for HTML (autolink URLs)
+ foreach($textrep as $key => $value){
+ if(isset($htmlrep[$key])) continue;
+ if(preg_match('/^https?:\/\//i',$value)){
+ $htmlrep[$key] = '<a href="'.hsc($value).'">'.hsc($value).'</a>';
+ }else{
+ $htmlrep[$key] = hsc($value);
+ }
+ }
+
+ // embed media from templates
+ $html = preg_replace_callback('/@MEDIA\(([^\)]+)\)@/',
+ array($this,'autoembed_cb'),$html);
+
+ // prepare default replacements
+ $ip = clientIP();
+ $cip = gethostsbyaddrs($ip);
+ $trep = array(
+ 'DATE' => dformat(),
+ 'BROWSER' => $_SERVER['HTTP_USER_AGENT'],
+ 'IPADDRESS' => $ip,
+ 'HOSTNAME' => $cip,
+ 'TITLE' => $conf['title'],
+ 'DOKUWIKIURL' => DOKU_URL,
+ 'USER' => $_SERVER['REMOTE_USER'],
+ 'NAME' => $INFO['userinfo']['name'],
+ 'MAIL' => $INFO['userinfo']['mail'],
+ );
+ $trep = array_merge($trep,(array) $textrep);
+ $hrep = array(
+ 'DATE' => '<i>'.hsc(dformat()).'</i>',
+ 'BROWSER' => hsc($_SERVER['HTTP_USER_AGENT']),
+ 'IPADDRESS' => '<code>'.hsc($ip).'</code>',
+ 'HOSTNAME' => '<code>'.hsc($cip).'</code>',
+ 'TITLE' => hsc($conf['title']),
+ 'DOKUWIKIURL' => '<a href="'.DOKU_URL.'">'.DOKU_URL.'</a>',
+ 'USER' => hsc($_SERVER['REMOTE_USER']),
+ 'NAME' => hsc($INFO['userinfo']['name']),
+ 'MAIL' => '<a href="mailto:"'.hsc($INFO['userinfo']['mail']).'">'.
+ hsc($INFO['userinfo']['mail']).'</a>',
+ );
+ $hrep = array_merge($hrep,(array) $htmlrep);
+
+ // Apply replacements
+ foreach ($trep as $key => $substitution) {
+ $text = str_replace('@'.strtoupper($key).'@',$substitution, $text);
+ }
+ foreach ($hrep as $key => $substitution) {
+ $html = str_replace('@'.strtoupper($key).'@',$substitution, $html);
+ }
+
+ $this->setHTML($html);
+ $this->setText($text);
+ }
+
+ /**
+ * Set the HTML part of the mail
+ *
+ * Placeholders can be used to reference embedded attachments
+ *
+ * You probably want to use setBody() instead
+ */
+ public function setHTML($html){
+ $this->html = $html;
+ }
+
+ /**
+ * Set the plain text part of the mail
+ *
+ * You probably want to use setBody() instead
+ */
+ public function setText($text){
+ $this->text = $text;
+ }
+
+ /**
+ * Add the To: recipients
+ *
+ * @see setAddress
+ * @param string $address Multiple adresses separated by commas
+ */
+ public function to($address){
+ $this->setHeader('To', $address, false);
+ }
+
+ /**
+ * Add the Cc: recipients
+ *
+ * @see setAddress
+ * @param string $address Multiple adresses separated by commas
+ */
+ public function cc($address){
+ $this->setHeader('Cc', $address, false);
+ }
+
+ /**
+ * Add the Bcc: recipients
+ *
+ * @see setAddress
+ * @param string $address Multiple adresses separated by commas
+ */
+ public function bcc($address){
+ $this->setHeader('Bcc', $address, false);
+ }
+
+ /**
+ * Add the From: address
+ *
+ * This is set to $conf['mailfrom'] when not specified so you shouldn't need
+ * to call this function
+ *
+ * @see setAddress
+ * @param string $address from address
+ */
+ public function from($address){
+ $this->setHeader('From', $address, false);
+ }
+
+ /**
+ * Add the mail's Subject: header
+ *
+ * @param string $subject the mail subject
+ */
+ public function subject($subject){
+ $this->headers['Subject'] = $subject;
+ }
+
+ /**
+ * Sets an email address header with correct encoding
+ *
+ * Unicode characters will be deaccented and encoded base64
+ * for headers. Addresses may not contain Non-ASCII data!
+ *
+ * Example:
+ * setAddress("föö <foo@bar.com>, me@somewhere.com","TBcc");
+ *
+ * @param string $address Multiple adresses separated by commas
+ * @param string returns the prepared header (can contain multiple lines)
+ */
+ public function cleanAddress($address){
+ // No named recipients for To: in Windows (see FS#652)
+ $names = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') ? false : true;
+
+ $address = preg_replace('/[\r\n\0]+/',' ',$address); // remove attack vectors
+
+ $headers = '';
+ $parts = explode(',',$address);
+ foreach ($parts as $part){
+ $part = trim($part);
+
+ // parse address
+ if(preg_match('#(.*?)<(.*?)>#',$part,$matches)){
+ $text = trim($matches[1]);
+ $addr = $matches[2];
+ }else{
+ $addr = $part;
+ }
+ // skip empty ones
+ if(empty($addr)){
+ continue;
+ }
+
+ // FIXME: is there a way to encode the localpart of a emailaddress?
+ if(!utf8_isASCII($addr)){
+ msg(htmlspecialchars("E-Mail address <$addr> is not ASCII"),-1);
+ continue;
+ }
+
+ if(is_null($this->validator)){
+ $this->validator = new EmailAddressValidator();
+ $this->validator->allowLocalAddresses = true;
+ }
+ if(!$this->validator->check_email_address($addr)){
+ msg(htmlspecialchars("E-Mail address <$addr> is not valid"),-1);
+ continue;
+ }
+
+ // text was given
+ if(!empty($text) && $names){
+ // add address quotes
+ $addr = "<$addr>";
+
+ if(defined('MAILHEADER_ASCIIONLY')){
+ $text = utf8_deaccent($text);
+ $text = utf8_strip($text);
+ }
+
+ if(!utf8_isASCII($text)){
+ $text = '=?UTF-8?B?'.base64_encode($text).'?=';
+ }
+ }else{
+ $text = '';
+ }
+
+ // add to header comma seperated
+ if($headers != ''){
+ $headers .= ', ';
+ }
+ $headers .= $text.' '.$addr;
+ }
+
+ if(empty($headers)) return false;
+
+ return $headers;
+ }
+
+
+ /**
+ * Prepare the mime multiparts for all attachments
+ *
+ * Replaces placeholders in the HTML with the correct CIDs
+ */
+ protected function prepareAttachments(){
+ $mime = '';
+ $part = 1;
+ // embedded attachments
+ foreach($this->attach as $media){
+ // create content id
+ $cid = 'part'.$part.'.'.$this->partid;
+
+ // replace wildcards
+ if($media['embed']){
+ $this->html = str_replace('%%'.$media['embed'].'%%','cid:'.$cid,$this->html);
+ }
+
+ $mime .= '--'.$this->boundary.MAILHEADER_EOL;
+ $mime .= 'Content-Type: '.$media['mime'].';'.MAILHEADER_EOL;
+ $mime .= 'Content-Transfer-Encoding: base64'.MAILHEADER_EOL;
+ $mime .= "Content-ID: <$cid>".MAILHEADER_EOL;
+ if($media['embed']){
+ $mime .= 'Content-Disposition: inline; filename="'.$media['name'].'"'.MAILHEADER_EOL;
+ }else{
+ $mime .= 'Content-Disposition: attachment; filename="'.$media['name'].'"'.MAILHEADER_EOL;
+ }
+ $mime .= MAILHEADER_EOL; //end of headers
+ $mime .= chunk_split(base64_encode($media['data']),74,MAILHEADER_EOL);
+
+ $part++;
+ }
+ return $mime;
+ }
+
+ /**
+ * Build the body and handles multi part mails
+ *
+ * Needs to be called before prepareHeaders!
+ *
+ * @return string the prepared mail body, false on errors
+ */
+ protected function prepareBody(){
+ global $conf;
+
+ // no HTML mails allowed? remove HTML body
+ if(!$this->allowhtml){
+ $this->html = '';
+ }
+
+ // check for body
+ if(!$this->text && !$this->html){
+ return false;
+ }
+
+ // add general headers
+ $this->headers['MIME-Version'] = '1.0';
+
+ $body = '';
+
+ if(!$this->html && !count($this->attach)){ // we can send a simple single part message
+ $this->headers['Content-Type'] = 'text/plain; charset=UTF-8';
+ $this->headers['Content-Transfer-Encoding'] = 'base64';
+ $body .= chunk_split(base64_encode($this->text),74,MAILHEADER_EOL);
+ }else{ // multi part it is
+ $body .= "This is a multi-part message in MIME format.".MAILHEADER_EOL;
+
+ // prepare the attachments
+ $attachments = $this->prepareAttachments();
+
+ // do we have alternative text content?
+ if($this->text && $this->html){
+ $this->headers['Content-Type'] = 'multipart/alternative;'.MAILHEADER_EOL.
+ ' boundary="'.$this->boundary.'XX"';
+ $body .= '--'.$this->boundary.'XX'.MAILHEADER_EOL;
+ $body .= 'Content-Type: text/plain; charset=UTF-8'.MAILHEADER_EOL;
+ $body .= 'Content-Transfer-Encoding: base64'.MAILHEADER_EOL;
+ $body .= MAILHEADER_EOL;
+ $body .= chunk_split(base64_encode($this->text),74,MAILHEADER_EOL);
+ $body .= '--'.$this->boundary.'XX'.MAILHEADER_EOL;
+ $body .= 'Content-Type: multipart/related;'.MAILHEADER_EOL.
+ ' boundary="'.$this->boundary.'"'.MAILHEADER_EOL;
+ $body .= MAILHEADER_EOL;
+ }
+
+ $body .= '--'.$this->boundary.MAILHEADER_EOL;
+ $body .= 'Content-Type: text/html; charset=UTF-8'.MAILHEADER_EOL;
+ $body .= 'Content-Transfer-Encoding: base64'.MAILHEADER_EOL;
+ $body .= MAILHEADER_EOL;
+ $body .= chunk_split(base64_encode($this->html),74,MAILHEADER_EOL);
+ $body .= MAILHEADER_EOL;
+ $body .= $attachments;
+ $body .= '--'.$this->boundary.'--'.MAILHEADER_EOL;
+
+ // close open multipart/alternative boundary
+ if($this->text && $this->html){
+ $body .= '--'.$this->boundary.'XX--'.MAILHEADER_EOL;
+ }
+ }
+
+ return $body;
+ }
+
+ /**
+ * Cleanup and encode the headers array
+ */
+ protected function cleanHeaders(){
+ global $conf;
+
+ // clean up addresses
+ if(empty($this->headers['From'])) $this->from($conf['mailfrom']);
+ $addrs = array('To','From','Cc','Bcc');
+ foreach($addrs as $addr){
+ if(isset($this->headers[$addr])){
+ $this->headers[$addr] = $this->cleanAddress($this->headers[$addr]);
+ }
+ }
+
+ if(isset($this->headers['Subject'])){
+ // add prefix to subject
+ if(empty($conf['mailprefix'])){
+ if(utf8_strlen($conf['title']) < 20) {
+ $prefix = '['.$conf['title'].']';
+ }else{
+ $prefix = '['.utf8_substr($conf['title'], 0, 20).'...]';
+ }
+ }else{
+ $prefix = '['.$conf['mailprefix'].']';
+ }
+ $len = strlen($prefix);
+ if(substr($this->headers['Subject'],0,$len) != $prefix){
+ $this->headers['Subject'] = $prefix.' '.$this->headers['Subject'];
+ }
+
+ // encode subject
+ if(defined('MAILHEADER_ASCIIONLY')){
+ $this->headers['Subject'] = utf8_deaccent($this->headers['Subject']);
+ $this->headers['Subject'] = utf8_strip($this->headers['Subject']);
+ }
+ if(!utf8_isASCII($this->headers['Subject'])){
+ $this->headers['Subject'] = '=?UTF-8?B?'.base64_encode($this->headers['Subject']).'?=';
+ }
+ }
+
+ // wrap headers
+ foreach($this->headers as $key => $val){
+ $this->headers[$key] = wordwrap($val,78,MAILHEADER_EOL.' ');
+ }
+ }
+
+ /**
+ * Create a string from the headers array
+ *
+ * @returns string the headers
+ */
+ protected function prepareHeaders(){
+ $headers = '';
+ foreach($this->headers as $key => $val){
+ $headers .= "$key: $val".MAILHEADER_EOL;
+ }
+ return $headers;
+ }
+
+ /**
+ * return a full email with all headers
+ *
+ * This is mainly intended for debugging and testing but could also be
+ * used for MHT exports
+ *
+ * @return string the mail, false on errors
+ */
+ public function dump(){
+ $this->cleanHeaders();
+ $body = $this->prepareBody();
+ if($body === 'false') return false;
+ $headers = $this->prepareHeaders();
+
+ return $headers.MAILHEADER_EOL.$body;
+ }
+
+ /**
+ * Send the mail
+ *
+ * Call this after all data was set
+ *
+ * @triggers MAIL_MESSAGE_SEND
+ * @return bool true if the mail was successfully passed to the MTA
+ */
+ public function send(){
+ $success = false;
+
+ // prepare hook data
+ $data = array(
+ // pass the whole mail class to plugin
+ 'mail' => $this,
+ // pass references for backward compatibility
+ 'to' => &$this->headers['To'],
+ 'cc' => &$this->headers['Cc'],
+ 'bcc' => &$this->headers['Bcc'],
+ 'from' => &$this->headers['From'],
+ 'subject' => &$this->headers['Subject'],
+ 'body' => &$this->text,
+ 'params' => &$this->sendparams,
+ 'headers' => '', // plugins shouldn't use this
+ // signal if we mailed successfully to AFTER event
+ 'success' => &$success,
+ );
+
+ // do our thing if BEFORE hook approves
+ $evt = new Doku_Event('MAIL_MESSAGE_SEND', $data);
+ if ($evt->advise_before(true)) {
+ // clean up before using the headers
+ $this->cleanHeaders();
+
+ // any recipients?
+ if(trim($this->headers['To']) === '' &&
+ trim($this->headers['Cc']) === '' &&
+ trim($this->headers['Bcc']) === '') return false;
+
+ // The To: header is special
+ if(isset($this->headers['To'])){
+ $to = $this->headers['To'];
+ unset($this->headers['To']);
+ }else{
+ $to = '';
+ }
+
+ // so is the subject
+ if(isset($this->headers['Subject'])){
+ $subject = $this->headers['Subject'];
+ unset($this->headers['Subject']);
+ }else{
+ $subject = '';
+ }
+
+ // make the body
+ $body = $this->prepareBody();
+ if($body === 'false') return false;
+
+ // cook the headers
+ $headers = $this->prepareHeaders();
+ // add any headers set by legacy plugins
+ if(trim($data['headers'])){
+ $headers .= MAILHEADER_EOL.trim($data['headers']);
+ }
+
+ // send the thing
+ if(is_null($this->sendparam)){
+ $success = @mail($to,$subject,$body,$headers);
+ }else{
+ $success = @mail($to,$subject,$body,$headers,$this->sendparam);
+ }
+ }
+ // any AFTER actions?
+ $evt->advise_after();
+ return $success;
+ }
+}
diff --git a/inc/RemoteAPICore.php b/inc/RemoteAPICore.php
index 9da493210..36c518881 100644
--- a/inc/RemoteAPICore.php
+++ b/inc/RemoteAPICore.php
@@ -169,7 +169,7 @@ class RemoteAPICore {
* @return page text.
*/
function rawPage($id,$rev=''){
- $id = cleanID($id);
+ $id = $this->resolvePageId($id);
if(auth_quickaclcheck($id) < AUTH_READ){
throw new RemoteAccessDeniedException('You are not allowed to read this file', 111);
}
@@ -228,7 +228,7 @@ class RemoteAPICore {
* Return a wiki page rendered to html
*/
function htmlPage($id,$rev=''){
- $id = cleanID($id);
+ $id = $this->resolvePageId($id);
if(auth_quickaclcheck($id) < AUTH_READ){
throw new RemoteAccessDeniedException('You are not allowed to read this page', 111);
}
@@ -356,14 +356,14 @@ class RemoteAPICore {
* Return a list of backlinks
*/
function listBackLinks($id){
- return ft_backlinks(cleanID($id));
+ return ft_backlinks($this->resolvePageId($id));
}
/**
* Return some basic data about a page
*/
function pageInfo($id,$rev=''){
- $id = cleanID($id);
+ $id = $this->resolvePageId($id);
if(auth_quickaclcheck($id) < AUTH_READ){
throw new RemoteAccessDeniedException('You are not allowed to read this page', 111);
}
@@ -394,7 +394,7 @@ class RemoteAPICore {
global $TEXT;
global $lang;
- $id = cleanID($id);
+ $id = $this->resolvePageId($id);
$TEXT = cleanText($text);
$sum = $params['sum'];
$minor = $params['minor'];
@@ -507,7 +507,7 @@ class RemoteAPICore {
* Returns the permissions of a given wiki page
*/
function aclCheck($id) {
- $id = cleanID($id);
+ $id = $this->resolvePageId($id);
return auth_quickaclcheck($id);
}
@@ -517,7 +517,7 @@ class RemoteAPICore {
* @author Michael Klier <chi@chimeric.de>
*/
function listLinks($id) {
- $id = cleanID($id);
+ $id = $this->resolvePageId($id);
if(auth_quickaclcheck($id) < AUTH_READ){
throw new RemoteAccessDeniedException('You are not allowed to read this page', 111);
}
@@ -633,7 +633,7 @@ class RemoteAPICore {
* @author Michael Klier <chi@chimeric.de>
*/
function pageVersions($id, $first) {
- $id = cleanID($id);
+ $id = $this->resolvePageId($id);
if(auth_quickaclcheck($id) < AUTH_READ) {
throw new RemoteAccessDeniedException('You are not allowed to read this page', 111);
}
@@ -711,7 +711,7 @@ class RemoteAPICore {
$unlockfail = array();
foreach((array) $set['lock'] as $id){
- $id = cleanID($id);
+ $id = $this->resolvePageId($id);
if(auth_quickaclcheck($id) < AUTH_EDIT || checklock($id)){
$lockfail[] = $id;
}else{
@@ -721,7 +721,7 @@ class RemoteAPICore {
}
foreach((array) $set['unlock'] as $id){
- $id = cleanID($id);
+ $id = $this->resolvePageId($id);
if(auth_quickaclcheck($id) < AUTH_EDIT || !unlock($id)){
$unlockfail[] = $id;
}else{
@@ -764,6 +764,14 @@ class RemoteAPICore {
return $ok;
}
+ private function resolvePageId($id) {
+ $id = cleanID($id);
+ if(empty($id)) {
+ global $conf;
+ $id = cleanID($conf['start']);
+ }
+ return $id;
+ }
}
diff --git a/inc/auth.php b/inc/auth.php
index 59ef1cb54..ed0e2dcf7 100644
--- a/inc/auth.php
+++ b/inc/auth.php
@@ -669,22 +669,17 @@ function auth_sendPassword($user,$password){
if(!$userinfo['mail']) return false;
$text = rawLocale('password');
- $text = str_replace('@DOKUWIKIURL@',DOKU_URL,$text);
- $text = str_replace('@FULLNAME@',$userinfo['name'],$text);
- $text = str_replace('@LOGIN@',$user,$text);
- $text = str_replace('@PASSWORD@',$password,$text);
- $text = str_replace('@TITLE@',$conf['title'],$text);
-
- if(empty($conf['mailprefix'])) {
- $subject = $lang['regpwmail'];
- } else {
- $subject = '['.$conf['mailprefix'].'] '.$lang['regpwmail'];
- }
+ $trep = array(
+ 'FULLNAME' => $userinfo['name'],
+ 'LOGIN' => $user,
+ 'PASSWORD' => $password
+ );
- return mail_send($userinfo['name'].' <'.$userinfo['mail'].'>',
- $subject,
- $text,
- $conf['mailfrom']);
+ $mail = new Mailer();
+ $mail->to($userinfo['name'].' <'.$userinfo['mail'].'>');
+ $mail->subject($lang['regpwmail']);
+ $mail->setBody($text,$trep);
+ return $mail->send();
}
/**
@@ -941,22 +936,17 @@ function act_resendpwd(){
io_saveFile($tfile,$user);
$text = rawLocale('pwconfirm');
- $text = str_replace('@DOKUWIKIURL@',DOKU_URL,$text);
- $text = str_replace('@FULLNAME@',$userinfo['name'],$text);
- $text = str_replace('@LOGIN@',$user,$text);
- $text = str_replace('@TITLE@',$conf['title'],$text);
- $text = str_replace('@CONFIRM@',$url,$text);
-
- if(empty($conf['mailprefix'])) {
- $subject = $lang['regpwmail'];
- } else {
- $subject = '['.$conf['mailprefix'].'] '.$lang['regpwmail'];
- }
+ $trep = array(
+ 'FULLNAME' => $userinfo['name'],
+ 'LOGIN' => $user,
+ 'CONFIRM' => $url
+ );
- if(mail_send($userinfo['name'].' <'.$userinfo['mail'].'>',
- $subject,
- $text,
- $conf['mailfrom'])){
+ $mail = new Mailer();
+ $mail->to($userinfo['name'].' <'.$userinfo['mail'].'>');
+ $mail->subject($lang['regpwmail']);
+ $mail->setBody($text,$trep);
+ if($mail->send()){
msg($lang['resendpwdconfirm'],1);
}else{
msg($lang['regmailfail'],-1);
diff --git a/inc/common.php b/inc/common.php
index 0a75f2eab..22a315901 100644
--- a/inc/common.php
+++ b/inc/common.php
@@ -789,8 +789,8 @@ function formText($text){
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
-function rawLocale($id){
- return io_readFile(localeFN($id));
+function rawLocale($id,$ext='txt'){
+ return io_readFile(localeFN($id,$ext));
}
/**
@@ -1086,8 +1086,9 @@ function notify($id,$who,$rev='',$summary='',$minor=false,$replace=array()){
global $lang;
global $conf;
global $INFO;
+ global $DIFF_INLINESTYLES;
- // decide if there is something to do
+ // decide if there is something to do, eg. whom to mail
if($who == 'admin'){
if(empty($conf['notify'])) return; //notify enabled?
$text = rawLocale('mailtext');
@@ -1112,49 +1113,54 @@ function notify($id,$who,$rev='',$summary='',$minor=false,$replace=array()){
return; //just to be safe
}
- $ip = clientIP();
- $text = str_replace('@DATE@',dformat(),$text);
- $text = str_replace('@BROWSER@',$_SERVER['HTTP_USER_AGENT'],$text);
- $text = str_replace('@IPADDRESS@',$ip,$text);
- $text = str_replace('@HOSTNAME@',gethostsbyaddrs($ip),$text);
- $text = str_replace('@NEWPAGE@',wl($id,'',true,'&'),$text);
- $text = str_replace('@PAGE@',$id,$text);
- $text = str_replace('@TITLE@',$conf['title'],$text);
- $text = str_replace('@DOKUWIKIURL@',DOKU_URL,$text);
- $text = str_replace('@SUMMARY@',$summary,$text);
- $text = str_replace('@USER@',$_SERVER['REMOTE_USER'],$text);
- $text = str_replace('@NAME@',$INFO['userinfo']['name'],$text);
- $text = str_replace('@MAIL@',$INFO['userinfo']['mail'],$text);
-
- foreach ($replace as $key => $substitution) {
- $text = str_replace('@'.strtoupper($key).'@',$substitution, $text);
- }
+ // prepare replacements (keys not set in hrep will be taken from trep)
+ $trep = array(
+ 'NEWPAGE' => wl($id,'',true,'&'),
+ 'PAGE' => $id,
+ 'SUMMARY' => $summary
+ );
+ $trep = array_merge($trep,$replace);
+ $hrep = array();
+ // prepare content
if($who == 'register'){
- $subject = $lang['mail_new_user'].' '.$summary;
+ $subject = $lang['mail_new_user'].' '.$summary;
}elseif($rev){
- $subject = $lang['mail_changed'].' '.$id;
- $text = str_replace('@OLDPAGE@',wl($id,"rev=$rev",true,'&'),$text);
- $df = new Diff(explode("\n",rawWiki($id,$rev)),
- explode("\n",rawWiki($id)));
- $dformat = new UnifiedDiffFormatter();
- $diff = $dformat->format($df);
+ $subject = $lang['mail_changed'].' '.$id;
+ $trep['OLDPAGE'] = wl($id,"rev=$rev",true,'&');
+ $df = new Diff(explode("\n",rawWiki($id,$rev)),
+ explode("\n",rawWiki($id)));
+ $dformat = new UnifiedDiffFormatter();
+ $tdiff = $dformat->format($df);
+
+ $DIFF_INLINESTYLES = true;
+ $dformat = new InlineDiffFormatter();
+ $hdiff = $dformat->format($df);
+ $hdiff = '<table>'.$hdiff.'</table>';
+ $DIFF_INLINESTYLES = false;
}else{
- $subject=$lang['mail_newpage'].' '.$id;
- $text = str_replace('@OLDPAGE@','none',$text);
- $diff = rawWiki($id);
- }
- $text = str_replace('@DIFF@',$diff,$text);
- if(empty($conf['mailprefix'])) {
- if(utf8_strlen($conf['title']) < 20) {
- $subject = '['.$conf['title'].'] '.$subject;
- }else{
- $subject = '['.utf8_substr($conf['title'], 0, 20).'...] '.$subject;
- }
- }else{
- $subject = '['.$conf['mailprefix'].'] '.$subject;
- }
- mail_send($to,$subject,$text,$conf['mailfrom'],'',$bcc);
+ $subject = $lang['mail_newpage'].' '.$id;
+ $trep['OLDPAGE'] = '---';
+ $tdiff = rawWiki($id);
+ $hdiff = nl2br(hsc($tdiff));
+ }
+ $trep['DIFF'] = $tdiff;
+ $hrep['DIFF'] = $hdiff;
+
+ // send mail
+ $mail = new Mailer();
+ $mail->to($to);
+ $mail->bcc($bcc);
+ $mail->subject($subject);
+ $mail->setBody($text,$trep,$hrep);
+ if($who == 'subscribers'){
+ $mail->setHeader(
+ 'List-Unsubscribe',
+ '<'.wl($id,array('do'=>'subscribe'),true,'&').'>',
+ false
+ );
+ }
+ return $mail->send();
}
/**
diff --git a/inc/fulltext.php b/inc/fulltext.php
index 620237296..8f4db111d 100644
--- a/inc/fulltext.php
+++ b/inc/fulltext.php
@@ -405,6 +405,8 @@ function ft_snippet_re_preprocess($term) {
}else{
$term = $term.'\b';
}
+
+ if($term == '\b' || $term == '\b\b') $term = '';
return $term;
}
diff --git a/inc/html.php b/inc/html.php
index 022cd792a..be5666353 100644
--- a/inc/html.php
+++ b/inc/html.php
@@ -280,8 +280,11 @@ function html_draft(){
* @author Harry Fuecks <hfuecks@gmail.com>
*/
function html_hilight($html,$phrases){
- $phrases = array_filter((array) $phrases);
- $regex = join('|',array_map('ft_snippet_re_preprocess', array_map('preg_quote_cb',$phrases)));
+ $phrases = (array) $phrases;
+ $phrases = array_map('preg_quote_cb', $phrases);
+ $phrases = array_map('ft_snippet_re_preprocess', $phrases);
+ $phrases = array_filter($phrases);
+ $regex = join('|',$phrases);
if ($regex === '') return $html;
if (!utf8_check($regex)) return $html;
diff --git a/inc/lang/en/mailwrap.html b/inc/lang/en/mailwrap.html
new file mode 100644
index 000000000..f9f80fd80
--- /dev/null
+++ b/inc/lang/en/mailwrap.html
@@ -0,0 +1,13 @@
+<html>
+<head>
+ <title>@TITLE@</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+</head>
+<body>
+
+@HTMLBODY@
+
+<br /><hr />
+<small>This mail was generated by DokuWiki at @DOKUWIKIURL@.</small>
+</body>
+</html>
diff --git a/inc/lang/en/subscr_digest.txt b/inc/lang/en/subscr_digest.txt
index fac8564bd..35011b6e6 100644
--- a/inc/lang/en/subscr_digest.txt
+++ b/inc/lang/en/subscr_digest.txt
@@ -15,6 +15,6 @@ To cancel the page notifications, log into the wiki at
@SUBSCRIBE@
and unsubscribe page and/or namespace changes.
---
+--
This mail was generated by DokuWiki at
@DOKUWIKIURL@
diff --git a/inc/lang/en/subscr_list.txt b/inc/lang/en/subscr_list.txt
index efe27d866..4c38b9326 100644
--- a/inc/lang/en/subscr_list.txt
+++ b/inc/lang/en/subscr_list.txt
@@ -12,6 +12,6 @@ To cancel the page notifications, log into the wiki at
@SUBSCRIBE@
and unsubscribe page and/or namespace changes.
---
+--
This mail was generated by DokuWiki at
@DOKUWIKIURL@
diff --git a/inc/lang/en/subscr_single.txt b/inc/lang/en/subscr_single.txt
index f2abe6d77..673c4c32a 100644
--- a/inc/lang/en/subscr_single.txt
+++ b/inc/lang/en/subscr_single.txt
@@ -18,6 +18,6 @@ To cancel the page notifications, log into the wiki at
@NEWPAGE@
and unsubscribe page and/or namespace changes.
---
+--
This mail was generated by DokuWiki at
@DOKUWIKIURL@
diff --git a/inc/load.php b/inc/load.php
index f3ab5bcdd..0572b5760 100644
--- a/inc/load.php
+++ b/inc/load.php
@@ -76,8 +76,9 @@ function load_autoload($name){
'SafeFN' => DOKU_INC.'inc/SafeFN.class.php',
'Sitemapper' => DOKU_INC.'inc/Sitemapper.php',
'PassHash' => DOKU_INC.'inc/PassHash.class.php',
+ 'Mailer' => DOKU_INC.'inc/Mailer.class.php',
'RemoteAPI' => DOKU_INC.'inc/remote.php',
- 'RemoteAPICore' => DOKU_INC.'inc/RemoteAPICore.php',
+ 'RemoteAPICore' => DOKU_INC.'inc/RemoteAPICore.php',
'DokuWiki_Action_Plugin' => DOKU_PLUGIN.'action.php',
'DokuWiki_Admin_Plugin' => DOKU_PLUGIN.'admin.php',
diff --git a/inc/media.php b/inc/media.php
index dd0193fa0..66984e957 100644
--- a/inc/media.php
+++ b/inc/media.php
@@ -516,6 +516,7 @@ function media_contentcheck($file,$mime){
* Send a notify mail on uploads
*
* @author Andreas Gohr <andi@splitbrain.org>
+ * @fixme this should embed thumbnails of images in HTML version
*/
function media_notify($id,$file,$mime,$old_rev=false){
global $lang;
@@ -523,31 +524,24 @@ function media_notify($id,$file,$mime,$old_rev=false){
global $INFO;
if(empty($conf['notify'])) return; //notify enabled?
- $ip = clientIP();
-
$text = rawLocale('uploadmail');
- $text = str_replace('@DATE@',dformat(),$text);
- $text = str_replace('@BROWSER@',$_SERVER['HTTP_USER_AGENT'],$text);
- $text = str_replace('@IPADDRESS@',$ip,$text);
- $text = str_replace('@HOSTNAME@',gethostsbyaddrs($ip),$text);
- $text = str_replace('@DOKUWIKIURL@',DOKU_URL,$text);
- $text = str_replace('@USER@',$_SERVER['REMOTE_USER'],$text);
- $text = str_replace('@MIME@',$mime,$text);
- $text = str_replace('@MEDIA@',ml($id,'',true,'&',true),$text);
- $text = str_replace('@SIZE@',filesize_h(filesize($file)),$text);
- if ($old_rev && $conf['mediarevisions']) {
- $text = str_replace('@OLD@', ml($id, "rev=$old_rev", true, '&', true), $text);
- } else {
- $text = str_replace('@OLD@', '', $text);
- }
+ $trep = array(
+ 'MIME' => $mime,
+ 'MEDIA' => ml($id,'',true,'&',true),
+ 'SIZE' => filesize_h(filesize($file)),
+ );
- if(empty($conf['mailprefix'])) {
- $subject = '['.$conf['title'].'] '.$lang['mail_upload'].' '.$id;
+ if ($old_rev && $conf['mediarevisions']) {
+ $trep['OLD'] = ml($id, "rev=$old_rev", true, '&', true);
} else {
- $subject = '['.$conf['mailprefix'].'] '.$lang['mail_upload'].' '.$id;
+ $trep['OLD'] = '---';
}
- mail_send($conf['notify'],$subject,$text,$conf['mailfrom']);
+ $mail = new Mailer();
+ $mail->to($conf['notify']);
+ $mail->subject($lang['mail_upload'].' '.$id);
+ $mail->setBody($text,$trep);
+ return $mail->send();
}
/**
diff --git a/inc/pageutils.php b/inc/pageutils.php
index db00258e2..c94d14624 100644
--- a/inc/pageutils.php
+++ b/inc/pageutils.php
@@ -355,19 +355,21 @@ function mediaFN($id, $rev=''){
}
/**
- * Returns the full filepath to a localized textfile if local
+ * Returns the full filepath to a localized file if local
* version isn't found the english one is returned
*
+ * @param string $id The id of the local file
+ * @param string $ext The file extension (usually txt)
* @author Andreas Gohr <andi@splitbrain.org>
*/
-function localeFN($id){
+function localeFN($id,$ext='txt'){
global $conf;
- $file = DOKU_CONF.'/lang/'.$conf['lang'].'/'.$id.'.txt';
+ $file = DOKU_CONF.'/lang/'.$conf['lang'].'/'.$id.'.'.$ext;
if(!@file_exists($file)){
- $file = DOKU_INC.'inc/lang/'.$conf['lang'].'/'.$id.'.txt';
+ $file = DOKU_INC.'inc/lang/'.$conf['lang'].'/'.$id.'.'.$ext;
if(!@file_exists($file)){
//fall back to english
- $file = DOKU_INC.'inc/lang/en/'.$id.'.txt';
+ $file = DOKU_INC.'inc/lang/en/'.$id.'.'.$ext;
}
}
return $file;
diff --git a/inc/subscription.php b/inc/subscription.php
index c94f17ad0..d1ee0397a 100644
--- a/inc/subscription.php
+++ b/inc/subscription.php
@@ -377,18 +377,20 @@ function subscription_send_list($subscriber_mail, $ids, $ns_id) {
*/
function subscription_send($subscriber_mail, $replaces, $subject, $id, $template) {
global $conf;
+ global $lang;
$text = rawLocale($template);
- $replaces = array_merge($replaces, array('TITLE' => $conf['title'],
- 'DOKUWIKIURL' => DOKU_URL,
- 'PAGE' => $id));
-
- foreach ($replaces as $key => $substitution) {
- $text = str_replace('@'.strtoupper($key).'@', $substitution, $text);
- }
+ $trep = array_merge($replaces, array('PAGE' => $id));
- global $lang;
$subject = $lang['mail_' . $subject] . ' ' . $id;
- mail_send('', '['.$conf['title'].'] '. $subject, $text,
- $conf['mailfrom'], '', $subscriber_mail);
+ $mail = new Mailer();
+ $mail->bcc($subscriber_mail);
+ $mail->subject($subject);
+ $mail->setBody($text,$trep);
+ $mail->setHeader(
+ 'List-Unsubscribe',
+ '<'.wl($id,array('do'=>'subscribe'),true,'&').'>',
+ false
+ );
+ return $mail->send();
}
diff --git a/lib/exe/xmlrpc.php b/lib/exe/xmlrpc.php
index cf3682f11..5e6c197d0 100644
--- a/lib/exe/xmlrpc.php
+++ b/lib/exe/xmlrpc.php
@@ -30,10 +30,11 @@ class dokuwiki_xmlrpc_server extends IXR_Server {
} catch (RemoteAccessDeniedException $e) {
if (!isset($_SERVER['REMOTE_USER'])) {
header('HTTP/1.1 401 Unauthorized');
+ return new IXR_Error(-32603, "server error. not authorized to call method $methodname");
} else {
header('HTTP/1.1 403 Forbidden');
+ return new IXR_Error(-32604, "server error. forbidden to call the method $methodname");
}
- return new IXR_Error(-32603, "server error. not authorized to call method $methodname");
} catch (RemoteException $e) {
return new IXR_Error($e->getCode(), $e->getMessage());
}
diff --git a/lib/plugins/config/lang/en/lang.php b/lib/plugins/config/lang/en/lang.php
index 42f34de74..d588e02f8 100644
--- a/lib/plugins/config/lang/en/lang.php
+++ b/lib/plugins/config/lang/en/lang.php
@@ -147,6 +147,7 @@ $lang['notify'] = 'Always send change notifications to this email address';
$lang['registernotify'] = 'Always send info on newly registered users to this email address';
$lang['mailfrom'] = 'Sender email address to use for automatic mails';
$lang['mailprefix'] = 'Email subject prefix to use for automatic mails. Leave blank to use the wiki title';
+$lang['htmlmail'] = 'Send better looking, but larger in size HTML multipart emails. Disable for plain text only mails.';
/* Syndication Settings */
$lang['sitemap'] = 'Generate Google sitemap this often (in days). 0 to disable';
diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php
index e610ac4d4..997495b2e 100644
--- a/lib/plugins/config/settings/config.metadata.php
+++ b/lib/plugins/config/settings/config.metadata.php
@@ -177,6 +177,7 @@ $meta['notify'] = array('email', '_multiple' => true);
$meta['registernotify'] = array('email');
$meta['mailfrom'] = array('richemail');
$meta['mailprefix'] = array('string');
+$meta['htmlmail'] = array('onoff');
$meta['_syndication'] = array('fieldset');
$meta['sitemap'] = array('numeric');