]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/MailNotify.php
improve text
[SourceForge/phpwiki.git] / lib / MailNotify.php
1 <?php //-*-php-*-
2 rcs_id('$Id: MailNotify.php,v 1.4 2007-01-04 16:47:49 rurban Exp $');
3
4 /**
5  * Handle the pagelist pref[notifyPages] logic for users
6  * and notify => hash ( page => (userid => userhash) ) for pages.
7  * Generate notification emails.
8  *
9  * We add WikiDB handlers and register ourself there:
10  *   onChangePage, onDeletePage, onRenamePage
11  * Administrative actions:
12  *   [Watch] WatchPage - add a page, or delete watch handlers into the users 
13  *                       pref[notifyPages] slot.
14  *   My WatchList      - view or edit list/regex of pref[notifyPages].
15  *   EMailConfirm methods: send and verify
16  *
17  * Helper functions:
18  *   getPageChangeEmails
19  *   MailAdmin
20  *   ? handle emailed confirmation links (EmailSignup, ModeratedPage)
21  *
22  * @package MailNotify
23  * @author  Reini Urban
24  */
25
26 class MailNotify {
27
28     function MailNotify($pagename) {
29         $this->pagename = $pagename; /* which page */
30         $this->emails  = array();    /* to whch addresses */
31         $this->userids = array();    /* corresponding array of displayed names, 
32                                       dont display the email addersses */
33         /* from: from which the mail appears to be */
34         $this->from = $this->fromId();
35     }
36
37     function fromId() {
38         global $request;
39         return $request->_user->getId() . '@' .  $request->get('REMOTE_HOST');
40     }
41
42     function userEmail($userid, $doverify = true) {
43         global $request;
44         $u = $request->getUser();
45         if ($u->UserName() == $userid) { // lucky: current user
46             $prefs = $u->getPreferences();
47             $email = $prefs->get('email');
48             // do a dynamic emailVerified check update
49             if ($doverify and !$request->_prefs->get('emailVerified'))
50                 $email = '';
51         } else {  // not current user
52             if (ENABLE_USER_NEW) {
53                 $u = WikiUser($userid);
54                 $u->getPreferences();
55                 $prefs = &$u->_prefs;
56             } else {
57                 $u = new WikiUser($request, $userid);
58                 $prefs = $u->getPreferences();
59             }
60             $email = $prefs->get('email');
61             if ($doverify and !$prefs->get('emailVerified')) {
62                 $email = '';
63             }
64         }
65         return $email;
66     }
67
68     /**
69      * getPageChangeEmails($notify)
70      * @param  $notify: hash ( page => (userid => userhash) )
71      * @return array
72      *         unique array of ($emails, $userids)
73      */
74     function getPageChangeEmails($notify) {
75         global $request;
76         $emails = array(); $userids = array();
77         foreach ($notify as $page => $users) {
78             if (glob_match($page, $this->pagename)) {
79                 foreach ($users as $userid => $user) {
80                     if (!$user) { // handle the case for ModeratePage: 
81                                   // no prefs, just userid's.
82                         $emails[] = $this->userEmail($userid, false);
83                         $userids[] = $userid;
84                     } else {
85                         if (!empty($user['verified']) and !empty($user['email'])) {
86                             $emails[]  = $user['email'];
87                             $userids[] = $userid;
88                         } elseif (!empty($user['email'])) {
89                             // do a dynamic emailVerified check update
90                             $email = $this->userEmail($userid, true);
91                             if ($email) {
92                                 $notify[$page][$userid]['verified'] = 1;
93                                 $request->_dbi->set('notify', $notify);
94                                 $emails[] = $email;
95                                 $userids[] = $userid;
96                             }
97                         }
98                         // ignore verification
99                         /*
100                         if (DEBUG) {
101                             if (!in_array($user['email'],$emails))
102                                 $emails[] = $user['email'];
103                         }
104                         */
105                     }
106                 }
107             }
108         }
109         $this->emails = array_unique($emails);
110         $this->userids = array_unique($userids);
111         return array($this->emails, $this->userids);
112     }
113     
114     function sendMail($subject, $content, 
115                       $notice = false,
116                       $silent = false)
117     {
118         global $request;
119         $emails = $this->emails;
120         $from = $this->from;
121         if (!$notice) $notice = _("PageChange Notification of %s");
122         if (mail(array_shift($emails),
123                  "[".WIKI_NAME."] ".$subject, 
124                  $subject."\n".$content,
125                  "From: $from\r\nBcc: ".join(',', $emails)
126                  ))
127         {
128             if (!$silent)
129                 trigger_error(sprintf($notice, $this->pagename)
130                               . " "
131                               . sprintf(_("sent to %s"), join(',',$this->userids)),
132                               E_USER_NOTICE);
133             return true;
134         } else {
135             trigger_error(sprintf($notice, $this->pagename)
136                           . " "
137                           . sprintf(_("Error: Couldn't send to %s"), join(',',$this->userids)), 
138                           E_USER_WARNING);
139             return false;
140         }
141     }
142     
143     /**
144      * Send udiff for a changed page to multiple users.
145      * See rename and remove methods also
146      */
147     function sendPageChangeNotification(&$wikitext, $version, &$meta) {
148
149         global $request;
150
151         if (@is_array($request->_deferredPageChangeNotification)) {
152             // collapse multiple changes (loaddir) into one email
153             $request->_deferredPageChangeNotification[] = 
154                 array($this->pagename, $this->emails, $this->userids);
155             return;
156         }
157         $backend = &$this->_wikidb->_backend;
158         //$backend = &$request->_dbi->_backend;
159         $subject = _("Page change").' '.urlencode($this->pagename);
160         $previous = $backend->get_previous_version($this->pagename, $version);
161         if (!isset($meta['mtime'])) $meta['mtime'] = time();
162         if ($previous) {
163             $difflink = WikiURL($this->pagename, array('action'=>'diff'), true);
164             $dbh = &$request->getDbh();
165             $cache = &$dbh->_wikidb->_cache;
166             //$cache = &$request->_dbi->_cache;
167             $content = explode("\n", $wikitext);
168             $prevdata = $cache->get_versiondata($this->pagename, $previous, true);
169             if (empty($prevdata['%content']))
170                 $prevdata = $backend->get_versiondata($this->pagename, $previous, true);
171             $other_content = explode("\n", $prevdata['%content']);
172             
173             include_once("lib/difflib.php");
174             $diff2 = new Diff($other_content, $this_content);
175             //$context_lines = max(4, count($other_content) + 1,
176             //                     count($this_content) + 1);
177             $fmt = new UnifiedDiffFormatter(/*$context_lines*/);
178             $content  = $this->pagename . " " . $previous . " " . 
179                 Iso8601DateTime($prevdata['mtime']) . "\n";
180             $content .= $this->pagename . " " . $version . " " .  
181                 Iso8601DateTime($meta['mtime']) . "\n";
182             $content .= $fmt->format($diff2);
183             
184         } else {
185             $difflink = WikiURL($this->pagename,array(),true);
186             $content = $this->pagename . " " . $version . " " .  
187                 Iso8601DateTime($meta['mtime']) . "\n";
188             $content .= _("New page");
189         }
190         $editedby = sprintf(_("Edited by: %s"), $this->from);
191         //$editedby = sprintf(_("Edited by: %s"), $meta['author']);
192         $this->sendMail($subject, 
193                         $editedby."\n".$difflink."\n\n".$content);
194     }
195
196     /** 
197      * support mass rename / remove (not yet tested)
198      */
199     function sendPageRenameNotification ($to, &$meta) {
200         global $request;
201
202         if (@is_array($request->_deferredPageRenameNotification)) {
203             $request->_deferredPageRenameNotification[] = 
204                 array($this->pagename, $to, $meta, $this->emails, $this->userids);
205         } else {
206             $pagename = $this->pagename;
207             //$editedby = sprintf(_("Edited by: %s"), $meta['author']) . ' ' . $meta['author_id'];
208             $editedby = sprintf(_("Edited by: %s"), $this->from);
209             $subject = sprintf(_("Page rename %s to %s"), urlencode($pagename), urlencode($to));
210             $link = WikiURL($to, true);
211             $this->sendMail($subject, 
212                             $editedby."\n".$link."\n\n"."Renamed $pagename to $to");
213         }
214     }
215
216     /**
217      * The handlers:
218      */
219     function onChangePage (&$wikidb, &$wikitext, $version, &$meta) {
220         $result = true;
221         if (!isa($GLOBALS['request'],'MockRequest')) {
222             $notify = $wikidb->_wikidb->get('notify');
223             /* Generate notification emails? */
224             if (!empty($notify) and is_array($notify)) {
225                 if (empty($this->pagename))
226                     $this->pagename = $meta['pagename'];
227                 //TODO: defer it (quite a massive load if you MassRevert some pages).
228                 //TODO: notification class which catches all changes,
229                 //  and decides at the end of the request what to mail. (type, page, who, what, users, emails)
230                 // could be used for PageModeration and RSS2 Cloud xml-rpc also.
231                 $this->getPageChangeEmails($notify);
232                 if (!empty($this->emails)) {
233                     $result = $this->sendPageChangeNotification($wikitext, $version, $meta);
234                 }
235             }
236         }
237         return $result;
238     }
239
240     function onDeletePage (&$wikidb, $pagename) {
241         $result = true;
242         /* Generate notification emails? */
243         if (! $wikidb->isWikiPage($pagename) and !isa($GLOBALS['request'],'MockRequest')) {
244             $notify = $wikidb->get('notify');
245             if (!empty($notify) and is_array($notify)) {
246                 //TODO: deferr it (quite a massive load if you remove some pages).
247                 //TODO: notification class which catches all changes,
248                 //  and decides at the end of the request what to mail. 
249                 // (type, page, who, what, users, emails)
250
251                 // could be used for PageModeration and RSS2 Cloud xml-rpc also.
252                 $this->getPageChangeEmails($notify);
253                 if (!empty($this->emails)) {
254                     $editedby = sprintf(_("Removed by: %s"), $this->from); // Todo: host_id
255                     $emails = join(',', $emails);
256                     $subject = sprintf(_("Page removed %s"), urlencode($pagename));
257                     $result = $this->sendMail($subject, 
258                                               $editedby."\n"."Deleted $pagename"."\n\n".$content);
259                 }
260             }
261         }
262         //How to create a RecentChanges entry with explaining summary? Dynamically
263         /*
264           $page = $this->getPage($pagename);
265           $current = $page->getCurrentRevision();
266           $meta = $current->_data;
267           $version = $current->getVersion();
268           $meta['summary'] = _("removed");
269           $page->save($current->getPackedContent(), $version + 1, $meta);
270         */
271         return $result;
272     }
273
274     function onRenamePage (&$wikidb, $oldpage, $new_pagename) {
275         $result = true;
276         if (!isa($GLOBALS['request'], 'MockRequest')) {
277             $notify = $wikidb->get('notify');
278             if (!empty($notify) and is_array($notify)) {
279                 $this->getPageChangeEmails($notify);
280                 if (!empty($this->emails)) {
281                     $newpage = $wikidb->getPage($new_pagename);
282                     $current = $newpage->getCurrentRevision();
283                     $meta = $current->_data;
284                     $this->pagename = $oldpage;
285                     $result = $this->sendPageRenameNotification($new_pagename, $meta);
286                 }
287             }
288         }
289     }
290
291     /**
292      * send mail to user and store the cookie in the db
293      * wikiurl?action=ConfirmEmail&id=bla
294      */
295     function sendEmailConfirmation ($email, $userid) {
296         $id = rand_ascii_readable(16);
297         $wikidb = $GLOBALS['request']->getDbh();
298         $data = $wikidb->get('ConfirmEmail');
299         while(!empty($data[$id])) { // id collision
300             $id = rand_ascii_readable(16);
301         }
302         $subject = WIKI_NAME . " " . _("e-mail address confirmation");
303         $ip = $request->get('REMOTE_HOST');
304         $expire_date = time() + 7*86400;
305         $content = fmt("Someone, probably you from IP address %s, has registered an
306 account \"%s\" with this e-mail address on %s.
307
308 To confirm that this account really does belong to you and activate
309 e-mail features on %s, open this link in your browser:
310
311 %s
312
313 If this is *not* you, don't follow the link. This confirmation code
314 will expire at %s.", 
315                        $ip, $userid, WIKI_NAME, WIKI_NAME, 
316                        WikiURL(HOME_PAGE, array('action' => 'ConfirmEmail',
317                                                 'id' => $id), 
318                                true),
319                        CTime($expire_date));
320         $this->sendMail($subject, $content, "", true);
321         $data[$id] = array('email' => $email,
322                            'userid' => $userid,
323                            'expire' => $expire_date);
324         $wikidb->set('ConfirmEmail', $data);
325         return '';
326     }
327
328     function checkEmailConfirmation () {
329         global $request;
330         $wikidb = $request->getDbh();
331         $data = $wikidb->get('ConfirmEmail');
332         $id = $request->getArg('id');
333         if (empty($data[$id])) { // id not found
334             return HTML(HTML::h1("Confirm E-mail address"),
335                         HTML::h1("Sorry! Wrong URL"));
336         }
337         // upgrade the user
338         $userid = $data['userid'];
339         $email = $data['email'];
340         $u = $request->getUser();
341         if ($u->UserName() == $userid) { // lucky: current user (session)
342             $prefs = $u->getPreferences();
343             $request->_user->_level = WIKIAUTH_USER;
344             $request->_prefs->set('emailVerified', true);
345         } else {  // not current user
346             if (ENABLE_USER_NEW) {
347                 $u = WikiUser($userid);
348                 $u->getPreferences();
349                 $prefs = &$u->_prefs;
350             } else {
351                 $u = new WikiUser($request, $userid);
352                 $prefs = $u->getPreferences();
353             }
354             $u->_level = WIKIAUTH_USER;
355             $request->setUser($u);
356             $request->_prefs->set('emailVerified', true);
357         }
358         unset($data[$id]);
359         $wikidb->set('ConfirmEmail', $data);
360         return HTML(HTML::h1("Confirm E-mail address"),
361                     HTML::p("Your e-mail address has now been confirmed."));
362     }
363 }
364
365
366 // $Log: not supported by cvs2svn $
367 // Revision 1.3  2006/12/24 13:35:43  rurban
368 // added experimental EMailConfirm auth. (not yet tested)
369 // requires actionpage ConfirmEmail
370 // TBD: purge expired cookies
371 //
372 // Revision 1.2  2006/12/23 11:50:45  rurban
373 // added missing result init
374 //
375 // Revision 1.1  2006/12/22 17:59:55  rurban
376 // Move mailer functions into seperate MailNotify.php
377 //
378
379 // Local Variables:
380 // mode: php
381 // tab-width: 8
382 // c-basic-offset: 4
383 // c-hanging-comment-ender-p: nil
384 // indent-tabs-mode: nil
385 // End:   
386 ?>