*/ // must be run within Dokuwiki if(!defined('DOKU_INC')) die(); if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); require_once(DOKU_PLUGIN.'syntax.php'); require_once(DOKU_INC.'inc/infoutils.php'); /** * This is the base class for all syntax classes, providing some general stuff */ class helper_plugin_freesync extends DokuWiki_Plugin { var $_profilePath; var $_client = null; var $_profile = array(); /** * constructor */ function helper_plugin_freesync(){ global $conf; $this->_profilePath = $conf['cachedir'].'/freesync'; if(!file_exists($this->_profilePath)) @mkdir($this->_profilePath); } /** * return some info */ function getInfo(){ return array( 'author' => 'Mikhail I. Izmestev', 'email' => 'izmmishao5@gmail.com', 'date' => '2009-03-11', 'name' => 'freesync helper', 'desc' => 'Dirty work for freesync', 'url' => '', ); } function getProfileName() { return $this->_profile['name']; } function getProfile() { return $this->_profile; } function saveProfile($oldname, $profile) { $this->loadProfile($oldname); $this->_profile["pages"] = null; $this->_profile["files"] = null; $profile = array_merge($this->_profile, $profile); $oldpfFN = $this->_profilePath.'/'.$oldname.".ini"; if(preg_match('/^http:\/\/([a-zA-Z0-9][a-zA-Z0-9_.]+)\//', $profile['xmlrpcurl'], $match)) { $profile['name'] = $match[1]; $pfFN = $this->_profilePath.'/'.$profile['name'].".ini"; $fprofile = fopen($pfFN, "w"); foreach($profile as $key => $val) { fprintf($fprofile, "%s=\"%s\"\n", $key, $val); } fclose($fprofile); if($oldpfFN != $pfFN && file_exists($oldpfFN)) unlink($oldpfFN); $this->loadProfile($profile['name']); } elseif(empty($profile['xmlrpcurl']) && file_exists($oldpfFN)) unlink($oldpfFN); else msg('Bad XMLRPC URL'); } function getProfiles() { $profiles = array(); if($dh = opendir($this->_profilePath)) { while($profile = readdir($dh)) { if(preg_match("/^(.*).ini$/", $profile, $match)) $profiles[] = $match[1]; } closedir($dh); } return $profiles; } function loadProfile($name) { $pfFN = $this->_profilePath.'/'.$name.".ini"; if(file_exists($pfFN)) $this->_profile = parse_ini_file($pfFN); else $this->_profile = array(); if(!empty($this->_profile['namespace']) && !preg_match('/.*:$/', $this->_profile['namespace'])) $this->_profile['namespace'] .= ":"; } function _xmlrpcInit() { global $conf; require_once(DOKU_INC.'inc/IXR_Library.php'); if(!$this->_client) { $this->_client = new IXR_Client($this->_profile['xmlrpcurl']); if(!empty($this->_profile['user'])) { $loginurl = str_replace('lib/exe/xmlrpc.php', 'doku.php?do=login', $this->_profile['xmlrpcurl']); $this->_client->sendRequest($loginurl); $this->_client->sendRequest($loginurl, array("id" => "start", "u" => $this->_profile['user'], "p" => $this->_profile['pass']), 'POST'); } } } function _rpcQuery($call, $data, &$response) { if(!$this->_client) $this->_xmlrpcInit(); if(!is_array($data)) $data = array($data); array_unshift($data, $call); if(call_user_func_array(array(&$this->{'_client'},"query"), $data)) { $response = $this->_client->getResponse(); return TRUE; } return false; } function getPagesDiff() { global $conf; $remote_list = array(); $local_list = array(); if($this->_profile['pages']) { if($this->_rpcQuery('wiki.getAllPages', array(), $rpages)) { foreach($rpages as $page) { $remote_list[$page["id"]] = array("id" => $page["id"], "rperms" => $page["perms"], "rsize" => $page["size"], "rlastModified" => $page["lastModified"]->getTimestamp()); } $pages = file($conf['indexdir'] . '/page.idx'); foreach(array_keys($pages) as $idx) { if(page_exists($pages[$idx])) { $perm = auth_quickaclcheck($pages[$idx]); if($perm >= AUTH_READ) { $local_list[trim($pages[$idx])] = array("id" => trim($pages[$idx]), "lperms" => $perm, "lsize" => @filesize(wikiFN($pages[$idx])), "llastModified" => @filemtime(wikiFN($pages[$idx]))); } } } } else msg("Error get remote list pages"); } if($this->_profile['files']) { if($this->_rpcQuery('wiki.getAttachments', array("", array("recursive" => true)), $rfiles)) { if(count($rfiles)) foreach($rfiles as $file) { $remote_list[$file["id"]] = array("id" => $file["id"], "rperms" => $file["perms"], "rsize" => $file["size"], "rlastModified" => $file["lastModified"]->getTimestamp(), "file" => 1); } if(auth_quickaclcheck(':*') >= AUTH_READ) { $dir = utf8_encodeFN(str_replace(':', '/', $ns)); $lfiles = array(); require_once(DOKU_INC.'inc/search.php'); search($lfiles, $conf['mediadir'], 'search_media', array('recursive' => true), $dir); if(count($lfiles)) foreach($lfiles as $file) { $local_list[$file["id"]] = array("id" => $file["id"], "lperms" => auth_quickaclcheck(getNS($file['id']).':*'), "lsize" => $file["size"], "llastModified" => $file["mtime"], "file" => 1); } } } else msg("Error get remote list files"); } $sync_list = array_merge_recursive($remote_list, $local_list); $sync_list = array_filter($sync_list, array(&$this, '_pageFilter')); ksort($sync_list); return $sync_list; } function _pageFilter($page) { $id = is_array($page['id'])?$page['id'][0]:$page['id']; if($page['llastModified'].','.$page['rlastModified'] == $this->_profile[$id]) { return 0; } return !strncmp($id, $this->_profile['namespace'], strlen($this->_profile['namespace'])) && $page['llastModified'] != $page['rlastModified']; } function getLocalPage($id, $onlyinfo = false) { if(empty($id)) return false; $file = wikiFN($id,''); $time = @filemtime($file); if(!$time){ return false; } $info = getRevisionInfo($id, $time, 1024); $page = array( 'name' => $id, 'author' => (($info['user']) ? $info['user'] : $info['ip']), 'version' => $time ); if($onlyinfo) return $page; $page['text'] = rawWiki($id,''); if(!$page['text']) { $data = array($id); $page['text'] = trigger_event('HTML_PAGE_FROMTEMPLATE',$data,'pageTemplate',true); } return $page; } function getRemotePage($id, $onlyinfo = false) { if(empty($id)) return false; if($this->_rpcQuery('wiki.getPageInfo', $id, $page)) { if($page['version']) { if(!$onlyinfo) { $page['text'] = false; $this->_rpcQuery('wiki.getPage', $id, $page['text']); } return $page; } } return false; } function page_l2r($id, $sum='') { if(! ($page = $this->getLocalPage($id)) ) { $page['text'] = ''; } if($this->_rpcQuery('wiki.putPage', array($id, $page['text'], $sum), $res)) { if($res == 0) { $rversion = $this->getRemotePage($id, true); $this->_profile[$id] = $page['version'].','.$rversion['lastModified']->getTimestamp(); $this->saveProfile($this->getProfileName(), $this->_profile); return "Succesful"; } } return "Error!"; } function page_r2l($id, $sum='') { global $TEXT; global $lang; global $conf; $id = cleanID($id); if(empty($id)) return 'Empty page ID'; $page = $this->getRemotePage($id); if(!$page || !$page['text']) return 'Error getting page'; $TEXT = trim($page['text']); if(!page_exists($id) && empty($TEXT)) { return 'Refusing to write an empty new wiki page'; } if(auth_quickaclcheck($id) < AUTH_EDIT) return 'You are not allowed to edit this page'; // Check, if page is locked if(checklock($id)) return 'The page is currently locked'; // SPAM check if(checkwordblock()) return 'Positive wordblock check'; // autoset summary on new pages if(!page_exists($id) && empty($sum)) { $sum = $lang['created']; } // autoset summary on deleted pages if(page_exists($id) && empty($TEXT) && empty($sum)) { $sum = $lang['deleted']; } lock($id); saveWikiText($id,$TEXT,$sum); unlock($id); // run the indexer if page wasn't indexed yet if(!@file_exists(metaFN($id, '.indexed'))) { // try to aquire a lock $lock = $conf['lockdir'].'/_indexer.lock'; while(!@mkdir($lock,$conf['dmode'])){ usleep(50); if(time()-@filemtime($lock) > 60*5){ // looks like a stale lock - remove it @rmdir($lock); }else{ return "Lock time out"; } } if($conf['dperm']) chmod($lock, $conf['dperm']); require_once(DOKU_INC.'inc/indexer.php'); // do the work idx_addPage($id); // we're finished - save and free lock io_saveFile(metaFN($id,'.indexed'),INDEXER_VERSION); @rmdir($lock); } $lversion = $this->getLocalPage($id, true); $this->_profile[$id] = $lversion['version'].','.$page['lastModified']->getTimestamp(); $this->saveProfile($this->getProfileName(), $this->_profile); return "Succesful"; } function getLocalFile($id, $onlyinfo = false) { if(empty($id)) return false; if (auth_quickaclcheck(getNS($id).':*') < AUTH_READ) return false; $filename = mediaFN($id); if (!@ file_exists($filename)) return false; $file['lastModified'] = filemtime($filename); $file['size'] = filesize($filename); if($onlyinfo) return $file; $data = io_readFile($filename, false); $file['content'] = base64_encode($data); return $file; } function getRemoteFile($id, $onlyinfo = false) { if(empty($id)) return false; if(!$this->_client) $this->_xmlrpcInit(); if($this->_rpcQuery('wiki.getAttachmentInfo', $id, $file) && $file['lastModified']) { $file['lastModified'] = $file['lastModified']->getTimestamp(); if(!$onlyinfo) { $file['content'] = false; $fetchurl = str_replace('xmlrpc.php', 'fetch.php?media='.$id, $this->_profile['xmlrpcurl']); $this->_client->sendRequest($fetchurl); if(strlen($this->_client->resp_body) && $this->_client->resp_body != "Not Found") $file['content'] = base64_encode($this->_client->resp_body); } return $file; } return false; } function file_l2r($id, $sum='') { $id = cleanID($id); $file = $this->getLocalFile($id); if($file && $this->_rpcQuery('wiki.putAttachment', array($id, $file['content'], array("ow" => true)), $res)) { $rversion = $this->getRemoteFile($id, true); $this->_profile[$id] = $file['lastModified'].','.$rversion['lastModified']; $this->saveProfile($this->getProfileName(), $this->_profile); return "Succesful"; } return "Error!"; } function file_r2l($id, $sum='') { global $conf; global $lang; if(!isset($id)) { return 'Filename not given.'; } $file = $this->getRemoteFile($id); if(!$file) { return 'Error get remote file'; } if(!$file['content']) { return 'File is empty'; } $auth = auth_quickaclcheck(getNS($id).':*'); if($auth >= AUTH_UPLOAD) { $ftmp = $conf['tmpdir'] . '/' . $id; // save temporary file @unlink($ftmp); $buff = base64_decode($file['content']); io_saveFile($ftmp, $buff); // get filename list($iext, $imime,$dl) = mimetype($id); $id = cleanID($id); $fn = mediaFN($id); // get filetype regexp $types = array_keys(getMimeTypes()); $types = array_map(create_function('$q','return preg_quote($q,"/");'),$types); $regex = join('|',$types); // because a temp file was created already if(preg_match('/\.('.$regex.')$/i',$fn)) { //check for overwrite $overwrite = @file_exists($fn); if($overwrite && $auth < AUTH_DELETE) { return $lang['uploadexist']; } // check for valid content @require_once(DOKU_INC.'inc/media.php'); $ok = media_contentcheck($ftmp, $imime); if($ok == -1) { return sprintf($lang['uploadexist'], ".$iext"); } elseif($ok == -2) { return $lang['uploadspam']; } elseif($ok == -3) { return $lang['uploadxss']; } // prepare event data $data[0] = $ftmp; $data[1] = $fn; $data[2] = $id; $data[3] = $imime; $data[4] = $overwrite; // trigger event require_once(DOKU_INC.'inc/events.php'); if(true == trigger_event('MEDIA_UPLOAD_FINISH', $data, array($this, '_media_upload_action'), true)) { $lversion = $this->getLocalFile($id, true); $this->_profile[$id] = $lversion['lastModified'].','.$file['lastModified']; $this->saveProfile($this->getProfileName(), $this->_profile); return "Succesful"; } } else { return $lang['uploadwrong']; } } else { return "You don't have permissions to upload files."; } } /** * Moves the temporary file to its final destination. * * Michael Klier */ function _media_upload_action($data) { global $conf; if(is_array($data) && count($data)===5) { io_createNamespace($data[2], 'media'); if(rename($data[0], $data[1])) { chmod($data[1], $conf['fmode']); media_notify($data[2], $data[1], $data[3]); // add a log entry to the media changelog require_once(DOKU_INC.'inc/changelog.php'); if ($data[4]) { addMediaLogEntry(time(), $data[2], DOKU_CHANGE_TYPE_EDIT); } else { addMediaLogEntry(time(), $data[2], DOKU_CHANGE_TYPE_CREATE); } return true; } else { return 'Upload failed.'; } } else { return 'Upload failed.'; } } function getDiff($id) { $id = cleanID($id); if(empty($id)) return 'Empty page ID'; $lpage = $this->getLocalPage($id); $rpage = $this->getRemotePage($id); require_once(DOKU_INC.'inc/DifferenceEngine.php'); $tdf = new TableDiffFormatter(); return '
'. ''. $tdf->format(new Diff(split("\n", $lpage['text']), split("\n", $rpage['text']))). '
Local WikiRemote Wiki
'; } }