694 lines
23 KiB
PHP
694 lines
23 KiB
PHP
|
<?php
|
|||
|
/**
|
|||
|
* Class for handling (email) subscriptions
|
|||
|
*
|
|||
|
* @author Adrian Lang <lang@cosmocode.de>
|
|||
|
* @author Andreas Gohr <andi@splitbrain.org>
|
|||
|
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
|
|||
|
*/
|
|||
|
class Subscription {
|
|||
|
|
|||
|
/**
|
|||
|
* Check if subscription system is enabled
|
|||
|
*
|
|||
|
* @return bool
|
|||
|
*/
|
|||
|
public function isenabled() {
|
|||
|
return actionOK('subscribe');
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Return the subscription meta file for the given ID
|
|||
|
*
|
|||
|
* @author Adrian Lang <lang@cosmocode.de>
|
|||
|
*
|
|||
|
* @param string $id The target page or namespace, specified by id; Namespaces
|
|||
|
* are identified by appending a colon.
|
|||
|
* @return string
|
|||
|
*/
|
|||
|
protected function file($id) {
|
|||
|
$meta_fname = '.mlist';
|
|||
|
if((substr($id, -1, 1) === ':')) {
|
|||
|
$meta_froot = getNS($id);
|
|||
|
$meta_fname = '/'.$meta_fname;
|
|||
|
} else {
|
|||
|
$meta_froot = $id;
|
|||
|
}
|
|||
|
return metaFN((string) $meta_froot, $meta_fname);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Lock subscription info
|
|||
|
*
|
|||
|
* We don't use io_lock() her because we do not wait for the lock and use a larger stale time
|
|||
|
*
|
|||
|
* @author Adrian Lang <lang@cosmocode.de>
|
|||
|
* @param string $id The target page or namespace, specified by id; Namespaces
|
|||
|
* are identified by appending a colon.
|
|||
|
* @return bool true, if you got a succesful lock
|
|||
|
*/
|
|||
|
protected function lock($id) {
|
|||
|
global $conf;
|
|||
|
|
|||
|
$lock = $conf['lockdir'].'/_subscr_'.md5($id).'.lock';
|
|||
|
|
|||
|
if(is_dir($lock) && time() - @filemtime($lock) > 60 * 5) {
|
|||
|
// looks like a stale lock - remove it
|
|||
|
@rmdir($lock);
|
|||
|
}
|
|||
|
|
|||
|
// try creating the lock directory
|
|||
|
if(!@mkdir($lock, $conf['dmode'])) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
if(!empty($conf['dperm'])) chmod($lock, $conf['dperm']);
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Unlock subscription info
|
|||
|
*
|
|||
|
* @author Adrian Lang <lang@cosmocode.de>
|
|||
|
* @param string $id The target page or namespace, specified by id; Namespaces
|
|||
|
* are identified by appending a colon.
|
|||
|
* @return bool
|
|||
|
*/
|
|||
|
protected function unlock($id) {
|
|||
|
global $conf;
|
|||
|
$lock = $conf['lockdir'].'/_subscr_'.md5($id).'.lock';
|
|||
|
return @rmdir($lock);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Construct a regular expression for parsing a subscription definition line
|
|||
|
*
|
|||
|
* @author Andreas Gohr <andi@splitbrain.org>
|
|||
|
*
|
|||
|
* @param string|array $user
|
|||
|
* @param string|array $style
|
|||
|
* @param string|array $data
|
|||
|
* @return string complete regexp including delimiters
|
|||
|
* @throws Exception when no data is passed
|
|||
|
*/
|
|||
|
protected function buildregex($user = null, $style = null, $data = null) {
|
|||
|
// always work with arrays
|
|||
|
$user = (array) $user;
|
|||
|
$style = (array) $style;
|
|||
|
$data = (array) $data;
|
|||
|
|
|||
|
// clean
|
|||
|
$user = array_filter(array_map('trim', $user));
|
|||
|
$style = array_filter(array_map('trim', $style));
|
|||
|
$data = array_filter(array_map('trim', $data));
|
|||
|
|
|||
|
// user names are encoded
|
|||
|
$user = array_map('auth_nameencode', $user);
|
|||
|
|
|||
|
// quote
|
|||
|
$user = array_map('preg_quote_cb', $user);
|
|||
|
$style = array_map('preg_quote_cb', $style);
|
|||
|
$data = array_map('preg_quote_cb', $data);
|
|||
|
|
|||
|
// join
|
|||
|
$user = join('|', $user);
|
|||
|
$style = join('|', $style);
|
|||
|
$data = join('|', $data);
|
|||
|
|
|||
|
// any data at all?
|
|||
|
if($user.$style.$data === '') throw new Exception('no data passed');
|
|||
|
|
|||
|
// replace empty values, set which ones are optional
|
|||
|
$sopt = '';
|
|||
|
$dopt = '';
|
|||
|
if($user === '') {
|
|||
|
$user = '\S+';
|
|||
|
}
|
|||
|
if($style === '') {
|
|||
|
$style = '\S+';
|
|||
|
$sopt = '?';
|
|||
|
}
|
|||
|
if($data === '') {
|
|||
|
$data = '\S+';
|
|||
|
$dopt = '?';
|
|||
|
}
|
|||
|
|
|||
|
// assemble
|
|||
|
return "/^($user)(?:\\s+($style))$sopt(?:\\s+($data))$dopt$/";
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Recursively search for matching subscriptions
|
|||
|
*
|
|||
|
* This function searches all relevant subscription files for a page or
|
|||
|
* namespace.
|
|||
|
*
|
|||
|
* @author Adrian Lang <lang@cosmocode.de>
|
|||
|
*
|
|||
|
* @param string $page The target object’s (namespace or page) id
|
|||
|
* @param string|array $user
|
|||
|
* @param string|array $style
|
|||
|
* @param string|array $data
|
|||
|
* @return array
|
|||
|
*/
|
|||
|
public function subscribers($page, $user = null, $style = null, $data = null) {
|
|||
|
if(!$this->isenabled()) return array();
|
|||
|
|
|||
|
// Construct list of files which may contain relevant subscriptions.
|
|||
|
$files = array(':' => $this->file(':'));
|
|||
|
do {
|
|||
|
$files[$page] = $this->file($page);
|
|||
|
$page = getNS(rtrim($page, ':')).':';
|
|||
|
} while($page !== ':');
|
|||
|
|
|||
|
$re = $this->buildregex($user, $style, $data);
|
|||
|
|
|||
|
// Handle files.
|
|||
|
$result = array();
|
|||
|
foreach($files as $target => $file) {
|
|||
|
if(!file_exists($file)) continue;
|
|||
|
|
|||
|
$lines = file($file);
|
|||
|
foreach($lines as $line) {
|
|||
|
// fix old style subscription files
|
|||
|
if(strpos($line, ' ') === false) $line = trim($line)." every\n";
|
|||
|
|
|||
|
// check for matching entries
|
|||
|
if(!preg_match($re, $line, $m)) continue;
|
|||
|
|
|||
|
$u = rawurldecode($m[1]); // decode the user name
|
|||
|
if(!isset($result[$target])) $result[$target] = array();
|
|||
|
$result[$target][$u] = array($m[2], $m[3]); // add to result
|
|||
|
}
|
|||
|
}
|
|||
|
return array_reverse($result);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Adds a new subscription for the given page or namespace
|
|||
|
*
|
|||
|
* This will automatically overwrite any existent subscription for the given user on this
|
|||
|
* *exact* page or namespace. It will *not* modify any subscription that may exist in higher namespaces.
|
|||
|
*
|
|||
|
* @param string $id The target page or namespace, specified by id; Namespaces
|
|||
|
* are identified by appending a colon.
|
|||
|
* @param string $user
|
|||
|
* @param string $style
|
|||
|
* @param string $data
|
|||
|
* @throws Exception when user or style is empty
|
|||
|
* @return bool
|
|||
|
*/
|
|||
|
public function add($id, $user, $style, $data = '') {
|
|||
|
if(!$this->isenabled()) return false;
|
|||
|
|
|||
|
// delete any existing subscription
|
|||
|
$this->remove($id, $user);
|
|||
|
|
|||
|
$user = auth_nameencode(trim($user));
|
|||
|
$style = trim($style);
|
|||
|
$data = trim($data);
|
|||
|
|
|||
|
if(!$user) throw new Exception('no subscription user given');
|
|||
|
if(!$style) throw new Exception('no subscription style given');
|
|||
|
if(!$data) $data = time(); //always add current time for new subscriptions
|
|||
|
|
|||
|
$line = "$user $style $data\n";
|
|||
|
$file = $this->file($id);
|
|||
|
return io_saveFile($file, $line, true);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Removes a subscription for the given page or namespace
|
|||
|
*
|
|||
|
* This removes all subscriptions matching the given criteria on the given page or
|
|||
|
* namespace. It will *not* modify any subscriptions that may exist in higher
|
|||
|
* namespaces.
|
|||
|
*
|
|||
|
* @param string $id The target object’s (namespace or page) id
|
|||
|
* @param string|array $user
|
|||
|
* @param string|array $style
|
|||
|
* @param string|array $data
|
|||
|
* @return bool
|
|||
|
*/
|
|||
|
public function remove($id, $user = null, $style = null, $data = null) {
|
|||
|
if(!$this->isenabled()) return false;
|
|||
|
|
|||
|
$file = $this->file($id);
|
|||
|
if(!file_exists($file)) return true;
|
|||
|
|
|||
|
$re = $this->buildregex($user, $style, $data);
|
|||
|
return io_deleteFromFile($file, $re, true);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Get data for $INFO['subscribed']
|
|||
|
*
|
|||
|
* $INFO['subscribed'] is either false if no subscription for the current page
|
|||
|
* and user is in effect. Else it contains an array of arrays with the fields
|
|||
|
* “target”, “style”, and optionally “data”.
|
|||
|
*
|
|||
|
* @param string $id Page ID, defaults to global $ID
|
|||
|
* @param string $user User, defaults to $_SERVER['REMOTE_USER']
|
|||
|
* @return array
|
|||
|
* @author Adrian Lang <lang@cosmocode.de>
|
|||
|
*/
|
|||
|
function user_subscription($id = '', $user = '') {
|
|||
|
if(!$this->isenabled()) return false;
|
|||
|
|
|||
|
global $ID;
|
|||
|
/** @var Input $INPUT */
|
|||
|
global $INPUT;
|
|||
|
if(!$id) $id = $ID;
|
|||
|
if(!$user) $user = $INPUT->server->str('REMOTE_USER');
|
|||
|
|
|||
|
$subs = $this->subscribers($id, $user);
|
|||
|
if(!count($subs)) return false;
|
|||
|
|
|||
|
$result = array();
|
|||
|
foreach($subs as $target => $info) {
|
|||
|
$result[] = array(
|
|||
|
'target' => $target,
|
|||
|
'style' => $info[$user][0],
|
|||
|
'data' => $info[$user][1]
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
return $result;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Send digest and list subscriptions
|
|||
|
*
|
|||
|
* This sends mails to all subscribers that have a subscription for namespaces above
|
|||
|
* the given page if the needed $conf['subscribe_time'] has passed already.
|
|||
|
*
|
|||
|
* This function is called form lib/exe/indexer.php
|
|||
|
*
|
|||
|
* @param string $page
|
|||
|
* @return int number of sent mails
|
|||
|
*/
|
|||
|
public function send_bulk($page) {
|
|||
|
if(!$this->isenabled()) return 0;
|
|||
|
|
|||
|
/** @var DokuWiki_Auth_Plugin $auth */
|
|||
|
global $auth;
|
|||
|
global $conf;
|
|||
|
global $USERINFO;
|
|||
|
/** @var Input $INPUT */
|
|||
|
global $INPUT;
|
|||
|
$count = 0;
|
|||
|
|
|||
|
$subscriptions = $this->subscribers($page, null, array('digest', 'list'));
|
|||
|
|
|||
|
// remember current user info
|
|||
|
$olduinfo = $USERINFO;
|
|||
|
$olduser = $INPUT->server->str('REMOTE_USER');
|
|||
|
|
|||
|
foreach($subscriptions as $target => $users) {
|
|||
|
if(!$this->lock($target)) continue;
|
|||
|
|
|||
|
foreach($users as $user => $info) {
|
|||
|
list($style, $lastupdate) = $info;
|
|||
|
|
|||
|
$lastupdate = (int) $lastupdate;
|
|||
|
if($lastupdate + $conf['subscribe_time'] > time()) {
|
|||
|
// Less than the configured time period passed since last
|
|||
|
// update.
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
// Work as the user to make sure ACLs apply correctly
|
|||
|
$USERINFO = $auth->getUserData($user);
|
|||
|
$INPUT->server->set('REMOTE_USER',$user);
|
|||
|
if($USERINFO === false) continue;
|
|||
|
if(!$USERINFO['mail']) continue;
|
|||
|
|
|||
|
if(substr($target, -1, 1) === ':') {
|
|||
|
// subscription target is a namespace, get all changes within
|
|||
|
$changes = getRecentsSince($lastupdate, null, getNS($target));
|
|||
|
} else {
|
|||
|
// single page subscription, check ACL ourselves
|
|||
|
if(auth_quickaclcheck($target) < AUTH_READ) continue;
|
|||
|
$meta = p_get_metadata($target);
|
|||
|
$changes = array($meta['last_change']);
|
|||
|
}
|
|||
|
|
|||
|
// Filter out pages only changed in small and own edits
|
|||
|
$change_ids = array();
|
|||
|
foreach($changes as $rev) {
|
|||
|
$n = 0;
|
|||
|
while(!is_null($rev) && $rev['date'] >= $lastupdate &&
|
|||
|
($INPUT->server->str('REMOTE_USER') === $rev['user'] ||
|
|||
|
$rev['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT)) {
|
|||
|
$pagelog = new PageChangeLog($rev['id']);
|
|||
|
$rev = $pagelog->getRevisions($n++, 1);
|
|||
|
$rev = (count($rev) > 0) ? $rev[0] : null;
|
|||
|
}
|
|||
|
|
|||
|
if(!is_null($rev) && $rev['date'] >= $lastupdate) {
|
|||
|
// Some change was not a minor one and not by myself
|
|||
|
$change_ids[] = $rev['id'];
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// send it
|
|||
|
if($style === 'digest') {
|
|||
|
foreach($change_ids as $change_id) {
|
|||
|
$this->send_digest(
|
|||
|
$USERINFO['mail'], $change_id,
|
|||
|
$lastupdate
|
|||
|
);
|
|||
|
$count++;
|
|||
|
}
|
|||
|
} elseif($style === 'list') {
|
|||
|
$this->send_list($USERINFO['mail'], $change_ids, $target);
|
|||
|
$count++;
|
|||
|
}
|
|||
|
// TODO: Handle duplicate subscriptions.
|
|||
|
|
|||
|
// Update notification time.
|
|||
|
$this->add($target, $user, $style, time());
|
|||
|
}
|
|||
|
$this->unlock($target);
|
|||
|
}
|
|||
|
|
|||
|
// restore current user info
|
|||
|
$USERINFO = $olduinfo;
|
|||
|
$INPUT->server->set('REMOTE_USER',$olduser);
|
|||
|
return $count;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Send the diff for some page change
|
|||
|
*
|
|||
|
* @param string $subscriber_mail The target mail address
|
|||
|
* @param string $template Mail template ('subscr_digest', 'subscr_single', 'mailtext', ...)
|
|||
|
* @param string $id Page for which the notification is
|
|||
|
* @param int|null $rev Old revision if any
|
|||
|
* @param string $summary Change summary if any
|
|||
|
* @return bool true if successfully sent
|
|||
|
*/
|
|||
|
public function send_diff($subscriber_mail, $template, $id, $rev = null, $summary = '') {
|
|||
|
global $DIFF_INLINESTYLES;
|
|||
|
|
|||
|
// prepare replacements (keys not set in hrep will be taken from trep)
|
|||
|
$trep = array(
|
|||
|
'PAGE' => $id,
|
|||
|
'NEWPAGE' => wl($id, '', true, '&'),
|
|||
|
'SUMMARY' => $summary,
|
|||
|
'SUBSCRIBE' => wl($id, array('do' => 'subscribe'), true, '&')
|
|||
|
);
|
|||
|
$hrep = array();
|
|||
|
|
|||
|
if($rev) {
|
|||
|
$subject = 'changed';
|
|||
|
$trep['OLDPAGE'] = wl($id, "rev=$rev", true, '&');
|
|||
|
|
|||
|
$old_content = rawWiki($id, $rev);
|
|||
|
$new_content = rawWiki($id);
|
|||
|
|
|||
|
$df = new Diff(explode("\n", $old_content),
|
|||
|
explode("\n", $new_content));
|
|||
|
$dformat = new UnifiedDiffFormatter();
|
|||
|
$tdiff = $dformat->format($df);
|
|||
|
|
|||
|
$DIFF_INLINESTYLES = true;
|
|||
|
$df = new Diff(explode("\n", $old_content),
|
|||
|
explode("\n", $new_content));
|
|||
|
$dformat = new InlineDiffFormatter();
|
|||
|
$hdiff = $dformat->format($df);
|
|||
|
$hdiff = '<table>'.$hdiff.'</table>';
|
|||
|
$DIFF_INLINESTYLES = false;
|
|||
|
} else {
|
|||
|
$subject = 'newpage';
|
|||
|
$trep['OLDPAGE'] = '---';
|
|||
|
$tdiff = rawWiki($id);
|
|||
|
$hdiff = nl2br(hsc($tdiff));
|
|||
|
}
|
|||
|
|
|||
|
$trep['DIFF'] = $tdiff;
|
|||
|
$hrep['DIFF'] = $hdiff;
|
|||
|
|
|||
|
$headers = array('Message-Id' => $this->getMessageID($id));
|
|||
|
if ($rev) {
|
|||
|
$headers['In-Reply-To'] = $this->getMessageID($id, $rev);
|
|||
|
}
|
|||
|
|
|||
|
return $this->send(
|
|||
|
$subscriber_mail, $subject, $id,
|
|||
|
$template, $trep, $hrep, $headers
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Send the diff for some media change
|
|||
|
*
|
|||
|
* @fixme this should embed thumbnails of images in HTML version
|
|||
|
*
|
|||
|
* @param string $subscriber_mail The target mail address
|
|||
|
* @param string $template Mail template ('uploadmail', ...)
|
|||
|
* @param string $id Media file for which the notification is
|
|||
|
* @param int|bool $rev Old revision if any
|
|||
|
*/
|
|||
|
public function send_media_diff($subscriber_mail, $template, $id, $rev = false) {
|
|||
|
global $conf;
|
|||
|
|
|||
|
$file = mediaFN($id);
|
|||
|
list($mime, /* $ext */) = mimetype($id);
|
|||
|
|
|||
|
$trep = array(
|
|||
|
'MIME' => $mime,
|
|||
|
'MEDIA' => ml($id,'',true,'&',true),
|
|||
|
'SIZE' => filesize_h(filesize($file)),
|
|||
|
);
|
|||
|
|
|||
|
if ($rev && $conf['mediarevisions']) {
|
|||
|
$trep['OLD'] = ml($id, "rev=$rev", true, '&', true);
|
|||
|
} else {
|
|||
|
$trep['OLD'] = '---';
|
|||
|
}
|
|||
|
|
|||
|
$headers = array('Message-Id' => $this->getMessageID($id, @filemtime($file)));
|
|||
|
if ($rev) {
|
|||
|
$headers['In-Reply-To'] = $this->getMessageID($id, $rev);
|
|||
|
}
|
|||
|
|
|||
|
$this->send($subscriber_mail, 'upload', $id, $template, $trep, null, $headers);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Send a notify mail on new registration
|
|||
|
*
|
|||
|
* @author Andreas Gohr <andi@splitbrain.org>
|
|||
|
*
|
|||
|
* @param string $login login name of the new user
|
|||
|
* @param string $fullname full name of the new user
|
|||
|
* @param string $email email address of the new user
|
|||
|
* @return bool true if a mail was sent
|
|||
|
*/
|
|||
|
public function send_register($login, $fullname, $email) {
|
|||
|
global $conf;
|
|||
|
if(empty($conf['registernotify'])) return false;
|
|||
|
|
|||
|
$trep = array(
|
|||
|
'NEWUSER' => $login,
|
|||
|
'NEWNAME' => $fullname,
|
|||
|
'NEWEMAIL' => $email,
|
|||
|
);
|
|||
|
|
|||
|
return $this->send(
|
|||
|
$conf['registernotify'],
|
|||
|
'new_user',
|
|||
|
$login,
|
|||
|
'registermail',
|
|||
|
$trep
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Send a digest mail
|
|||
|
*
|
|||
|
* Sends a digest mail showing a bunch of changes of a single page. Basically the same as send_diff()
|
|||
|
* but determines the last known revision first
|
|||
|
*
|
|||
|
* @author Adrian Lang <lang@cosmocode.de>
|
|||
|
*
|
|||
|
* @param string $subscriber_mail The target mail address
|
|||
|
* @param string $id The ID
|
|||
|
* @param int $lastupdate Time of the last notification
|
|||
|
* @return bool
|
|||
|
*/
|
|||
|
protected function send_digest($subscriber_mail, $id, $lastupdate) {
|
|||
|
$pagelog = new PageChangeLog($id);
|
|||
|
$n = 0;
|
|||
|
do {
|
|||
|
$rev = $pagelog->getRevisions($n++, 1);
|
|||
|
$rev = (count($rev) > 0) ? $rev[0] : null;
|
|||
|
} while(!is_null($rev) && $rev > $lastupdate);
|
|||
|
|
|||
|
return $this->send_diff(
|
|||
|
$subscriber_mail,
|
|||
|
'subscr_digest',
|
|||
|
$id, $rev
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Send a list mail
|
|||
|
*
|
|||
|
* Sends a list mail showing a list of changed pages.
|
|||
|
*
|
|||
|
* @author Adrian Lang <lang@cosmocode.de>
|
|||
|
*
|
|||
|
* @param string $subscriber_mail The target mail address
|
|||
|
* @param array $ids Array of ids
|
|||
|
* @param string $ns_id The id of the namespace
|
|||
|
* @return bool true if a mail was sent
|
|||
|
*/
|
|||
|
protected function send_list($subscriber_mail, $ids, $ns_id) {
|
|||
|
if(count($ids) === 0) return false;
|
|||
|
|
|||
|
$tlist = '';
|
|||
|
$hlist = '<ul>';
|
|||
|
foreach($ids as $id) {
|
|||
|
$link = wl($id, array(), true);
|
|||
|
$tlist .= '* '.$link.NL;
|
|||
|
$hlist .= '<li><a href="'.$link.'">'.hsc($id).'</a></li>'.NL;
|
|||
|
}
|
|||
|
$hlist .= '</ul>';
|
|||
|
|
|||
|
$id = prettyprint_id($ns_id);
|
|||
|
$trep = array(
|
|||
|
'DIFF' => rtrim($tlist),
|
|||
|
'PAGE' => $id,
|
|||
|
'SUBSCRIBE' => wl($id, array('do' => 'subscribe'), true, '&')
|
|||
|
);
|
|||
|
$hrep = array(
|
|||
|
'DIFF' => $hlist
|
|||
|
);
|
|||
|
|
|||
|
return $this->send(
|
|||
|
$subscriber_mail,
|
|||
|
'subscribe_list',
|
|||
|
$ns_id,
|
|||
|
'subscr_list', $trep, $hrep
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Helper function for sending a mail
|
|||
|
*
|
|||
|
* @author Adrian Lang <lang@cosmocode.de>
|
|||
|
*
|
|||
|
* @param string $subscriber_mail The target mail address
|
|||
|
* @param string $subject The lang id of the mail subject (without the
|
|||
|
* prefix “mail_”)
|
|||
|
* @param string $context The context of this mail, eg. page or namespace id
|
|||
|
* @param string $template The name of the mail template
|
|||
|
* @param array $trep Predefined parameters used to parse the
|
|||
|
* template (in text format)
|
|||
|
* @param array $hrep Predefined parameters used to parse the
|
|||
|
* template (in HTML format), null to default to $trep
|
|||
|
* @param array $headers Additional mail headers in the form 'name' => 'value'
|
|||
|
* @return bool
|
|||
|
*/
|
|||
|
protected function send($subscriber_mail, $subject, $context, $template, $trep, $hrep = null, $headers = array()) {
|
|||
|
global $lang;
|
|||
|
global $conf;
|
|||
|
|
|||
|
$text = rawLocale($template);
|
|||
|
$subject = $lang['mail_'.$subject].' '.$context;
|
|||
|
$mail = new Mailer();
|
|||
|
$mail->bcc($subscriber_mail);
|
|||
|
$mail->subject($subject);
|
|||
|
$mail->setBody($text, $trep, $hrep);
|
|||
|
if(in_array($template, array('subscr_list', 'subscr_digest'))){
|
|||
|
$mail->from($conf['mailfromnobody']);
|
|||
|
}
|
|||
|
if(isset($trep['SUBSCRIBE'])) {
|
|||
|
$mail->setHeader('List-Unsubscribe', '<'.$trep['SUBSCRIBE'].'>', false);
|
|||
|
}
|
|||
|
|
|||
|
foreach ($headers as $header => $value) {
|
|||
|
$mail->setHeader($header, $value);
|
|||
|
}
|
|||
|
|
|||
|
return $mail->send();
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Get a valid message id for a certain $id and revision (or the current revision)
|
|||
|
*
|
|||
|
* @param string $id The id of the page (or media file) the message id should be for
|
|||
|
* @param string $rev The revision of the page, set to the current revision of the page $id if not set
|
|||
|
* @return string
|
|||
|
*/
|
|||
|
protected function getMessageID($id, $rev = null) {
|
|||
|
static $listid = null;
|
|||
|
if (is_null($listid)) {
|
|||
|
$server = parse_url(DOKU_URL, PHP_URL_HOST);
|
|||
|
$listid = join('.', array_reverse(explode('/', DOKU_BASE))).$server;
|
|||
|
$listid = urlencode($listid);
|
|||
|
$listid = strtolower(trim($listid, '.'));
|
|||
|
}
|
|||
|
|
|||
|
if (is_null($rev)) {
|
|||
|
$rev = @filemtime(wikiFN($id));
|
|||
|
}
|
|||
|
|
|||
|
return "<$id?rev=$rev@$listid>";
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Default callback for COMMON_NOTIFY_ADDRESSLIST
|
|||
|
*
|
|||
|
* Aggregates all email addresses of user who have subscribed the given page with 'every' style
|
|||
|
*
|
|||
|
* @author Steven Danz <steven-danz@kc.rr.com>
|
|||
|
* @author Adrian Lang <lang@cosmocode.de>
|
|||
|
*
|
|||
|
* @todo move the whole functionality into this class, trigger SUBSCRIPTION_NOTIFY_ADDRESSLIST instead,
|
|||
|
* use an array for the addresses within it
|
|||
|
*
|
|||
|
* @param array &$data Containing the entries:
|
|||
|
* - $id (the page id),
|
|||
|
* - $self (whether the author should be notified,
|
|||
|
* - $addresslist (current email address list)
|
|||
|
* - $replacements (array of additional string substitutions, @KEY@ to be replaced by value)
|
|||
|
*/
|
|||
|
public function notifyaddresses(&$data) {
|
|||
|
if(!$this->isenabled()) return;
|
|||
|
|
|||
|
/** @var DokuWiki_Auth_Plugin $auth */
|
|||
|
global $auth;
|
|||
|
global $conf;
|
|||
|
/** @var Input $INPUT */
|
|||
|
global $INPUT;
|
|||
|
|
|||
|
$id = $data['id'];
|
|||
|
$self = $data['self'];
|
|||
|
$addresslist = $data['addresslist'];
|
|||
|
|
|||
|
$subscriptions = $this->subscribers($id, null, 'every');
|
|||
|
|
|||
|
$result = array();
|
|||
|
foreach($subscriptions as $target => $users) {
|
|||
|
foreach($users as $user => $info) {
|
|||
|
$userinfo = $auth->getUserData($user);
|
|||
|
if($userinfo === false) continue;
|
|||
|
if(!$userinfo['mail']) continue;
|
|||
|
if(!$self && $user == $INPUT->server->str('REMOTE_USER')) continue; //skip our own changes
|
|||
|
|
|||
|
$level = auth_aclcheck($id, $user, $userinfo['grps']);
|
|||
|
if($level >= AUTH_READ) {
|
|||
|
if(strcasecmp($userinfo['mail'], $conf['notify']) != 0) { //skip user who get notified elsewhere
|
|||
|
$result[$user] = $userinfo['mail'];
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
$data['addresslist'] = trim($addresslist.','.implode(',', $result), ',');
|
|||
|
}
|
|||
|
}
|