<?php    
/**
 * DekiReader
 * is a class for getting instant email notifications with DekiWiki, if someone
 * changes a site in your Watchlist
 *
 * This script is free to use for private and commercial purposes
 * Author: Evgeny Anisiforov
 * mailtO: jeff at ebesucher point de
 *
 * I spend a whole day on writing this, so 
 * Please just leave a comment in my blog, if you use this. ;)
 */ 

/**
 * The most problem about getting notifications is that DekiWiki requires us
 * to be logged in (with a cookie) to be able to view the full rss feed
 * of changes (including changed things)
 * This is a big problem, as the most rss read does not have such function.
 * This script emulates a login for each user to get the auth cookie
 * and then sends the contents of the RSS-feed to the specified email-address
 * It also takes care of marking old messages as read, so your users won't
 * get notifications more than one time
 * 
 * The best practice would be to use a cronjob to start DekiReader every X minutes.
 * like this:
          * / 10 * * * * cd /www/Cron_Jobs/DekiReader; nice php notifyfromdb.php
          
 * notice: this file has only the class definitions, of cource you need a script
 * to create an object of DekiReader and pass the userdata to it.
 * */

/*
* this script needs the PEAR-packages "http_client" and "http_request"
*/
require_once "HTTP/Request.php";
require_once 
"HTTP/Client.php";

define('ERROR_DEKIWIKI_WRONG_CREDENTIALS''ERROR_DEKIWIKI_WRONG_CREDENTIALS');
define('ERROR_WEB_SERVICE''ERROR_WEB_SERVICE');

/* ------- Cookie's creation for Deki Wiki ------- */
class DekiCookie {
    public 
$url "http://wiki.ebesucher.in";
    
    
/** thanks to kurdte from: http://wiki.developer.mindtouch.com/MindTouch_Deki/Specs/Authentication_Providers */
    
public function getAuthToken($login$password) {
        
/* Request a value for the user's cookie */
        
$url $this->url."/@api/deki/users/authenticate/";
        
$req =& new HTTP_Request($url);
        
$req->setBasicAuth($login$password);
        
$response $req->sendRequest();
        
        if (!
PEAR::isError($response)) {
        
$output=$req->getResponseBody();
        
        
/* Authentication proccess : if the response contains 401 authentication failed, the user is not registered */
        
if(strpos($output,"authentication")==&& strpos($output,"401")==0)
        {
            
//$cookie_deki=$req->getResponseCookies();
            
return $output;
            
//setcookie("authtoken",str_replace("\"","",$cookie_deki[0]['value']),time()+3600, '/');
        
}
        else
        {
            
$error ERROR_DEKIWIKI_WRONG_CREDENTIALS;
        }
        }
        else {
            
$response->getMessage();
            
$error ERROR_WEB_SERVICE;
        } 
    }
}

class 
DekiReader {
    
/**
        array with the date of users to check
        every item must contain: username, password
        every item may contain: authtoken
    */
    
public $userdata;
    public 
$url;
    public 
$emaildomain;
    private 
$domain;
    
/** Directory to store cache-Data (what feed-messages did we
      * allready read? */
    
public $cachedir "cache/";
    
    
/**
     *  creates a DekiReader
     *  $emaildomain = the domain for sender-address
     *  if not given, we'll take the domain
    */
    
public function DekiReader($domain$userdata$emaildomain false) {
        
$this->domain $domain;
        
$this->url $domain."/@api/deki/site/feed?title=Special:Watchlist";
        
$this->userdata $userdata;
        if (!
$emaildomain) {
            
//delete http:// or https:// at the beginning
            
$d eregi_replace('^http://'''$domain);
            
$d eregi_replace('^https://'''$d);
            
$this->emaildomain $d;   
        }
        else {
            
$this->emaildomain $emaildomain;
        }    
    }
    
    
/**
    * Returns the proper RFC 822 formatted date. 
    * @return string
    */
    
public function RFCDate($timestamp) {
       
$tz date("Z"$timestamp);
       
$tzs = ($tz 0) ? "-" "+";
       
$tz abs($tz);
       
$tz = ($tz/3600)*100 + ($tz%3600)/60;
       
$result sprintf("%s %s%04d"date("D, j M Y H:i:s"$timestamp), $tzs$tz);
    
       return 
$result;
    }
    
    
/** convert the Dateformat of the Feed to a Timestamp */
    
public function strangeDate2Timestamp($date) {
        
$regs = array();
        
preg_match('~((\d+)-(\d+)-(\d+))T((\d+):(\d+):(\d+))Z~is'$date$regs);
        
        
//date and time
        
$d $regs[0];
        
$t $regs[1];
        return 
mktime($regs[6], $regs[7], $regs[8], $regs[3], $regs[4], $regs[2]);
    }
    
    
/** read the message cache for a user */
    
public function getCache($username) {
        
//we use username and feed-url to cache read messages
        
$cache  $this->getCacheFilename($username);
        
        
//read the cache
        
$contents file_exists($cache) ? file_get_contents($cache) : '';
        
        return 
$contents;
    }
    
    
//get the filename of the message cache for a username
    
public function getCacheFilename($username) {
        return 
$this->cachedir.'rss_' md5($username."@".$this->url) . '.txt';
    }
    
    
//add something to messagecache
    
public function addToCache($username$url) {
        
$handle fopen($this->getCacheFilename($username), 'a');
        
fwrite($handle$url "\r\n");
        
fclose($handle);
    }
    
    public function 
run() {
        
$deki = new DekiCookie();
        
header('Content-Type: text/plain');
        foreach (
$this->userdata as $user) {
            echo 
"trying to get ".$this->url." for user ".$user['username']."\n";
            
$req = new HTTP_Request($this->url);            
            
$req->setMethod(HTTP_REQUEST_METHOD_GET);
            
//do we have an authtoken?
            
if (!$user['authtoken']) {
                
$user['authtoken'] = $deki->getAuthToken($user['username'], $user['password']);
                echo 
"estimated authtoken for user ".$user['username'].": ".$user['authtoken']."\n";
            }
            
$req->addCookie("authtoken"$user['authtoken']);
            
$req->sendRequest();
            
$rss $req->getResponseBody();
            
            
$xml    = new SimpleXMLElement($rss);
            
$cache_contents $this->getCache($user['username']);
            
            
//some output
            
echo 'Feed: ' . (string)$xml->link['href'] . "\r\n";
            
            
//iterate the items in the feed
            
foreach ($xml->entry as $item) {
                
$url = (string)$item->link['href'];
                
$id          = (string)$item->id;
                
//did we allready read this?
                
if (strpos($cache_contents$id) !== false) {
                    echo 
"   read: $id\r\n";    
                    continue;
                }
                else {
                    echo 
"   unread: $id\r\n";
                }
                
                
// The data from the feed
                
$authorname  = (string)$item->author->name;
                
//delete scopes for better compartibility
                
$authorname  str_replace("("""$authorname);
                
$authorname  str_replace(")"""$authorname);
                
//here we don't have a read possibility to get the email of
                //the author, we just simulate it by adding our domain name
                //to the username (or you could write a function that does that better..)
                
$author      '"'.$authorname.'"'."<".$authorname."@".$this->emaildomain.">";

                
$title       = (string)$item->title;
                
$link        = (string)$item->link['href'];
                
$pubDate     = (string)$item->published;
                
//convert the date from the feed to a compartible date format
                //for the emails, so that we can see the correct date of
                //the posting in our email program
                
$updatedtimestamp $this->strangeDate2Timestamp((string)$item->updated);
                
$updated     $this->RFCDate($updatedtimestamp);
                
//we want all tags between <summary> and </summary>, so just
                //iterate through the children
                
$description "";
                foreach (
$item->summary->children() as $child)
                {
                    
$description .= $child->asXML();
                }
    
                
    
                
$to   $user['email']; 
                
$mail "
                <html><head></head><body>
                Page: <a href=\"$url\">$title</a>
                $description
                </body></html>"


                
mail($to'[Wiki] ' $title$mail"From: $author"
                     
."\nContent-Type: text/html; charset=utf-8"
                     
."\nDate: ".$updated
                     
); 
                                        
                
// we have send a notification for this item, so send
                // write this to the cache
                
$this->addToCache($user['username'], $id);
            }
        }
    }
}

?>