summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README2
-rw-r--r--_test/tests/inc/search/search.test.php19
-rw-r--r--_test/tests/inc/subscription.test.php246
-rw-r--r--_test/tests/inc/subscription_set.test.php20
-rw-r--r--inc/RemoteAPICore.php8
-rw-r--r--inc/Tar.class.php44
-rw-r--r--inc/actions.php22
-rw-r--r--inc/auth.php14
-rw-r--r--inc/changelog.php1
-rw-r--r--inc/common.php85
-rw-r--r--inc/html.php3
-rw-r--r--inc/lang/ar/subscr_single.txt2
-rw-r--r--inc/lang/bg/subscr_single.txt2
-rw-r--r--inc/lang/da/subscr_single.txt2
-rw-r--r--inc/lang/de-informal/subscr_single.txt2
-rw-r--r--inc/lang/de/subscr_single.txt2
-rw-r--r--inc/lang/en/subscr_single.txt2
-rw-r--r--inc/lang/eo/subscr_single.txt2
-rw-r--r--inc/lang/he/subscr_single.txt2
-rw-r--r--inc/lang/ia/subscr_single.txt2
-rw-r--r--inc/lang/it/subscr_single.txt2
-rw-r--r--inc/lang/ko/subscr_single.txt2
-rw-r--r--inc/lang/la/subscr_digest.txt2
-rw-r--r--inc/lang/la/subscr_single.txt2
-rw-r--r--inc/lang/no/subscr_digest.txt2
-rw-r--r--inc/lang/no/subscr_list.txt2
-rw-r--r--inc/lang/no/subscr_single.txt2
-rw-r--r--inc/lang/pt/subscr_single.txt2
-rw-r--r--inc/lang/sq/subscr_single.txt2
-rw-r--r--inc/load.php1
-rw-r--r--inc/plugin.php4
-rw-r--r--inc/search.php11
-rw-r--r--inc/subscription.php925
-rw-r--r--lib/exe/indexer.php93
-rw-r--r--lib/scripts/fileuploaderextended.js2
-rw-r--r--lib/scripts/toolbar.js2
36 files changed, 936 insertions, 602 deletions
diff --git a/README b/README
index 0490040f2..3b7cb8a9c 100644
--- a/README
+++ b/README
@@ -4,7 +4,7 @@ at http://www.dokuwiki.org/
For Installation Instructions see
http://www.dokuwiki.org/install
-DokuWiki - 2004-2012 (c) Andreas Gohr <andi@splitbrain.org>
+DokuWiki - 2004-2013 (c) Andreas Gohr <andi@splitbrain.org>
and the DokuWiki Community
See COPYING and file headers for license info
diff --git a/_test/tests/inc/search/search.test.php b/_test/tests/inc/search/search.test.php
index 33cc80e74..9c854a661 100644
--- a/_test/tests/inc/search/search.test.php
+++ b/_test/tests/inc/search/search.test.php
@@ -1,6 +1,7 @@
<?php
class search_test extends DokuWikiTest {
+
function strip_index_data($entry) {
$n_entry = array();
foreach(array('id', 'type', 'level', 'open') as $k) {
@@ -9,6 +10,24 @@ class search_test extends DokuWikiTest {
return $n_entry;
}
+ function test_search_allpages(){
+ $data = array();
+
+ //depth is 0 hence we should recurse endlesly
+ search($data, dirname(__FILE__) . '/data', 'search_allpages', array('depth' => 0), 'ns1');
+ $this->assertEquals(3, count($data));
+
+ //depth is 1 and we start too deep to expect results
+ $data = array();
+ search($data, dirname(__FILE__) . '/data', 'search_allpages', array('depth' => 1), 'ns1/ns3');
+ $this->assertEquals(0, count($data));
+
+ //depth is 1 so I should get only pages from ns1
+ $data = array();
+ search($data, dirname(__FILE__) . '/data', 'search_allpages', array('depth' => 1), 'ns1');
+ $this->assertEquals(2, count($data));
+ }
+
function test_search_index(){
$data = array();
search($data, dirname(__FILE__) . '/data', 'search_index',
diff --git a/_test/tests/inc/subscription.test.php b/_test/tests/inc/subscription.test.php
new file mode 100644
index 000000000..333400576
--- /dev/null
+++ b/_test/tests/inc/subscription.test.php
@@ -0,0 +1,246 @@
+<?php
+
+class subscription_test extends DokuWikiTest {
+
+ function test_regexp() {
+ // data to test against
+ $data = array(
+ "casper every\n",
+ "Andreas digest 1344689733",
+ "Cold%20Fusion every",
+ "zioth list 1344691369\n",
+ "nlights digest",
+ "rikblok\tdigest \t 1344716803",
+ );
+
+ // user, style, data, expected number of results
+ $tests = array(
+ array('Cold Fusion', null, null, 1),
+ array('casper', null, null, 1),
+ array('nope', null, null, 0),
+ array('lights', null, null, 0),
+ array(array('Cold Fusion', 'casper', 'nope'), null, null, 2),
+ array(null, 'list', null, 1),
+ array(null, 'every', null, 2),
+ array(null, 'digest', null, 3),
+ array(null, array('list', 'every'), null, 3),
+ array('casper', 'digest', null, 0),
+ array('casper', array('digest', 'every'), null, 1),
+ array('zioth', 'list', '1344691369', 1),
+ array('zioth', null, '1344691369', 1),
+ array('zioth', 'digest', '1344691369', 0),
+ );
+
+ $sub = new MockupSubscription();
+
+ $row = 0;
+ foreach($tests as $test) {
+ $re = $sub->buildregex($test[0], $test[1], $test[2]);
+ $this->assertFalse(empty($re), "test line $row");
+ $result = preg_grep($re, $data);
+ $this->assertEquals($test[3], count($result), "test line $row. $re got\n".print_r($result, true));
+
+ $row++;
+ }
+ }
+
+ function test_addremove() {
+ $sub = new MockupSubscription();
+
+ // no subscriptions
+ $this->assertArrayNotHasKey(
+ 'wiki:dokuwiki',
+ $sub->subscribers('wiki:dokuwiki', null, array('every', 'list', 'digest'))
+ );
+
+ // add page subscription
+ $sub->add('wiki:dokuwiki', 'testuser', 'every');
+
+ // one subscription
+ $this->assertArrayHasKey(
+ 'wiki:dokuwiki',
+ $sub->subscribers('wiki:dokuwiki', null, array('every', 'list', 'digest'))
+ );
+
+ // remove page subscription
+ $sub->remove('wiki:dokuwiki', 'testuser');
+
+ // no subscription
+ $this->assertArrayNotHasKey(
+ 'wiki:dokuwiki',
+ $sub->subscribers('wiki:dokuwiki', null, array('every', 'list', 'digest'))
+ );
+
+ // add namespace subscription
+ $sub->add('wiki:', 'testuser', 'every');
+
+ // one subscription
+ $this->assertArrayHasKey(
+ 'wiki:',
+ $sub->subscribers('wiki:dokuwiki', null, array('every', 'list', 'digest'))
+ );
+
+ // remove (non existing) page subscription
+ $sub->remove('wiki:dokuwiki', 'testuser');
+
+ // still one subscription
+ $this->assertArrayHasKey(
+ 'wiki:',
+ $sub->subscribers('wiki:dokuwiki', null, array('every', 'list', 'digest'))
+ );
+
+ // change namespace subscription
+ $sub->add('wiki:', 'testuser', 'digest', '1234567');
+
+ // still one subscription
+ $this->assertArrayHasKey(
+ 'wiki:',
+ $sub->subscribers('wiki:dokuwiki', null, array('every', 'list', 'digest'))
+ );
+
+ // check contents
+ $this->assertEquals(
+ array('wiki:' => array('testuser' => array('digest', '1234567'))),
+ $sub->subscribers('wiki:dokuwiki', null, array('every', 'list', 'digest'))
+ );
+
+ // change subscription data
+ $sub->add('wiki:', 'testuser', 'digest', '7654321');
+
+ // still one subscription
+ $this->assertArrayHasKey(
+ 'wiki:',
+ $sub->subscribers('wiki:dokuwiki', null, array('every', 'list', 'digest'))
+ );
+
+ // check contents
+ $this->assertEquals(
+ array('wiki:' => array('testuser' => array('digest', '7654321'))),
+ $sub->subscribers('wiki:dokuwiki', null, array('every', 'list', 'digest'))
+ );
+ }
+
+ function test_bulkdigest() {
+ $sub = new MockupSubscription();
+
+ // let's start with nothing
+ $this->assertEquals(0, $sub->send_bulk('sub1:test'));
+
+ // create a subscription
+ $sub->add('sub1:', 'testuser', 'digest', '978328800'); // last mod 2001-01-01
+
+ // now create change
+ $_SERVER['REMOTE_USER'] = 'someguy';
+ saveWikiText('sub1:test', 'foo bar', 'a subscription change', false);
+
+ // should trigger a mail
+ $this->assertEquals(1, $sub->send_bulk('sub1:test'));
+ $this->assertEquals(array('arthur@example.com'), $sub->mails);
+
+ $sub->reset();
+
+ // now create more changes
+ $_SERVER['REMOTE_USER'] = 'someguy';
+ saveWikiText('sub1:sub2:test', 'foo bar', 'a subscription change', false);
+ saveWikiText('sub1:another_test', 'foo bar', 'a subscription change', false);
+
+ // should not trigger a mail, because the subscription time has not been reached, yet
+ $this->assertEquals(0, $sub->send_bulk('sub1:test'));
+ $this->assertEquals(array(), $sub->mails);
+
+ // reset the subscription time
+ $sub->add('sub1:', 'testuser', 'digest', '978328800'); // last mod 2001-01-01
+
+ // we now should get mails for three changes
+ $this->assertEquals(3, $sub->send_bulk('sub1:test'));
+ $this->assertEquals(array('arthur@example.com', 'arthur@example.com', 'arthur@example.com'), $sub->mails);
+ }
+
+ function test_bulklist() {
+ $sub = new MockupSubscription();
+
+ // let's start with nothing
+ $this->assertEquals(0, $sub->send_bulk('sub1:test'));
+
+ // create a subscription
+ $sub->add('sub1:', 'testuser', 'list', '978328800'); // last mod 2001-01-01
+
+ // now create change
+ $_SERVER['REMOTE_USER'] = 'someguy';
+ saveWikiText('sub1:test', 'foo bar', 'a subscription change', false);
+
+ // should trigger a mail
+ $this->assertEquals(1, $sub->send_bulk('sub1:test'));
+ $this->assertEquals(array('arthur@example.com'), $sub->mails);
+
+ $sub->reset();
+
+ // now create more changes
+ $_SERVER['REMOTE_USER'] = 'someguy';
+ saveWikiText('sub1:sub2:test', 'foo bar', 'a subscription change', false);
+ saveWikiText('sub1:another_test', 'foo bar', 'a subscription change', false);
+
+ // should not trigger a mail, because the subscription time has not been reached, yet
+ $this->assertEquals(0, $sub->send_bulk('sub1:test'));
+ $this->assertEquals(array(), $sub->mails);
+
+ // reset the subscription time
+ $sub->add('sub1:', 'testuser', 'list', '978328800'); // last mod 2001-01-01
+
+ // we now should get a single mail for all three changes
+ $this->assertEquals(1, $sub->send_bulk('sub1:test'));
+ $this->assertEquals(array('arthur@example.com'), $sub->mails);
+ }
+
+ /**
+ * Tests, if overwriting subscriptions works even when subscriptions for the same
+ * user exist for two nested namespaces, this is a test for the bug described in FS#2580
+ */
+ function test_overwrite() {
+ $sub = new MockupSubscription();
+
+ $sub->add(':', 'admin', 'digest', '123456789');
+ $sub->add(':wiki:', 'admin', 'digest', '123456789');
+ $sub->add(':', 'admin', 'digest', '1234');
+ $sub->add(':wiki:', 'admin', 'digest', '1234');
+
+ $subscriptions = $sub->subscribers(':wiki:', 'admin');
+
+ $this->assertCount(1, $subscriptions[':'], 'More than one subscription saved for the root namespace even though the old one should have been overwritten.');
+ $this->assertCount(1, $subscriptions[':wiki:'], 'More than one subscription saved for the wiki namespace even though the old one should have been overwritten.');
+ $this->assertCount(2, $subscriptions, 'Didn\'t find the expected two subscriptions');
+ }
+}
+
+/**
+ * makes protected methods visible for testing
+ */
+class MockupSubscription extends Subscription {
+ public $mails; // we keep sent mails here
+
+ public function __construct() {
+ $this->reset();
+ }
+
+ /**
+ * resets the mail array
+ */
+ public function reset() {
+ $this->mails = array();
+ }
+
+ public function isenabled() {
+ return true;
+ }
+
+ public function buildregex($user = null, $style = null, $data = null) {
+ return parent::buildregex($user, $style, $data);
+ }
+
+ protected function send($subscriber_mail, $subject, $id, $template, $trep, $hrep = null) {
+ $this->mails[] = $subscriber_mail;
+ return true;
+ }
+}
+
+//Setup VIM: ex: et ts=4 :
diff --git a/_test/tests/inc/subscription_set.test.php b/_test/tests/inc/subscription_set.test.php
deleted file mode 100644
index 5c0a6c816..000000000
--- a/_test/tests/inc/subscription_set.test.php
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-/**
- * Tests the subscription set function
- */
-class subscription_set_test extends DokuWikiTest {
- /**
- * Tests, if overwriting subscriptions works even when subscriptions for the same
- * user exist for two nested namespaces, this is a test for the bug described in FS#2580
- */
- function test_overwrite() {
- subscription_set('admin', ':', 'digest', '123456789');
- subscription_set('admin', ':wiki:', 'digest', '123456789');
- subscription_set('admin', ':', 'digest', '1234', true);
- subscription_set('admin', ':wiki:', 'digest', '1234', true);
- $subscriptions = subscription_find(':wiki:', array('user' => 'admin'));
- $this->assertCount(1, $subscriptions[':'], 'More than one subscription saved for the root namespace even though the old one should have been overwritten.');
- $this->assertCount(1, $subscriptions[':wiki:'], 'More than one subscription saved for the wiki namespace even though the old one should have been overwritten.');
- $this->assertCount(2, $subscriptions, 'Didn\'t find the expected two subscriptions');
- }
-}
diff --git a/inc/RemoteAPICore.php b/inc/RemoteAPICore.php
index c04a14f5c..81b211ec8 100644
--- a/inc/RemoteAPICore.php
+++ b/inc/RemoteAPICore.php
@@ -3,7 +3,7 @@
/**
* Increased whenever the API is changed
*/
-define('DOKU_API_VERSION', 7);
+define('DOKU_API_VERSION', 8);
class RemoteAPICore {
@@ -344,6 +344,8 @@ class RemoteAPICore {
for($i=0; $i<$len; $i++) {
unset($data[$i]['meta']);
+ $data[$i]['perms'] = $data[$i]['perm'];
+ unset($data[$i]['perm']);
$data[$i]['lastModified'] = $this->api->toDate($data[$i]['mtime']);
}
return $data;
@@ -654,7 +656,9 @@ class RemoteAPICore {
if(count($revisions)>0 && $first==0) {
array_unshift($revisions, ''); // include current revision
- array_pop($revisions); // remove extra log entry
+ if ( count($revisions) > $conf['recent'] ){
+ array_pop($revisions); // remove extra log entry
+ }
}
if(count($revisions) > $conf['recent']) {
diff --git a/inc/Tar.class.php b/inc/Tar.class.php
index 59e14c705..20f397395 100644
--- a/inc/Tar.class.php
+++ b/inc/Tar.class.php
@@ -17,7 +17,7 @@
*
* $tar = new Tar();
* $tar->open('myfile.tgz');
- * $tar->extract(/tmp);
+ * $tar->extract('/tmp');
*
* To create a new TAR archive directly on the filesystem (low memory requirements), create() it,
* add*() files and close() it:
@@ -81,7 +81,7 @@ class Tar {
$this->fh = @fopen($this->file, 'rb');
}
- if(!$this->fh) throw(new TarIOException('Could not open file for reading: '.$this->file));
+ if(!$this->fh) throw new TarIOException('Could not open file for reading: '.$this->file);
$this->closed = false;
}
@@ -107,9 +107,9 @@ class Tar {
* Reopen the file with open() again if you want to do additional operations
*/
public function contents() {
- if($this->closed || !$this->file) throw(new TarIOException('Can not read from a closed archive'));
+ if($this->closed || !$this->file) throw new TarIOException('Can not read from a closed archive');
- $result = Array();
+ $result = array();
while($read = $this->readbytes(512)) {
$header = $this->parseHeader($read);
if(!is_array($header)) continue;
@@ -148,7 +148,7 @@ class Tar {
* @return array
*/
function extract($outdir, $strip = '', $exclude = '', $include = '') {
- if($this->closed || !$this->file) throw(new TarIOException('Can not read from a closed archive'));
+ if($this->closed || !$this->file) throw new TarIOException('Can not read from a closed archive');
$outdir = rtrim($outdir, '/');
io_mkdir_p($outdir);
@@ -207,7 +207,7 @@ class Tar {
// is this a file?
if(!$header['typeflag']) {
$fp = fopen($output, "wb");
- if(!$fp) throw(new TarIOException('Could not open file for writing: '.$output));
+ if(!$fp) throw new TarIOException('Could not open file for writing: '.$output);
$size = floor($header['size'] / 512);
for($i = 0; $i < $size; $i++) {
@@ -260,7 +260,7 @@ class Tar {
$this->fh = @fopen($this->file, 'wb');
}
- if(!$this->fh) throw(new TarIOException('Could not open file for writing: '.$this->file));
+ if(!$this->fh) throw new TarIOException('Could not open file for writing: '.$this->file);
}
$this->writeaccess = false;
$this->closed = false;
@@ -275,13 +275,13 @@ class Tar {
* @throws TarIOException
*/
public function addFile($file, $name = '') {
- if($this->closed) throw(new TarIOException('Archive has been closed, files can no longer be added'));
+ if($this->closed) throw new TarIOException('Archive has been closed, files can no longer be added');
if(!$name) $name = $file;
$name = $this->cleanPath($name);
$fp = fopen($file, 'rb');
- if(!$fp) throw(new TarIOException('Could not open file for reading: '.$file));
+ if(!$fp) throw new TarIOException('Could not open file for reading: '.$file);
// create file header and copy all stat info from the original file
clearstatcache(false, $file);
@@ -314,7 +314,7 @@ class Tar {
* @throws TarIOException
*/
public function addData($name, $data, $uid = 0, $gid = 0, $perm = 0666, $mtime = 0) {
- if($this->closed) throw(new TarIOException('Archive has been closed, files can no longer be added'));
+ if($this->closed) throw new TarIOException('Archive has been closed, files can no longer be added');
$name = $this->cleanPath($name);
$len = strlen($data);
@@ -401,7 +401,7 @@ class Tar {
if($comptype === Tar::COMPRESS_AUTO) $comptype = $this->filetype($file);
if(!file_put_contents($file, $this->getArchive($comptype, $complevel))) {
- throw(new TarIOException('Could not write to file: '.$file));
+ throw new TarIOException('Could not write to file: '.$file);
}
}
@@ -439,14 +439,14 @@ class Tar {
} else {
$written = @fwrite($this->fh, $data);
}
- if($written === false) throw(new TarIOException('Failed to write to archive stream'));
+ if($written === false) throw new TarIOException('Failed to write to archive stream');
return $written;
}
/**
* Skip forward in the open file pointer
*
- * This is basically a wrapper around seek() (and a workarounf for bzip2)
+ * This is basically a wrapper around seek() (and a workaround for bzip2)
*
* @param int $bytes seek to this position
*/
@@ -494,11 +494,11 @@ class Tar {
}
// values are needed in octal
- $uid = sprintf("%6s ", DecOct($uid));
- $gid = sprintf("%6s ", DecOct($gid));
- $perm = sprintf("%6s ", DecOct($perm));
- $size = sprintf("%11s ", DecOct($size));
- $mtime = sprintf("%11s", DecOct($mtime));
+ $uid = sprintf("%6s ", decoct($uid));
+ $gid = sprintf("%6s ", decoct($gid));
+ $perm = sprintf("%6s ", decoct($perm));
+ $size = sprintf("%11s ", decoct($size));
+ $mtime = sprintf("%11s", decoct($mtime));
$data_first = pack("a100a8a8a8a12A12", $name, $perm, $uid, $gid, $size, $mtime);
$data_last = pack("a1a100a6a2a32a32a8a8a155a12", $typeflag, '', 'ustar', '', '', '', '', '', $prefix, "");
@@ -511,7 +511,7 @@ class Tar {
$this->writebytes($data_first);
- $chks = pack("a8", sprintf("%6s ", DecOct($chks)));
+ $chks = pack("a8", sprintf("%6s ", decoct($chks)));
$this->writebytes($chks.$data_last);
}
@@ -598,11 +598,11 @@ class Tar {
*/
protected function compressioncheck($comptype) {
if($comptype === Tar::COMPRESS_GZIP && !function_exists('gzopen')) {
- throw(new TarIllegalCompressionException('No gzip support available'));
+ throw new TarIllegalCompressionException('No gzip support available');
}
if($comptype === Tar::COMPRESS_BZIP && !function_exists('bzopen')) {
- throw(new TarIllegalCompressionException('No bzip2 support available'));
+ throw new TarIllegalCompressionException('No bzip2 support available');
}
}
@@ -631,4 +631,4 @@ class TarIOException extends Exception {
}
class TarIllegalCompressionException extends Exception {
-} \ No newline at end of file
+}
diff --git a/inc/actions.php b/inc/actions.php
index f65b47451..4083b0454 100644
--- a/inc/actions.php
+++ b/inc/actions.php
@@ -711,21 +711,28 @@ function act_subscription($act){
$target = $params['target'];
$style = $params['style'];
- $data = $params['data'];
$action = $params['action'];
// Perform action.
- if (!subscription_set($_SERVER['REMOTE_USER'], $target, $style, $data)) {
+ $sub = new Subscription();
+ if($action == 'unsubscribe'){
+ $ok = $sub->remove($target, $_SERVER['REMOTE_USER'], $style);
+ }else{
+ $ok = $sub->add($target, $_SERVER['REMOTE_USER'], $style);
+ }
+
+ if($ok) {
+ msg(sprintf($lang["subscr_{$action}_success"], hsc($INFO['userinfo']['name']),
+ prettyprint_id($target)), 1);
+ act_redirect($ID, $act);
+ } else {
throw new Exception(sprintf($lang["subscr_{$action}_error"],
hsc($INFO['userinfo']['name']),
prettyprint_id($target)));
}
- msg(sprintf($lang["subscr_{$action}_success"], hsc($INFO['userinfo']['name']),
- prettyprint_id($target)), 1);
- act_redirect($ID, $act);
// Assure that we have valid data if act_redirect somehow fails.
- $INFO['subscribed'] = get_info_subscribed();
+ $INFO['subscribed'] = $sub->user_subscription();
return 'show';
}
@@ -777,8 +784,7 @@ function subscription_handle_post(&$params) {
$style = null;
}
- $data = in_array($style, array('list', 'digest')) ? time() : null;
- $params = compact('target', 'style', 'data', 'action');
+ $params = compact('target', 'style', 'action');
}
//Setup VIM: ex: et ts=2 :
diff --git a/inc/auth.php b/inc/auth.php
index c68a699fe..c4f1dcf2b 100644
--- a/inc/auth.php
+++ b/inc/auth.php
@@ -780,23 +780,19 @@ function register() {
return false;
}
- // create substitutions for use in notification email
- $substitutions = array(
- 'NEWUSER' => $login,
- 'NEWNAME' => $fullname,
- 'NEWEMAIL' => $email,
- );
+ // send notification about the new user
+ $subscription = new Subscription();
+ $subscription->send_register($login, $fullname, $email);
+ // are we done?
if(!$conf['autopasswd']) {
msg($lang['regsuccess2'], 1);
- notify('', 'register', '', $login, false, $substitutions);
return true;
}
- // autogenerated password? then send him the password
+ // autogenerated password? then send password to user
if(auth_sendPassword($login, $pass)) {
msg($lang['regsuccess'], 1);
- notify('', 'register', '', $login, false, $substitutions);
return true;
} else {
msg($lang['regmailfail'], -1);
diff --git a/inc/changelog.php b/inc/changelog.php
index 688aebfd6..9768fea51 100644
--- a/inc/changelog.php
+++ b/inc/changelog.php
@@ -258,6 +258,7 @@ function getRecentsSince($from,$to=null,$ns='',$flags=0){
} else {
$lines = @file($conf['changelog']);
}
+ if(!$lines) return $recent;
// we start searching at the end of the list
$lines = array_reverse($lines);
diff --git a/inc/common.php b/inc/common.php
index 3c40a47dc..bc49e76b2 100644
--- a/inc/common.php
+++ b/inc/common.php
@@ -107,9 +107,11 @@ function pageinfo() {
$info['isadmin'] = false;
$info['ismanager'] = false;
if(isset($_SERVER['REMOTE_USER'])) {
+ $sub = new Subscription();
+
$info['userinfo'] = $USERINFO;
$info['perm'] = auth_quickaclcheck($ID);
- $info['subscribed'] = get_info_subscribed();
+ $info['subscribed'] = $sub->user_subscription();
$info['client'] = $_SERVER['REMOTE_USER'];
if($info['perm'] == AUTH_ADMIN) {
@@ -320,15 +322,13 @@ function idfilter($id, $ue = true) {
if($conf['useslash'] && $conf['userewrite']) {
$id = strtr($id, ':', '/');
} elseif(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' &&
- $conf['userewrite'] &&
- strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') === false
+ $conf['userewrite']
) {
$id = strtr($id, ':', ';');
}
if($ue) {
$id = rawurlencode($id);
$id = str_replace('%3A', ':', $id); //keep as colon
- $id = str_replace('%3B', ';', $id); //keep as semicolon
$id = str_replace('%2F', '/', $id); //keep as slash
}
return $id;
@@ -1105,90 +1105,31 @@ function saveOldRevision($id) {
* @author Andreas Gohr <andi@splitbrain.org>
*/
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, eg. whom to mail
if($who == 'admin') {
if(empty($conf['notify'])) return false; //notify enabled?
- $text = rawLocale('mailtext');
- $to = $conf['notify'];
- $bcc = '';
+ $tpl = 'mailtext';
+ $to = $conf['notify'];
} elseif($who == 'subscribers') {
- if(!$conf['subscribers']) return false; //subscribers enabled?
+ if(!actionOK('subscribe')) return false; //subscribers enabled?
if($conf['useacl'] && $_SERVER['REMOTE_USER'] && $minor) return false; //skip minors
$data = array('id' => $id, 'addresslist' => '', 'self' => false);
trigger_event(
'COMMON_NOTIFY_ADDRESSLIST', $data,
- 'subscription_addresslist'
+ array(new Subscription(), 'notifyaddresses')
);
- $bcc = $data['addresslist'];
- if(empty($bcc)) return false;
- $to = '';
- $text = rawLocale('subscr_single');
- } elseif($who == 'register') {
- if(empty($conf['registernotify'])) return false;
- $text = rawLocale('registermail');
- $to = $conf['registernotify'];
- $bcc = '';
+ $to = $data['addresslist'];
+ if(empty($to)) return false;
+ $tpl = 'subscr_single';
} else {
return false; //just to be safe
}
- // 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;
- } elseif($rev) {
- $subject = $lang['mail_changed'].' '.$id;
- $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;
- $hdf = new Diff(explode("\n", hsc($old_content)),
- explode("\n", hsc($new_content)));
- $dformat = new InlineDiffFormatter();
- $hdiff = $dformat->format($hdf);
- $hdiff = '<table>'.$hdiff.'</table>';
- $DIFF_INLINESTYLES = false;
- } else {
- $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();
+ $subscription = new Subscription();
+ return $subscription->send_diff($to, $tpl, $id, $rev, $summary);
}
/**
diff --git a/inc/html.php b/inc/html.php
index f4e6af663..5c1c75cf6 100644
--- a/inc/html.php
+++ b/inc/html.php
@@ -1390,8 +1390,7 @@ function html_edit(){
$data = array('form' => $form,
'wr' => $wr,
'media_manager' => true,
- 'target' => ($INPUT->has('target') && $wr &&
- $RANGE !== '') ? $INPUT->str('target') : 'section',
+ 'target' => ($INPUT->has('target') && $wr) ? $INPUT->str('target') : 'section',
'intro_locale' => $include);
if ($data['target'] !== 'section') {
diff --git a/inc/lang/ar/subscr_single.txt b/inc/lang/ar/subscr_single.txt
index 5c62aeaeb..611688415 100644
--- a/inc/lang/ar/subscr_single.txt
+++ b/inc/lang/ar/subscr_single.txt
@@ -15,7 +15,7 @@
لإلغاء إشعارات الصفحة,لُج الويكي في
@DOKUWIKIURL@ ثم زُر
-@NEWPAGE@
+@SUBSCRIBE@
وألغ الاشتراك من تغييرات الصفحة و/أو النطاق.
--
diff --git a/inc/lang/bg/subscr_single.txt b/inc/lang/bg/subscr_single.txt
index 7b26f8e96..a74a21fb8 100644
--- a/inc/lang/bg/subscr_single.txt
+++ b/inc/lang/bg/subscr_single.txt
@@ -14,7 +14,7 @@
Нова версия: @NEWPAGE@
Ако желаете да прекратите уведомяването за страницата трябва да се впишете на адрес @DOKUWIKIURL@, да посетите
-@NEWPAGE@
+@SUBSCRIBE@
и да прекратите абонамента за промени по страницата или именното пространство.
--
diff --git a/inc/lang/da/subscr_single.txt b/inc/lang/da/subscr_single.txt
index 64b14588c..cdc554513 100644
--- a/inc/lang/da/subscr_single.txt
+++ b/inc/lang/da/subscr_single.txt
@@ -15,7 +15,7 @@ Ny Revision: @NEWPAGE@
For at slå side notifikationer fra, skal du logge ind på
@DOKUWIKIURL@ og besøge
-@NEWPAGE@
+@SUBSCRIBE@
og slå abonnoment for side / navnerum ændringer fra.
--
diff --git a/inc/lang/de-informal/subscr_single.txt b/inc/lang/de-informal/subscr_single.txt
index 3c557bc17..6e3f58b9f 100644
--- a/inc/lang/de-informal/subscr_single.txt
+++ b/inc/lang/de-informal/subscr_single.txt
@@ -15,7 +15,7 @@ Neue Revision: @NEWPAGE@
Um das Abonnement für diese Seite aufzulösen, melde dich im Wiki an
@DOKUWIKIURL@, besuche dann
-@NEWPAGE@
+@SUBSCRIBE@
und klicke auf den Link 'Aboverwaltung'.
--
diff --git a/inc/lang/de/subscr_single.txt b/inc/lang/de/subscr_single.txt
index f3e1cd393..da9914e50 100644
--- a/inc/lang/de/subscr_single.txt
+++ b/inc/lang/de/subscr_single.txt
@@ -15,7 +15,7 @@ Neue Revision: @NEWPAGE@
Um das Abonnement für diese Seite aufzulösen, melden Sie sich im Wiki an
@DOKUWIKIURL@, besuchen dann
-@NEWPAGE@
+@SUBSCRIBE@
und klicken auf die Taste 'Aboverwaltung'.
--
diff --git a/inc/lang/en/subscr_single.txt b/inc/lang/en/subscr_single.txt
index 673c4c32a..0bc310e04 100644
--- a/inc/lang/en/subscr_single.txt
+++ b/inc/lang/en/subscr_single.txt
@@ -15,7 +15,7 @@ New Revision: @NEWPAGE@
To cancel the page notifications, log into the wiki at
@DOKUWIKIURL@ then visit
-@NEWPAGE@
+@SUBSCRIBE@
and unsubscribe page and/or namespace changes.
--
diff --git a/inc/lang/eo/subscr_single.txt b/inc/lang/eo/subscr_single.txt
index 431fd0251..e4847e8ab 100644
--- a/inc/lang/eo/subscr_single.txt
+++ b/inc/lang/eo/subscr_single.txt
@@ -15,7 +15,7 @@ Nova versio: @NEWPAGE@
Por nuligi la paĝinformojn, ensalutu la vikion ĉe
@DOKUWIKIURL@, poste iru al
-@NEWPAGE@
+@SUBSCRIBE@
kaj malabonu la paĝajn kaj/aŭ nomspacajn ŝanĝojn.
--
diff --git a/inc/lang/he/subscr_single.txt b/inc/lang/he/subscr_single.txt
index 123b186c8..78b551e2f 100644
--- a/inc/lang/he/subscr_single.txt
+++ b/inc/lang/he/subscr_single.txt
@@ -14,7 +14,7 @@
לביטול התרעות בנוגע לעמוד, יש להיכנס לאתר הוויקי בכתובת
@DOKUWIKIURL@ ואז לבקר בדף
-@NEWPAGE@
+@SUBSCRIBE@
ולבטל את המינוי לקבלת שינויים בדף ו/או במרחב השם.
--
diff --git a/inc/lang/ia/subscr_single.txt b/inc/lang/ia/subscr_single.txt
index 3d6ef7103..445df197c 100644
--- a/inc/lang/ia/subscr_single.txt
+++ b/inc/lang/ia/subscr_single.txt
@@ -15,7 +15,7 @@ Version nove: @NEWPAGE@
Pro cancellar le notificationes de paginas, aperi un session al wiki a
@DOKUWIKIURL@ postea visita
-@NEWPAGE@
+@SUBSCRIBE@
e cancella tu subscription al modificationes in paginas e/o spatios de nomines.
--
diff --git a/inc/lang/it/subscr_single.txt b/inc/lang/it/subscr_single.txt
index 8cde8ea0f..a8649a4ef 100644
--- a/inc/lang/it/subscr_single.txt
+++ b/inc/lang/it/subscr_single.txt
@@ -15,7 +15,7 @@ Nuova revisione: @NEWPAGE@
Per non ricevere più queste notifiche, collegati al
wiki all'indirizzo @DOKUWIKIURL@ e poi visita
-@NEWPAGE@
+@SUBSCRIBE@
e rimuovi la sottoscrizione alle modifiche della
pagina o categoria.
diff --git a/inc/lang/ko/subscr_single.txt b/inc/lang/ko/subscr_single.txt
index 6bd1885e6..2679db393 100644
--- a/inc/lang/ko/subscr_single.txt
+++ b/inc/lang/ko/subscr_single.txt
@@ -14,7 +14,7 @@
새 버전 : @NEWPAGE@
이 문서의 알림을 취소하려면, @DOKUWIKIURL@에 로그인한 뒤
-@NEWPAGE@ 문서를 방문하여 문서나 이름공간의 구독을 취소하세요.
+@SUBSCRIBE@ 문서를 방문하여 문서나 이름공간의 구독을 취소하세요.
--
@DOKUWIKIURL@의 DokuWiki가 자동으로 만들어낸 메일입니다. \ No newline at end of file
diff --git a/inc/lang/la/subscr_digest.txt b/inc/lang/la/subscr_digest.txt
index 629213359..32d378a7e 100644
--- a/inc/lang/la/subscr_digest.txt
+++ b/inc/lang/la/subscr_digest.txt
@@ -12,7 +12,7 @@ Noua recensio: @NEWPAGE@
Ut paginae adnotationes deleas, in uicem ineas in
@DOKUWIKIURL@, deinde uideas
-@NEWPAGE@
+@SUBSCRIBE@
et paginarum generum optiones mutes.
--
diff --git a/inc/lang/la/subscr_single.txt b/inc/lang/la/subscr_single.txt
index 7839791ea..14285014c 100644
--- a/inc/lang/la/subscr_single.txt
+++ b/inc/lang/la/subscr_single.txt
@@ -15,7 +15,7 @@ Noua recensio: @NEWPAGE@
Ut paginae adnotationes deleas, in uicem ineas in
@DOKUWIKIURL@, deinde uideas
-@NEWPAGE@
+@SUBSCRIBE@
et paginarum et\aut generum optiones mutasa.
--
diff --git a/inc/lang/no/subscr_digest.txt b/inc/lang/no/subscr_digest.txt
index 6afd0cc5c..670d39d32 100644
--- a/inc/lang/no/subscr_digest.txt
+++ b/inc/lang/no/subscr_digest.txt
@@ -12,7 +12,7 @@ Ny versjon: @NEWPAGE@
For å avslutte varslingen, logg inn på
@DOKUWIKIURL@ og gå til
-@NEWPAGE@
+@SUBSCRIBE@
og avslutt abonnementet på endringer av siden eller i navnerommet.
--
diff --git a/inc/lang/no/subscr_list.txt b/inc/lang/no/subscr_list.txt
index 72cd307cb..860d88d2a 100644
--- a/inc/lang/no/subscr_list.txt
+++ b/inc/lang/no/subscr_list.txt
@@ -9,7 +9,7 @@ Her er endringene:
For å avslutte varslinga, logg inn på
@DOKUWIKIURL@ og gå til
-@NEWPAGE@
+@SUBSCRIBE@
og avslutt abonnementet på endringer av sida eller i navnerommet.
--
diff --git a/inc/lang/no/subscr_single.txt b/inc/lang/no/subscr_single.txt
index 25296da58..b26b3a879 100644
--- a/inc/lang/no/subscr_single.txt
+++ b/inc/lang/no/subscr_single.txt
@@ -15,7 +15,7 @@ Ny versjon: @NEWPAGE@
For å avslutte varslingen, logg inn på
@DOKUWIKIURL@, gå til
-@NEWPAGE@
+@SUBSCRIBE@
og avslutt abonnementet på endringer av siden eller i navnerommet.
--
diff --git a/inc/lang/pt/subscr_single.txt b/inc/lang/pt/subscr_single.txt
index 1187b5911..469c6bfb1 100644
--- a/inc/lang/pt/subscr_single.txt
+++ b/inc/lang/pt/subscr_single.txt
@@ -15,7 +15,7 @@ Revisão Nova: @NEWPAGE@
Para cancelar as notificações de página, inicie sessão no wiki em
@DOKUWIKIURL@, visite
-@NEWPAGE@
+@SUBSCRIBE@
e des-subscreva às alterações de página e/ou espaço de nome.
--
diff --git a/inc/lang/sq/subscr_single.txt b/inc/lang/sq/subscr_single.txt
index 90520be4f..df28ee176 100644
--- a/inc/lang/sq/subscr_single.txt
+++ b/inc/lang/sq/subscr_single.txt
@@ -15,7 +15,7 @@ Rishikimi i ri: @NEWPAGE@
Për të fshirë lajmërimet e faqes, hyni në wiki tek
@DOKUWIKIURL@ dhe pastaj vizitoni
-@NEWPAGE@
+@SUBSCRIBE@
dhe fshini ndryshimet e faqes dhe/ose hapësirës së emrit.
--
diff --git a/inc/load.php b/inc/load.php
index 49c307054..7fd9fc9d0 100644
--- a/inc/load.php
+++ b/inc/load.php
@@ -82,6 +82,7 @@ function load_autoload($name){
'Mailer' => DOKU_INC.'inc/Mailer.class.php',
'RemoteAPI' => DOKU_INC.'inc/remote.php',
'RemoteAPICore' => DOKU_INC.'inc/RemoteAPICore.php',
+ 'Subscription' => DOKU_INC.'inc/subscription.php',
'DokuWiki_Action_Plugin' => DOKU_PLUGIN.'action.php',
'DokuWiki_Admin_Plugin' => DOKU_PLUGIN.'admin.php',
diff --git a/inc/plugin.php b/inc/plugin.php
index e4bba989d..153e89407 100644
--- a/inc/plugin.php
+++ b/inc/plugin.php
@@ -81,8 +81,8 @@ class DokuWiki_Plugin {
* retrieve a language dependent file and pass to xhtml renderer for display
* plugin equivalent of p_locale_xhtml()
*
- * @param $id id of language dependent wiki page
- * @return string parsed contents of the wiki page in xhtml format
+ * @param string $id id of language dependent wiki page
+ * @return string parsed contents of the wiki page in xhtml format
*/
function locale_xhtml($id) {
return p_cached_output($this->localFN($id));
diff --git a/inc/search.php b/inc/search.php
index 1cecfd5ec..53bd240e8 100644
--- a/inc/search.php
+++ b/inc/search.php
@@ -247,11 +247,16 @@ function search_pagename(&$data,$base,$file,$type,$lvl,$opts){
* @author Andreas Gohr <andi@splitbrain.org>
*/
function search_allpages(&$data,$base,$file,$type,$lvl,$opts){
+ if(isset($opts['depth']) && $opts['depth']){
+ $parts = explode('/',ltrim($file,'/'));
+ if(($type == 'd' && count($parts) > $opts['depth'])
+ || ($type != 'd' && count($parts) > $opts['depth'] + 1)){
+ return false; // depth reached
+ }
+ }
+
//we do nothing with directories
if($type == 'd'){
- if(!$opts['depth']) return true; // recurse forever
- $parts = explode('/',ltrim($file,'/'));
- if(count($parts) == $opts['depth']) return false; // depth reached
return true;
}
diff --git a/inc/subscription.php b/inc/subscription.php
index 6b201c266..62cfd1509 100644
--- a/inc/subscription.php
+++ b/inc/subscription.php
@@ -1,414 +1,627 @@
<?php
/**
- * Utilities for handling (email) subscriptions
- *
- * The public interface of this file consists of the functions
- * - subscription_find
- * - subscription_send_digest
- * - subscription_send_list
- * - subscription_set
- * - get_info_subscribed
- * - subscription_addresslist
- * - subscription_lock
- * - subscription_unlock
+ * 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 {
-/**
- * Get the name of the metafile tracking subscriptions to target page or
- * namespace
- *
- * @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
- */
-function subscription_filename($id) {
- $meta_fname = '.mlist';
- if ((substr($id, -1, 1) === ':')) {
- $meta_froot = getNS($id);
- $meta_fname = '/' . $meta_fname;
- } else {
- $meta_froot = $id;
+ /**
+ * Check if subscription system is enabled
+ *
+ * @return bool
+ */
+ public function isenabled() {
+ return actionOK('subscribe');
}
- return metaFN((string) $meta_froot, $meta_fname);
-}
-
-/**
- * Lock subscription info for an 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
- */
-function subscription_lock_filename ($id){
- global $conf;
- return $conf['lockdir'].'/_subscr_' . md5($id) . '.lock';
-}
-/**
- * Creates a lock file for writing subscription data
- *
- * @todo add lock time parameter to io_lock() and use this instead
- * @param $id
- * @return bool
- */
-function subscription_lock($id) {
- global $conf;
- $lock = subscription_lock_filename($id);
-
- if (is_dir($lock) && time()-@filemtime($lock) > 60*5) {
- // looks like a stale lock - remove it
- @rmdir($lock);
+ /**
+ * 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);
}
- // try creating the lock directory
- if (!@mkdir($lock,$conf['dmode'])) {
- return false;
- }
+ /**
+ * 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;
- if($conf['dperm']) chmod($lock, $conf['dperm']);
- return true;
-}
+ $lock = $conf['lockdir'].'/_subscr_'.md5($id).'.lock';
-/**
- * Unlock subscription info for an 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 bool
- */
-function subscription_unlock($id) {
- $lockf = subscription_lock_filename($id);
- return @rmdir($lockf);
-}
+ if(is_dir($lock) && time() - @filemtime($lock) > 60 * 5) {
+ // looks like a stale lock - remove it
+ @rmdir($lock);
+ }
-/**
- * Set subscription information
- *
- * Allows to set subscription information for permanent storage in meta files.
- * Subscriptions consist of a target object, a subscribing user, a subscribe
- * style and optional data.
- * A subscription may be deleted by specifying an empty subscribe style.
- * Only one subscription per target and user is allowed.
- * The function returns false on error, otherwise true. Note that no error is
- * returned if a subscription should be deleted but the user is not subscribed
- * and the subscription meta file exists.
- *
- * @author Adrian Lang <lang@cosmocode.de>
- *
- * @param string $user The subscriber or unsubscriber
- * @param string $page The target object (page or namespace), specified by
- * id; Namespaces are identified by a trailing colon.
- * @param string $style The subscribe style; DokuWiki currently implements
- * “every”, “digest”, and “list”.
- * @param string $data An optional data blob
- * @param bool $overwrite Whether an existing subscription may be overwritten
- * @return bool
- */
-function subscription_set($user, $page, $style, $data = null,
- $overwrite = false) {
- global $lang;
- if (is_null($style)) {
- // Delete subscription.
- $file = subscription_filename($page);
- if (!@file_exists($file)) {
- msg(sprintf($lang['subscr_not_subscribed'], $user,
- prettyprint_id($page)), -1);
+ // try creating the lock directory
+ if(!@mkdir($lock, $conf['dmode'])) {
return false;
}
- // io_deleteFromFile does not return false if no line matched.
- return io_deleteFromFile($file,
- subscription_regex(array('user' => auth_nameencode($user))),
- true);
+ if($conf['dperm']) chmod($lock, $conf['dperm']);
+ return true;
}
- // Delete subscription if one exists and $overwrite is true. If $overwrite
- // is false, fail.
- $subs = subscription_find($page, array('user' => $user));
- if (count($subs) > 0 && isset($subs[$page])) {
- if (!$overwrite) {
- msg(sprintf($lang['subscr_already_subscribed'], $user,
- prettyprint_id($page)), -1);
- return false;
+ /**
+ * 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+';
}
- // Fail if deletion failed, else continue.
- if (!subscription_set($user, $page, null)) {
- return false;
+ if($style === '') {
+ $style = '\S+';
+ $sopt = '?';
+ }
+ if($data === '') {
+ $data = '\S+';
+ $dopt = '?';
}
- }
- $file = subscription_filename($page);
- $content = auth_nameencode($user) . ' ' . $style;
- if (!is_null($data)) {
- $content .= ' ' . $data;
+ // assemble
+ return "/^($user)(?:\\s+($style))$sopt(?:\\s+($data))$dopt$/";
}
- return io_saveFile($file, $content . "\n", true);
-}
-/**
- * Recursively search for matching subscriptions
- *
- * This function searches all relevant subscription files for a page or
- * namespace.
- *
- * @author Adrian Lang <lang@cosmocode.de>
- * @see function subscription_regex for $pre documentation
- *
- * @param string $page The target object’s (namespace or page) id
- * @param array $pre A hash of predefined values
- * @return array
- */
-function subscription_find($page, $pre) {
- // Construct list of files which may contain relevant subscriptions.
- $filenames = array(':' => subscription_filename(':'));
- do {
- $filenames[$page] = subscription_filename($page);
- $page = getNS(rtrim($page, ':')) . ':';
- } while ($page !== ':');
-
- // Handle files.
- $matches = array();
- foreach ($filenames as $cur_page => $filename) {
- if (!@file_exists($filename)) {
- continue;
- }
- $subscriptions = file($filename);
- foreach ($subscriptions as $subscription) {
- if (strpos($subscription, ' ') === false) {
- // This is an old subscription file.
- $subscription = trim($subscription) . " every\n";
- }
+ /**
+ * 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();
- list($user, $rest) = explode(' ', $subscription, 2);
- $subscription = rawurldecode($user) . " " . $rest;
+ // 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 !== ':');
- if (preg_match(subscription_regex($pre), $subscription,
- $line_matches) === 0) {
- continue;
- }
- $match = array_slice($line_matches, 1);
- if (!isset($matches[$cur_page])) {
- $matches[$cur_page] = array();
+ $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
}
- $matches[$cur_page][] = $match;
}
+ return array_reverse($result);
}
- return array_reverse($matches);
-}
-/**
- * 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”.
- *
- * @author Adrian Lang <lang@cosmocode.de>
- */
-function get_info_subscribed() {
- global $ID;
- global $conf;
- if (!$conf['subscribers']) {
- return false;
+ /**
+ * 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);
}
- $subs = subscription_find($ID, array('user' => $_SERVER['REMOTE_USER']));
- if (count($subs) === 0) {
- return false;
+ /**
+ * 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);
}
- $_ret = array();
- foreach ($subs as $target => $subs_data) {
- $new = array('target' => $target,
- 'style' => $subs_data[0][0]);
- if (count($subs_data[0]) > 1) {
- $new['data'] = $subs_data[0][1];
+ /**
+ * 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;
+ if(!$id) $id = $ID;
+ if(!$user) $user = $_SERVER['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]
+ );
}
- $_ret[] = $new;
+
+ return $result;
}
- return $_ret;
-}
+ /**
+ * 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;
-/**
- * Construct a regular expression parsing a subscription definition line
- *
- * @author Adrian Lang <lang@cosmocode.de>
- *
- * @param array $pre A hash of predefined values; “user”, “style”, and
- * “data” may be set to limit the results to
- * subscriptions matching these parameters. If
- * “escaped” is true, these fields are inserted into the
- * regular expression without escaping.
- *
- * @return string complete regexp including delimiters
- */
-function subscription_regex($pre = array()) {
- if (!isset($pre['escaped']) || $pre['escaped'] === false) {
- $pre = array_map('preg_quote_cb', $pre);
+ /** @var auth_basic $auth */
+ global $auth;
+ global $conf;
+ global $USERINFO;
+ $count = 0;
+
+ $subscriptions = $this->subscribers($page, null, array('digest', 'list'));
+
+ // remember current user info
+ $olduinfo = $USERINFO;
+ $olduser = $_SERVER['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);
+ $_SERVER['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 &&
+ ($_SERVER['REMOTE_USER'] === $rev['user'] ||
+ $rev['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT)) {
+ $rev = getRevisions($rev['id'], $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;
+ $_SERVER['REMOTE_USER'] = $olduser;
+ return $count;
}
- foreach (array('user', 'style', 'data') as $key) {
- if (!isset($pre[$key])) {
- $pre[$key] = '(\S+)';
+
+ /**
+ * 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", hsc($old_content)),
+ explode("\n", hsc($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;
+
+ return $this->send(
+ $subscriber_mail, $subject, $id,
+ $template, $trep, $hrep
+ );
}
- return '/^' . $pre['user'] . '(?: ' . $pre['style'] .
- '(?: ' . $pre['data'] . ')?)?$/';
-}
-/**
- * Return a string with the email addresses of all the
- * users subscribed to a page
- *
- * This is the default action for COMMON_NOTIFY_ADDRESSLIST.
- *
- * @author Steven Danz <steven-danz@kc.rr.com>
- * @author Adrian Lang <lang@cosmocode.de>
- *
- * @todo this does NOT return a string but uses a reference to write back, either fix function or docs
- * @param array $data Containing $id (the page id), $self (whether the author
- * should be notified, $addresslist (current email address
- * list)
- * @return string
- */
-function subscription_addresslist(&$data){
- global $conf;
- /** @var auth_basic $auth */
- global $auth;
+ /**
+ * 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;
- $id = $data['id'];
- $self = $data['self'];
- $addresslist = $data['addresslist'];
+ $trep = array(
+ 'NEWUSER' => $login,
+ 'NEWNAME' => $fullname,
+ 'NEWEMAIL' => $email,
+ );
- if (!$conf['subscribers'] || $auth === null) {
- return '';
+ return $this->send(
+ $conf['registernotify'],
+ 'new_user',
+ $login,
+ 'registermail',
+ $trep
+ );
}
- $pres = array('style' => 'every', 'escaped' => true);
- if (!$self && isset($_SERVER['REMOTE_USER'])) {
- $pres['user'] = '((?!' . preg_quote_cb($_SERVER['REMOTE_USER']) .
- '(?: |$))\S+)';
+
+ /**
+ * 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 array $id The ID
+ * @param int $lastupdate Time of the last notification
+ * @return bool
+ */
+ protected function send_digest($subscriber_mail, $id, $lastupdate) {
+ $n = 0;
+ do {
+ $rev = getRevisions($id, $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
+ );
}
- $subs = subscription_find($id, $pres);
- $emails = array();
- foreach ($subs as $by_targets) {
- foreach ($by_targets as $sub) {
- $info = $auth->getUserData($sub[0]);
- if ($info === false) continue;
- $level = auth_aclcheck($id, $sub[0], $info['grps']);
- if ($level >= AUTH_READ) {
- if (strcasecmp($info['mail'], $conf['notify']) != 0) {
- $emails[$sub[0]] = $info['mail'];
- }
- }
+
+ /**
+ * 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
+ );
}
- $data['addresslist'] = trim($addresslist . ',' . implode(',', $emails), ',');
-}
-/**
- * Send a digest mail
- *
- * Sends a digest mail showing a bunch of changes.
- *
- * @author Adrian Lang <lang@cosmocode.de>
- *
- * @param string $subscriber_mail The target mail address
- * @param array $id The ID
- * @param int $lastupdate Time of the last notification
- */
-function subscription_send_digest($subscriber_mail, $id, $lastupdate) {
- $n = 0;
- do {
- $rev = getRevisions($id, $n++, 1);
- $rev = (count($rev) > 0) ? $rev[0] : null;
- } while (!is_null($rev) && $rev > $lastupdate);
-
- $replaces = array('NEWPAGE' => wl($id, '', true, '&'),
- 'SUBSCRIBE' => wl($id, array('do' => 'subscribe'), true, '&'));
- if (!is_null($rev)) {
- $subject = 'changed';
- $replaces['OLDPAGE'] = wl($id, "rev=$rev", true, '&');
- $df = new Diff(explode("\n", rawWiki($id, $rev)),
- explode("\n", rawWiki($id)));
- $dformat = new UnifiedDiffFormatter();
- $replaces['DIFF'] = $dformat->format($df);
- } else {
- $subject = 'newpage';
- $replaces['OLDPAGE'] = 'none';
- $replaces['DIFF'] = rawWiki($id);
+ /**
+ * 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
+ * @return bool
+ */
+ protected function send($subscriber_mail, $subject, $context, $template, $trep, $hrep = null) {
+ 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);
+ }
+ return $mail->send();
}
- subscription_send($subscriber_mail, $replaces, $subject, $id,
- 'subscr_digest');
-}
-/**
- * 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
- */
-function subscription_send_list($subscriber_mail, $ids, $ns_id) {
- if (count($ids) === 0) return;
- global $conf;
- $list = '';
- foreach ($ids as $id) {
- $list .= '* ' . wl($id, array(), true) . NL;
+ /**
+ * 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 $id (the page id), $self (whether the author
+ * should be notified, $addresslist (current email address
+ * list)
+ */
+ public function notifyaddresses(&$data) {
+ if(!$this->isenabled()) return;
+
+ /** @var auth_basic $auth */
+ global $auth;
+ global $conf;
+
+ $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 == $_SERVER['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), ',');
}
- subscription_send($subscriber_mail,
- array('DIFF' => rtrim($list),
- 'SUBSCRIBE' => wl($ns_id . $conf['start'],
- array('do' => 'subscribe'),
- true, '&')),
- 'subscribe_list',
- prettyprint_id($ns_id),
- 'subscr_list');
}
/**
- * Helper function for sending a mail
+ * Compatibility wrapper around Subscription:notifyaddresses
*
- * @author Adrian Lang <lang@cosmocode.de>
+ * for plugins emitting COMMON_NOTIFY_ADDRESSLIST themselves and relying on on this to
+ * be the default handler
*
- * @param string $subscriber_mail The target mail address
- * @param array $replaces Predefined parameters used to parse the
- * template
- * @param string $subject The lang id of the mail subject (without the
- * prefix “mail_”)
- * @param string $id The page or namespace id
- * @param string $template The name of the mail template
- * @return bool
+ * @param array $data event data for
+ *
+ * @deprecated 2012-12-07
*/
-function subscription_send($subscriber_mail, $replaces, $subject, $id, $template) {
- global $lang;
- global $conf;
-
- $text = rawLocale($template);
- $trep = array_merge($replaces, array('PAGE' => $id));
- $hrep = $trep;
- $hrep['DIFF'] = nl2br(htmlspecialchars($hrep['DIFF']));
-
- $subject = $lang['mail_' . $subject] . ' ' . $id;
- $mail = new Mailer();
- $mail->bcc($subscriber_mail);
- $mail->subject($subject);
- $mail->setBody($text,$trep,$hrep);
- $mail->from($conf['mailfromnobody']);
- $mail->setHeader(
- 'List-Unsubscribe',
- '<'.wl($id,array('do'=>'subscribe'),true,'&').'>',
- false
- );
- return $mail->send();
-}
+function subscription_addresslist(&$data) {
+ $sub = new Subscription();
+ $sub->notifyaddresses($data);
+} \ No newline at end of file
diff --git a/lib/exe/indexer.php b/lib/exe/indexer.php
index 28ee5331f..27576f76d 100644
--- a/lib/exe/indexer.php
+++ b/lib/exe/indexer.php
@@ -169,97 +169,20 @@ function runSitemapper(){
* @author Adrian Lang <lang@cosmocode.de>
*/
function sendDigest() {
- echo 'sendDigest(): started'.NL;
- global $ID;
global $conf;
- if (!$conf['subscribers']) {
+ global $ID;
+
+ echo 'sendDigest(): started'.NL;
+ if(!actionOK('subscribe')) {
echo 'sendDigest(): disabled'.NL;
return false;
}
- $subscriptions = subscription_find($ID, array('style' => '(digest|list)',
- 'escaped' => true));
- /** @var auth_basic $auth */
- global $auth;
- global $lang;
- global $conf;
- global $USERINFO;
-
- $sent = false;
-
- // remember current user info
- $olduinfo = $USERINFO;
- $olduser = $_SERVER['REMOTE_USER'];
-
- foreach($subscriptions as $id => $users) {
- if (!subscription_lock($id)) {
- continue;
- }
- foreach($users as $data) {
- list($user, $style, $lastupdate) = $data;
- $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);
- $_SERVER['REMOTE_USER'] = $user;
- if ($USERINFO === false) {
- continue;
- }
-
- if (substr($id, -1, 1) === ':') {
- // The subscription target is a namespace
- $changes = getRecentsSince($lastupdate, null, getNS($id));
- } else {
- if(auth_quickaclcheck($id) < AUTH_READ) continue;
-
- $meta = p_get_metadata($id);
- $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 &&
- ($_SERVER['REMOTE_USER'] === $rev['user'] ||
- $rev['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT)) {
- $rev = getRevisions($rev['id'], $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'];
- }
- }
-
- if ($style === 'digest') {
- foreach($change_ids as $change_id) {
- subscription_send_digest($USERINFO['mail'], $change_id,
- $lastupdate);
- $sent = true;
- }
- } elseif ($style === 'list') {
- subscription_send_list($USERINFO['mail'], $change_ids, $id);
- $sent = true;
- }
- // TODO: Handle duplicate subscriptions.
-
- // Update notification time.
- subscription_set($user, $id, $style, time(), true);
- }
- subscription_unlock($id);
- }
+ $sub = new Subscription();
+ $sent = $sub->send_bulk($ID);
- // restore current user info
- $USERINFO = $olduinfo;
- $_SERVER['REMOTE_USER'] = $olduser;
+ echo "sendDigest(): sent $sent mails".NL;
echo 'sendDigest(): finished'.NL;
- return $sent;
+ return (bool) $sent;
}
/**
diff --git a/lib/scripts/fileuploaderextended.js b/lib/scripts/fileuploaderextended.js
index 4abd63bef..0ba7a0525 100644
--- a/lib/scripts/fileuploaderextended.js
+++ b/lib/scripts/fileuploaderextended.js
@@ -173,7 +173,7 @@ qq.extend(qq.FileUploaderExtended.prototype, {
if (result.success){
qq.addClass(item, this._classes.success);
- $link = '<a href="' + result.link + '" name="h_:' + result.id + '" class="select">' + nameInput.value + '</a>';
+ $link = '<a href="' + result.link + '" id="h_:' + result.id + '" class="select">' + nameInput.value + '</a>';
jQuery(fileElement).html($link);
} else {
diff --git a/lib/scripts/toolbar.js b/lib/scripts/toolbar.js
index 04d30c1a6..059a4ba5c 100644
--- a/lib/scripts/toolbar.js
+++ b/lib/scripts/toolbar.js
@@ -94,7 +94,7 @@ function tb_format(btn, props, edid) {
* @author Andreas Gohr <andi@splitbrain.org>
*/
function tb_formatln(btn, props, edid) {
- var sample = props.title || props.sample,
+ var sample = props.sample || props.title,
opts,
selection = getSelection(jQuery('#'+edid)[0]);