| <?php␊ | 
| /* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */␊ | 
| /*␊ | 
| # ***** BEGIN LICENSE BLOCK *****␊ | 
| # This file is part of InDefero, an open source project management application.␊ | 
| # Copyright (C) 2008 CĂ©ondo Ltd and contributors.␊ | 
| #␊ | 
| # InDefero is free software; you can redistribute it and/or modify␊ | 
| # it under the terms of the GNU General Public License as published by␊ | 
| # the Free Software Foundation; either version 2 of the License, or␊ | 
| # (at your option) any later version.␊ | 
| #␊ | 
| # InDefero is distributed in the hope that it will be useful,␊ | 
| # but WITHOUT ANY WARRANTY; without even the implied warranty of␊ | 
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the␊ | 
| # GNU General Public License for more details.␊ | 
| #␊ | 
| # You should have received a copy of the GNU General Public License␊ | 
| # along with this program; if not, write to the Free Software␊ | 
| # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA␊ | 
| #␊ | 
| # ***** END LICENSE BLOCK ***** */␊ | 
| ␊ | 
| /**␊ | 
| * This classes is a plugin which allows to synchronise access rights␊ | 
| * between indefero and mercurial web-published repositories.␊ | 
| */␊ | 
| class IDF_Plugin_SyncMercurial␊ | 
| {␊ | 
| ␊ | 
| /**␊ | 
| * Entry point of the plugin.␊ | 
| */␊ | 
| static public function entry($signal, &$params)␊ | 
| {␊ | 
| // First check for the 3 mandatory config variables.␊ | 
| if (!Pluf::f('idf_plugin_syncmercurial_passwd_file', false) or␊ | 
| !Pluf::f('idf_plugin_syncmercurial_path', false) or␊ | 
| !Pluf::f('idf_plugin_syncmercurial_hgrc', false)) {␊ | 
| return;␊ | 
| }␊ | 
| include_once 'File/Passwd/Authdigest.php';␊ | 
| $plug = new IDF_Plugin_SyncMercurial();␊ | 
| switch ($signal) {␊ | 
| case 'IDF_Project::created':␊ | 
| $plug->processMercurialCreate($params['project']);␊ | 
| break;␊ | 
| case 'IDF_Project::membershipsUpdated':␊ | 
| $plug->processSyncAuthz($params['project']);␊ | 
| break;␊ | 
| case 'Pluf_User::passwordUpdated':␊ | 
| $plug->processSyncPasswd($params['user']);␊ | 
| break;␊ | 
| }␊ | 
| }␊ | 
| ␊ | 
| /**␊ | 
| * Run hg init command to create the corresponding Mercurial␊ | 
| * repository.␊ | 
| *␊ | 
| * @param IDF_Project ␊ | 
| * @return bool Success␊ | 
| */␊ | 
| function processMercurialCreate($project)␊ | 
| {␊ | 
| $shortname = $project->shortname;␊ | 
| ␊ | 
| if (false===($mercurial_path=Pluf::f('idf_plugin_syncmercurial_path',false))) {␊ | 
| throw new Pluf_Exception_SettingError("'idf_plugin_syncmercurial_path' must be defined in your configuration file.");␊ | 
| }␊ | 
| ␊ | 
| if (file_exists($mercurial_path.'/'.$shortname)) {␊ | 
| throw new Exception(sprintf(__('The repository %s already exists.'),␊ | 
| $mercurial_path.'/'.$shortname));␊ | 
| }␊ | 
| $return = 0;␊ | 
| $output = array();␊ | 
| $cmd = sprintf('hg init %s', ␊ | 
| escapeshellarg($mercurial_path.'/'.$shortname));␊ | 
| $ll = exec($cmd, $output, $return);␊ | 
| return ($return == 0);␊ | 
| }␊ | 
| ␊ | 
| /**␊ | 
| * Synchronise an user's password.␊ | 
| *␊ | 
| * @param Pluf_User␊ | 
| */␊ | 
| function processSyncPasswd($user)␊ | 
| {␊ | 
| $passwd_file = Pluf::f('idf_plugin_syncmercurial_passwd_file');␊ | 
| if (!file_exists($passwd_file) or !is_writable($passwd_file)) {␊ | 
| return false;␊ | 
| }␊ | 
| $ht = new File_Passwd_Authbasic($passwd_file);␊ | 
| $ht->load();␊ | 
| $ht->setMode(FILE_PASSWD_SHA); ␊ | 
| if ($ht->userExists($user->login)) {␊ | 
| $ht->changePasswd($user->login, $this->getMercurialPass($user));␊ | 
| } else {␊ | 
| $ht->addUser($user->login, $this->getMercurialPass($user));␊ | 
| }␊ | 
| $ht->save();␊ | 
| return true;␊ | 
| }␊ | 
| ␊ | 
| /**␊ | 
| * Synchronize the hgrc file and the passwd file for the project.␊ | 
| *␊ | 
| * @param IDF_Project␊ | 
| */␊ | 
| function processSyncAuthz($project)␊ | 
| {␊ | 
| $this->SyncAccess($project);␊ | 
| $this->generateProjectPasswd($project);␊ | 
| }␊ | 
| ␊ | 
| /**␊ | 
| * Get the repository password for the user␊ | 
| */␊ | 
| function getMercurialPass($user){␊ | 
| return substr(sha1($user->password.Pluf::f('secret_key')), 0, 8);␊ | 
| }␊ | 
| ␊ | 
| /**␊ | 
| * For a particular project: update all passwd information␊ | 
| */␊ | 
| function generateProjectPasswd($project)␊ | 
| {␊ | 
| $passwd_file = Pluf::f('idf_plugin_syncmercurial_passwd_file');␊ | 
| if (!file_exists($passwd_file) or !is_writable($passwd_file)) {␊ | 
| throw new Exception (sprintf(__('%s does not exist or is not writable.'), $passwd_file));␊ | 
| }␊ | 
| $ht = new File_Passwd_Authbasic($passwd_file);␊ | 
| $ht->setMode(FILE_PASSWD_SHA); ␊ | 
| $ht->load();␊ | 
| $mem = $project->getMembershipData();␊ | 
| $members = array_merge((array)$mem['members'], (array)$mem['owners'], ␊ | 
| (array)$mem['authorized']);␊ | 
| foreach($members as $user) {␊ | 
| if ($ht->userExists($user->login)) {␊ | 
| $ht->changePasswd($user->login, $this->getMercurialPass($user));␊ | 
| } else {␊ | 
| $ht->addUser($user->login, $this->getMercurialPass($user));␊ | 
| }␊ | 
| }␊ | 
| $ht->save();␊ | 
| }␊ | 
| ␊ | 
| /**␊ | 
| * Generate the hgrc file␊ | 
| */␊ | 
| function SyncAccess($project)␊ | 
| {␊ | 
| $shortname = $project->shortname;␊ | 
| $hgrc_file = Pluf::f('idf_plugin_syncmercurial_path').sprintf('/%s/.hg/hgrc', $shortname);␊ | 
| ␊ | 
| // Get allow_push list␊ | 
| $allow_push = '';␊ | 
| $mem = $project->getMembershipData();␊ | 
| foreach ($mem['owners'] as $v) {␊ | 
| $allow_push .= $v->login.' ';␊ | 
| }␊ | 
| foreach ($mem['members'] as $v) {␊ | 
| $allow_push .= $v->login.' ';␊ | 
| }␊ | 
| ␊ | 
| // Generate hgrc content ␊ | 
| if (is_file($hgrc_file)) {␊ | 
| $tmp_content = parse_ini_file($hgrc_file, true);␊ | 
| $tmp_content['web']['allow_push'] = $allow_push;␊ | 
| }␊ | 
| else {␊ | 
| $tmp_content = Pluf::f('idf_plugin_syncmercurial_hgrc');␊ | 
| $tmp_content['web']['allow_push'] = $allow_push;␊ | 
| }␊ | 
| $fcontent = '';␊ | 
| foreach ($tmp_content as $key => $elem){␊ | 
| $fcontent .= '['.$key."]\n";␊ | 
| foreach ($elem as $key2 => $elem2){␊ | 
| $fcontent .= $key2.' = '.$elem2."\n"; ␊ | 
| }␊ | 
| }␊ | 
| file_put_contents($hgrc_file, $fcontent, LOCK_EX);␊ | 
| ␊ | 
| // Generate private repository config file␊ | 
| $private_file = Pluf::f('idf_plugin_syncmercurial_private_include');␊ | 
| $notify_file = Pluf::f('idf_plugin_syncmercurial_private_notify');␊ | 
| $fcontent = '';␊ | 
| foreach (Pluf::factory('IDF_Project')->getList() as $project) {␊ | 
| $conf = new IDF_Conf();␊ | 
| $conf->setProject($project);␊ | 
| if ($project->private == true){␊ | 
| $mem = $project->getMembershipData();␊ | 
| $user = '';␊ | 
| foreach ($mem['owners'] as $v) {␊ | 
| $user .= $v->login.' ';␊ | 
| }␊ | 
| foreach ($mem['members'] as $v) {␊ | 
| $user .= $v->login.' ';␊ | 
| }␊ | 
| foreach ($mem['authorized'] as $v) {␊ | 
| $user .= $v->login.' ';␊ | 
| }␊ | 
| $fcontent .= '<Location '. sprintf(Pluf::f('idf_plugin_syncmercurial_private_url'), $project->shortname).'>'."\n";␊ | 
| $fcontent .= 'AuthType Basic'."\n";␊ | 
| $fcontent .= 'AuthName "Restricted"'."\n";␊ | 
| $fcontent .= sprintf('AuthUserFile %s', Pluf::f('idf_plugin_syncmercurial_passwd_file'))."\n";␊ | 
| $fcontent .= sprintf('Require user %s', $user)."\n";␊ | 
| $fcontent .= '</Location>'."\n\n";␊ | 
| }␊ | 
| }␊ | 
| file_put_contents($private_file, $fcontent, LOCK_EX);␊ | 
| file_put_contents($notify_file, ' ', LOCK_EX);␊ | 
| return true;␊ | 
| }␊ | 
| }␊ |