source: documentation/trunk/packages/dokuwiki-2011-05-25a/inc/subscription.php@ 25027

Last change on this file since 25027 was 25027, checked in by jmt12, 12 years ago

Adding the packages directory, and within it a configured version of dokuwiki all ready to run

File size: 12.8 KB
Line 
1<?php
2/**
3 * Utilities for handling (email) subscriptions
4 *
5 * The public interface of this file consists of the functions
6 * - subscription_find
7 * - subscription_send_digest
8 * - subscription_send_list
9 * - subscription_set
10 * - get_info_subscribed
11 * - subscription_addresslist
12 * - subscription_lock
13 * - subscription_unlock
14 *
15 * @author Adrian Lang <[email protected]>
16 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
17 */
18
19/**
20 * Get the name of the metafile tracking subscriptions to target page or
21 * namespace
22 *
23 * @param string $id The target page or namespace, specified by id; Namespaces
24 * are identified by appending a colon.
25 *
26 * @author Adrian Lang <[email protected]>
27 */
28function subscription_filename($id) {
29 $meta_fname = '.mlist';
30 if ((substr($id, -1, 1) === ':')) {
31 $meta_froot = getNS($id);
32 $meta_fname = '/' . $meta_fname;
33 } else {
34 $meta_froot = $id;
35 }
36 return metaFN((string) $meta_froot, $meta_fname);
37}
38
39/**
40 * Lock subscription info for an ID
41 *
42 * @param string $id The target page or namespace, specified by id; Namespaces
43 * are identified by appending a colon.
44 *
45 * @author Adrian Lang <[email protected]>
46 */
47function subscription_lock_filename ($id){
48 global $conf;
49 return $conf['lockdir'].'/_subscr_' . md5($id) . '.lock';
50}
51
52function subscription_lock($id) {
53 global $conf;
54 $lock = subscription_lock_filename($id);
55
56 if (is_dir($lock) && time()-@filemtime($lock) > 60*5) {
57 // looks like a stale lock - remove it
58 @rmdir($lock);
59 }
60
61 // try creating the lock directory
62 if (!@mkdir($lock,$conf['dmode'])) {
63 return false;
64 }
65
66 if($conf['dperm']) chmod($lock, $conf['dperm']);
67 return true;
68}
69
70/**
71 * Unlock subscription info for an ID
72 *
73 * @param string $id The target page or namespace, specified by id; Namespaces
74 * are identified by appending a colon.
75 *
76 * @author Adrian Lang <[email protected]>
77 */
78function subscription_unlock($id) {
79 $lockf = subscription_lock_filename($id);
80 return @rmdir($lockf);
81}
82
83/**
84 * Set subscription information
85 *
86 * Allows to set subscription information for permanent storage in meta files.
87 * Subscriptions consist of a target object, a subscribing user, a subscribe
88 * style and optional data.
89 * A subscription may be deleted by specifying an empty subscribe style.
90 * Only one subscription per target and user is allowed.
91 * The function returns false on error, otherwise true. Note that no error is
92 * returned if a subscription should be deleted but the user is not subscribed
93 * and the subscription meta file exists.
94 *
95 * @param string $user The subscriber or unsubscriber
96 * @param string $page The target object (page or namespace), specified by
97 * id; Namespaces are identified by a trailing colon.
98 * @param string $style The subscribe style; DokuWiki currently implements
99 * “every”, “digest”, and “list”.
100 * @param string $data An optional data blob
101 * @param bool $overwrite Whether an existing subscription may be overwritten
102 *
103 * @author Adrian Lang <[email protected]>
104 */
105function subscription_set($user, $page, $style, $data = null,
106 $overwrite = false) {
107 global $lang;
108 if (is_null($style)) {
109 // Delete subscription.
110 $file = subscription_filename($page);
111 if (!@file_exists($file)) {
112 msg(sprintf($lang['subscr_not_subscribed'], $user,
113 prettyprint_id($page)), -1);
114 return false;
115 }
116
117 // io_deleteFromFile does not return false if no line matched.
118 return io_deleteFromFile($file,
119 subscription_regex(array('user' => auth_nameencode($user))),
120 true);
121 }
122
123 // Delete subscription if one exists and $overwrite is true. If $overwrite
124 // is false, fail.
125 $subs = subscription_find($page, array('user' => $user));
126 if (count($subs) > 0 && array_pop(array_keys($subs)) === $page) {
127 if (!$overwrite) {
128 msg(sprintf($lang['subscr_already_subscribed'], $user,
129 prettyprint_id($page)), -1);
130 return false;
131 }
132 // Fail if deletion failed, else continue.
133 if (!subscription_set($user, $page, null)) {
134 return false;
135 }
136 }
137
138 $file = subscription_filename($page);
139 $content = auth_nameencode($user) . ' ' . $style;
140 if (!is_null($data)) {
141 $content .= ' ' . $data;
142 }
143 return io_saveFile($file, $content . "\n", true);
144}
145
146/**
147 * Recursively search for matching subscriptions
148 *
149 * This function searches all relevant subscription files for a page or
150 * namespace.
151 *
152 * @param string $page The target object’s (namespace or page) id
153 * @param array $pre A hash of predefined values
154 *
155 * @see function subscription_regex for $pre documentation
156 *
157 * @author Adrian Lang <[email protected]>
158 */
159function subscription_find($page, $pre) {
160 // Construct list of files which may contain relevant subscriptions.
161 $filenames = array(':' => subscription_filename(':'));
162 do {
163 $filenames[$page] = subscription_filename($page);
164 $page = getNS(rtrim($page, ':')) . ':';
165 } while ($page !== ':');
166
167 // Handle files.
168 $matches = array();
169 foreach ($filenames as $cur_page => $filename) {
170 if (!@file_exists($filename)) {
171 continue;
172 }
173 $subscriptions = file($filename);
174 foreach ($subscriptions as $subscription) {
175 if (strpos($subscription, ' ') === false) {
176 // This is an old subscription file.
177 $subscription = trim($subscription) . " every\n";
178 }
179
180 list($user, $rest) = explode(' ', $subscription, 2);
181 $subscription = rawurldecode($user) . " " . $rest;
182
183 if (preg_match(subscription_regex($pre), $subscription,
184 $line_matches) === 0) {
185 continue;
186 }
187 $match = array_slice($line_matches, 1);
188 if (!isset($matches[$cur_page])) {
189 $matches[$cur_page] = array();
190 }
191 $matches[$cur_page][] = $match;
192 }
193 }
194 return array_reverse($matches);
195}
196
197/**
198 * Get data for $INFO['subscribed']
199 *
200 * $INFO['subscribed'] is either false if no subscription for the current page
201 * and user is in effect. Else it contains an array of arrays with the fields
202 * “target”, “style”, and optionally “data”.
203 *
204 * @author Adrian Lang <[email protected]>
205 */
206function get_info_subscribed() {
207 global $ID;
208 global $conf;
209 if (!$conf['subscribers']) {
210 return false;
211 }
212
213 $subs = subscription_find($ID, array('user' => $_SERVER['REMOTE_USER']));
214 if (count($subs) === 0) {
215 return false;
216 }
217
218 $_ret = array();
219 foreach ($subs as $target => $subs_data) {
220 $new = array('target' => $target,
221 'style' => $subs_data[0][0]);
222 if (count($subs_data[0]) > 1) {
223 $new['data'] = $subs_data[0][1];
224 }
225 $_ret[] = $new;
226 }
227
228 return $_ret;
229}
230
231/**
232 * Construct a regular expression parsing a subscription definition line
233 *
234 * @param array $pre A hash of predefined values; “user”, “style”, and
235 * “data” may be set to limit the results to
236 * subscriptions matching these parameters. If
237 * “escaped” is true, these fields are inserted into the
238 * regular expression without escaping.
239 *
240 * @author Adrian Lang <[email protected]>
241 */
242function subscription_regex($pre = array()) {
243 if (!isset($pre['escaped']) || $pre['escaped'] === false) {
244 $pre = array_map('preg_quote_cb', $pre);
245 }
246 foreach (array('user', 'style', 'data') as $key) {
247 if (!isset($pre[$key])) {
248 $pre[$key] = '(\S+)';
249 }
250 }
251 return '/^' . $pre['user'] . '(?: ' . $pre['style'] .
252 '(?: ' . $pre['data'] . ')?)?$/';
253}
254
255/**
256 * Return a string with the email addresses of all the
257 * users subscribed to a page
258 *
259 * This is the default action for COMMON_NOTIFY_ADDRESSLIST.
260 *
261 * @param array $data Containing $id (the page id), $self (whether the author
262 * should be notified, $addresslist (current email address
263 * list)
264 *
265 * @author Steven Danz <[email protected]>
266 * @author Adrian Lang <[email protected]>
267 */
268function subscription_addresslist(&$data){
269 global $conf;
270 global $auth;
271
272 $id = $data['id'];
273 $self = $data['self'];
274 $addresslist = $data['addresslist'];
275
276 if (!$conf['subscribers'] || $auth === null) {
277 return '';
278 }
279 $pres = array('style' => 'every', 'escaped' => true);
280 if (!$self && isset($_SERVER['REMOTE_USER'])) {
281 $pres['user'] = '((?!' . preg_quote_cb($_SERVER['REMOTE_USER']) .
282 '(?: |$))\S+)';
283 }
284 $subs = subscription_find($id, $pres);
285 $emails = array();
286 foreach ($subs as $by_targets) {
287 foreach ($by_targets as $sub) {
288 $info = $auth->getUserData($sub[0]);
289 if ($info === false) continue;
290 $level = auth_aclcheck($id, $sub[0], $info['grps']);
291 if ($level >= AUTH_READ) {
292 if (strcasecmp($info['mail'], $conf['notify']) != 0) {
293 $emails[$sub[0]] = $info['mail'];
294 }
295 }
296 }
297 }
298 $data['addresslist'] = trim($addresslist . ',' . implode(',', $emails), ',');
299}
300
301/**
302 * Send a digest mail
303 *
304 * Sends a digest mail showing a bunch of changes.
305 *
306 * @param string $subscriber_mail The target mail address
307 * @param array $id The ID
308 * @param int $lastupdate Time of the last notification
309 *
310 * @author Adrian Lang <[email protected]>
311 */
312function subscription_send_digest($subscriber_mail, $id, $lastupdate) {
313 $n = 0;
314 do {
315 $rev = getRevisions($id, $n++, 1);
316 $rev = (count($rev) > 0) ? $rev[0] : null;
317 } while (!is_null($rev) && $rev > $lastupdate);
318
319 $replaces = array('NEWPAGE' => wl($id, '', true, '&'),
320 'SUBSCRIBE' => wl($id, array('do' => 'subscribe'), true, '&'));
321 if (!is_null($rev)) {
322 $subject = 'changed';
323 $replaces['OLDPAGE'] = wl($id, "rev=$rev", true, '&');
324 $df = new Diff(explode("\n", rawWiki($id, $rev)),
325 explode("\n", rawWiki($id)));
326 $dformat = new UnifiedDiffFormatter();
327 $replaces['DIFF'] = $dformat->format($df);
328 } else {
329 $subject = 'newpage';
330 $replaces['OLDPAGE'] = 'none';
331 $replaces['DIFF'] = rawWiki($id);
332 }
333 subscription_send($subscriber_mail, $replaces, $subject, $id,
334 'subscr_digest');
335}
336
337/**
338 * Send a list mail
339 *
340 * Sends a list mail showing a list of changed pages.
341 *
342 * @param string $subscriber_mail The target mail address
343 * @param array $ids Array of ids
344 * @param string $ns_id The id of the namespace
345 *
346 * @author Adrian Lang <[email protected]>
347 */
348function subscription_send_list($subscriber_mail, $ids, $ns_id) {
349 if (count($ids) === 0) return;
350 global $conf;
351 $list = '';
352 foreach ($ids as $id) {
353 $list .= '* ' . wl($id, array(), true) . NL;
354 }
355 subscription_send($subscriber_mail,
356 array('DIFF' => rtrim($list),
357 'SUBSCRIBE' => wl($ns_id . $conf['start'],
358 array('do' => 'subscribe'),
359 true, '&')),
360 'subscribe_list',
361 prettyprint_id($ns_id),
362 'subscr_list');
363}
364
365/**
366 * Helper function for sending a mail
367 *
368 * @param string $subscriber_mail The target mail address
369 * @param array $replaces Predefined parameters used to parse the
370 * template
371 * @param string $subject The lang id of the mail subject (without the
372 * prefix “mail_”)
373 * @param string $id The page or namespace id
374 * @param string $template The name of the mail template
375 *
376 * @author Adrian Lang <[email protected]>
377 */
378function subscription_send($subscriber_mail, $replaces, $subject, $id, $template) {
379 global $conf;
380
381 $text = rawLocale($template);
382 $replaces = array_merge($replaces, array('TITLE' => $conf['title'],
383 'DOKUWIKIURL' => DOKU_URL,
384 'PAGE' => $id));
385
386 foreach ($replaces as $key => $substitution) {
387 $text = str_replace('@'.strtoupper($key).'@', $substitution, $text);
388 }
389
390 global $lang;
391 $subject = $lang['mail_' . $subject] . ' ' . $id;
392 mail_send('', '['.$conf['title'].'] '. $subject, $text,
393 $conf['mailfrom'], '', $subscriber_mail);
394}
Note: See TracBrowser for help on using the repository browser.