diff options
author | ahriman <ahriman@falte.red> | 2019-01-02 04:57:35 +0000 |
---|---|---|
committer | ahriman <ahriman@falte.red> | 2019-01-02 04:57:35 +0000 |
commit | 2bd7f83a6495011ada78ca8a9f2af417caf01760 (patch) | |
tree | f9acdb7f09e011c65330ab993d4db3620787dbfb /wiki/inc/subscription.php | |
parent | bcb215c3a7e914d05f166846a33860e48bba64fb (diff) | |
download | site-2bd7f83a6495011ada78ca8a9f2af417caf01760.tar.gz |
removed dokuwiki
Diffstat (limited to 'wiki/inc/subscription.php')
-rw-r--r-- | wiki/inc/subscription.php | 693 |
1 files changed, 0 insertions, 693 deletions
diff --git a/wiki/inc/subscription.php b/wiki/inc/subscription.php deleted file mode 100644 index 74bec65..0000000 --- a/wiki/inc/subscription.php +++ /dev/null @@ -1,693 +0,0 @@ -<?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), ','); - } -} |