diff --git a/livesupport/modules/alib/doc/aarfc.html b/livesupport/modules/alib/doc/aarfc.html new file mode 100644 index 000000000..9049622c1 --- /dev/null +++ b/livesupport/modules/alib/doc/aarfc.html @@ -0,0 +1,227 @@ + + + + Auth library + + + + +

Auth library - request for comments

+22.7.2004 +

Authentication & authorization

+

Authentication - as user's identity +checking - login call create and return auth token, client sends this token +with all subsequent calls, logout call make this token invalid
+

+

Authorization - as checking user's +permission for called action on some object - that's main solved problem. +

+

Basic model

+
Subject --- Action ---> Object
+
+

Where:

+ +
+

Subject implementation

+

Subjects are divided into two types - users and groups. There is membership relation +(type N:M) from subjects table to itself with "linearization" feature - for +questions about it send me a mail please ;)
+This approach allows inserting user to group or group to group with quick +searching of direct and indirect membership. +

+

Object implementation

+

For simple use with existing projects, there would be a object tree +always separated from project's database tables. It would be implemented by +table of objects and information about parent/child (or other) relation +between objects. +

+

+There is also class table and N:M membership relation between objects and +classes. +

+

Example:

+
+
+RootNode
+        |
+        |-> Publication_A(publication)
+        |              \-> Issue_1(issue)              <--\
+        |                       |-> Sport(section)        |    <--\
+        |                       \-> Politics(section)     |       |
+        \-> Publication_B(publication)                    |       |
+                       |-> Issue_1(issue)              <--|       |
+                       |        |-> Politics(section)     |       |
+                       |        |-> Sport(section)        |    <--|
+                       |        \-> Culture(section)      |       |
+                       \-> Issue_2(issue)              <--|       |
+                                |-> Culture(section)      |       |
+                                \-> Politics(section)     |       |
+                                                          |       |
+Class "Issues" -------------------------------------------/       |
+Class "Sport sections" -------------------------------------------/
+
+ + + +
+

Permissions for actions

+

There are several ways to handle permissions - I've used this:
+allow/deny - all without allow +permission is denied, but more specified setting may overcome less +specified
+(e.g. group of users is allowed to do smth., but one specified group-member is +denied) +

+

Permissions are stored as triple [subject, action, object] +and allow/deny flag.
+

+
+

Procedure of permission checking:

+ +
+

Rem.: Some cache system for authorization decisions would be good ... +

+

Auth system usage

+
+

There are 3 main types of usage:

+
    +
  1. authorization of called action
  2. +
  3. automatic modification of user interface in dependence on user +permissions
  4. +
  5. automatic generation of admin interface for permissions settings
  6. +
+
+

Important part of API:

+
+ +

All methods may return PEAR::error object if fails ...

+
+

Connection to existing applications

+

PHP applications could include Alib class and call API methods +directly.
+Other programming platforms should call XMLRPC or HTTP layer above this API. +

+
+ +

P.S.: sorry for my English ... ;)

+ + diff --git a/livesupport/modules/alib/doc/reference.html b/livesupport/modules/alib/doc/reference.html new file mode 100644 index 000000000..7de65ad0f --- /dev/null +++ b/livesupport/modules/alib/doc/reference.html @@ -0,0 +1,60 @@ + + +Alib reference + + + +

Alib reference

+ +in construction - sorry ;) + + +

Contents

+
    +
  1. Subjects
  2. +
  3. Perms
  4. +
  5. Objects
  6. +
  7. Classes
  8. +
  9. DB structure
  10. +
+ + +

Subjects

+ + +

Perms

+ + +

Objects

+ + +

Classes

+

Classes may be replaced by one branch in object tree ...

+ + +

DB structure

+
+subjects         < perms >         objects/classes
+         < smemb 
+                           cmemb > 
+ 
+ + + diff --git a/livesupport/modules/alib/doc/todo.txt b/livesupport/modules/alib/doc/todo.txt new file mode 100644 index 000000000..ef6a3a915 --- /dev/null +++ b/livesupport/modules/alib/doc/todo.txt @@ -0,0 +1,17 @@ + + $Id: todo.txt,v 1.1 2004/07/23 00:22:13 tomas Exp $ + +* delete old sessions +* if user have 'classes' permission: + -> create new class ('X') + -> add '_all' perm on class 'X' to himself + -> insert RootNode to class 'X' + => user have all perms ;) +* complete xmlrpc layer + +--- +partialy done: + +. actions would have priority order (or set lower priority to '_all' action only), + temp hack: '_all' action is in string sort after all act names => with ASC order have '_all' lower prio ... +--- diff --git a/livesupport/modules/alib/var/alib.php b/livesupport/modules/alib/var/alib.php new file mode 100644 index 000000000..891e364ba --- /dev/null +++ b/livesupport/modules/alib/var/alib.php @@ -0,0 +1,444 @@ +permTable = $config['tblNamePrefix'].'perms'; + $this->sessTable = $config['tblNamePrefix'].'sess'; + } + + /* ========== public methods: ========== */ + + /* --- session/authentication --- */ + + /** + * login + * + * @param login string + * @param pass string + * @return boolean/sessionId/err + **/ + function login($login, $pass) + { + if(FALSE === $this->authenticate($login, $pass)) return FALSE; + for($c=1; $c>0;){ + $sessid = md5(uniqid(rand())); + $c = $this->dbc->getOne("SELECT count(*) FROM {$this->sessTable} WHERE sessid='$sessid'"); + if(PEAR::isError($c)) return $c; + } + $userid = $this->getSubjId($login); + $r = $this->dbc->query("INSERT INTO {$this->sessTable} (sessid, userid, login) + VALUES ('$sessid', '$userid', '$login')"); + if(PEAR::isError($r)) return $r; + $this->login = $login; + $this->userid = $userid; + $this->sessid = $sessid; + return $sessid; + } + + /** + * logout + * + * @param sessid string + * @return true/err + **/ + function logout($sessid) + { + $ct = $this->checkToken($sessid); + if($ct === FALSE) + return PEAR::raiseError('Alib::logout: not logged ($ct)', ALIBERR_NOTLOGGED, PEAR_ERROR_RETURN); + elseif(PEAR::isError($ct)) + return $ct; + else{ + $r = $this->dbc->query("DELETE FROM {$this->sessTable} WHERE sessid='$sessid'"); + if(PEAR::isError($r)) return $r; + $this->login = NULL; + $this->userid = NULL; + $this->sessid = NULL; + return TRUE; + } + } + + /** + * checkToken + * + * @param sessid string + * @return boolean/err + **/ + function checkToken($sessid) + { + $c = $this->dbc->getOne("SELECT count(*) as cnt FROM {$this->sessTable} WHERE sessid='$sessid'"); + return ($c == 1 ? TRUE : (PEAR::isError($c) ? $c : FALSE )); + } + + /** + * setToken + * + * @param sessid string + * @return boolean/err + **/ + function setToken($sessid) + { + $r = checkToken($sessid); + if(PEAR::isError($r)) return $r; + if(!$r) return PEAR::raiseError("ALib::setToken: invalid token ($sessid)"); + $this->sessid = $sessid; + return TRUE; + } + + /* --- authorization --- */ + /** + * addPerm + * + * @param sid int + * @param action string + * @param oid int + * @param type char + * @return int/err + **/ + function addPerm($sid, $action, $oid, $type='A') + { + $permid = $this->dbc->nextId("{$this->permTable}_id_seq"); + $r = $this->dbc->query($q = " + INSERT INTO {$this->permTable} (permid, subj, action, obj, type) + VALUES ($permid, $sid, '$action', $oid, '$type') + "); + if(PEAR::isError($r)) return($r); + return $permid; + } + + /** + * removePerm + * + * @param permid int OPT + * @param subj int OPT + * @param obj int OPT + * @return null/error + **/ + function removePerm($permid=NULL, $subj=NULL, $obj=NULL) + { + return $this->dbc->query("DELETE FROM {$this->permTable} WHERE 1=1". + ($permid ? " AND permid=$permid" : ''). + ($subj ? " AND subj=$subj" : ''). + ($obj ? " AND obj=$obj" : '') + ); + } + + /** + * checkPerm + * + * @param sid int + * @param action string + * @param oid int OPT + * @return boolean/err + **/ + function checkPerm($sid, $action, $oid=NULL) + { + if(!is_numeric($sid)) return FALSE; + if(is_null($oid)) $oid = $this->getObjId($this->RootNode); + if(PEAR::isError($oid)) return $oid; + if(!is_numeric($oid)) return FALSE; + // query elements + $q_flds = "m.level as S_lvl, p.subj, s.login, action, p.type, p.obj"; + $q_from = "{$this->subjTable} s, {$this->permTable} p"; + $q_join = "LEFT JOIN {$this->smembTable} m ON p.subj=m.gid "; + $q_cond = "p.action in('_all', '$action') AND (m.uid=$sid OR p.subj=$sid) AND s.id=p.subj"; + $q_ordb = "ORDER BY S_lvl, action, p.type DESC"; // action ASC order is hack for lower priority of '_all' + $qc0 = $q_cond; + // test if object is class: + $iscls = $this->isClass($oid); if(PEAR::isError($iscls)) return $iscls; + if($iscls){ + $q_from .= ", {$this->classTable} c"; + $q_cond .= " AND c.id=p.obj AND c.id=$oid"; + }else{ + // object is normal node => path search => retrieve L/R values for oid: + $r1 = $this->dbc->getRow("SELECT lft, rgt, level FROM {$this->treeTable} WHERE id=$oid"); + if(is_null($r1)) + return PEAR::raiseError('Alib::checkPerm: object not exists', ALIBERR_NOTEXISTS, PEAR_ERROR_RETURN); + if(PEAR::isError($r1)) return($r1); + // fetch all path to oid + join with perms + $q_flds .= ", t.name, ({$r1['level']}-t.level)as T_lvl"; + $q_from = "{$this->treeTable} t, ".$q_from; + $q_cond .= " AND t.id=p.obj AND t.lft<={$r1['lft']} AND t.rgt>={$r1['rgt']}"; + $q_ordb = "ORDER BY T_lvl, S_lvl, action, p.type DESC"; // action ASC order is hack for lower priority of '_all' + } + $query="SELECT $q_flds FROM $q_from $q_join WHERE $q_cond $q_ordb"; + $r2 = $this->dbc->getAll($query); + if(PEAR::isError($r2)) return($r2); + if(!$iscls && !(is_array($r2) && count($r2)>0)){ + // no perm found, search in classes: + $q_from = "{$this->cmembTable} cm, ".$q_from; + $q_cond = $qc0. + " AND t.lft<={$r1['lft']} AND t.rgt>={$r1['rgt']}". + " AND cm.cid=p.obj AND cm.objid=t.id"; + $query="SELECT $q_flds FROM $q_from $q_join WHERE $q_cond $q_ordb"; + $r2 = $this->dbc->getAll($query); + if(PEAR::isError($r2)) return($r2); + } + // if there is row with type='A' on the top => permit + return (is_array($r2) && count($r2)>0 && $r2[0]['type']=='A'); + } + + /* --- object tree --- */ + + /** + * removeObj + * + * @param id int + * @return void/error + **/ + function removeObj($id) + { + $r = $this->removePerm(NULL, NULL, $id); if(PEAR::isError($r)) return $r; + return parent::removeObj($id); + } + + /* --- users/groups --- */ + + /** + * removeSubj + * + * @param login string + * @return void/error + **/ + function removeSubj($login) + { + $uid = $this->getSubjId($login); if(PEAR::isError($uid)) return $uid; + $r = $this->removePerm(NULL, $uid); if(PEAR::isError($r)) return $r; + return parent::removeSubj($login, $uid); + } + + /* --- sessions --- */ + /** + * getSessLogin + * + * @param sessid string + * @return string/error + **/ + function getSessLogin($sessid) + { + return $this->dbc->getOne(" + SELECT login FROM {$this->sessTable} WHERE sessid='$sessid'"); + } + + /** + * getSessUserId + * + * @param sessid string + * @return int/error + **/ + function getSessUserId($sessid) + { + return $this->dbc->getOne(" + SELECT userid FROM {$this->sessTable} WHERE sessid='$sessid'"); + } + + /* --- info methods: --- */ + /** + * getObjPerms + * + * @param id int + * @return array/null/err + **/ + function getObjPerms($id) + { + return $this->dbc->getAll(" + SELECT s.login, p.* FROM {$this->permTable} p, {$this->subjTable} s + WHERE s.id=p.subj AND p.obj=$id"); + } + + /** + * getSubjPerms + * + * @param sid int + * @return array + **/ + function getSubjPerms($sid) + { + $a1 = $this->dbc->getAll(" + SELECT t.name, t.type as otype , p.* FROM {$this->permTable} p, {$this->treeTable} t + WHERE t.id=p.obj AND p.subj=$sid"); + if(PEAR::isError($a1)) return $a1; + $a2 = $this->dbc->getAll(" + SELECT c.cname as name, 'C'as otype, p.* FROM {$this->permTable} p, {$this->classTable} c + WHERE c.id=p.obj AND p.subj=$sid"); + if(PEAR::isError($a2)) return $a2; + return array_merge($a1, $a2); + } + + /* --- info methods related to application structure: --- */ + /* (this part should be added/rewritten to allow defining/modifying/using application structure) */ + /* (only very simple structure definition - in config - supported now) */ + + /** + * getAllActions + * + * @return array + **/ + function getAllActions() + { + return $this->config['allActions']; + } + + /** + * getAllowedActions + * + * @param type string + * @return array + **/ + function getAllowedActions($type) + { + return $this->config['allowedActions'][$type]; + } + + + /* ========== test and debug methods: ========== */ + + /** + * dumpPerms + * + * @param indstr string // indentation string + * @param ind string // aktual indentation + * @return string + **/ + function dumpPerms($indstr=' ', $ind='') + { + $r = $ind.join(', ', array_map(create_function('$v', 'return "{$v[\'action\']}/{$v[\'type\']}";'), + $this->dbc->getAll("SELECT action, type FROM {$this->permTable}") + ))."\n"; + return $r; + } + + /** + * deleteData + * + * @return void + **/ + function deleteData() + { + $this->dbc->query("DELETE FROM {$this->permTable}"); + parent::deleteData(); + } + /** + * testData + * + * @return array + **/ + function testData() + { + parent::testData(); + $t =& $this->tdata['tree']; + $c =& $this->tdata['classes']; + $s =& $this->tdata['subjects']; + $o[] = $this->addPerm($s[0], '_all', $t[0], 'A'); + $o[] = $this->addPerm($s[1], '_all', $t[4], 'A'); + $o[] = $this->addPerm($s[1], '_all', $t[7], 'D'); +# $o[] = $this->addPerm($s[2], 'addChilds', $t[6], 'A'); + $o[] = $this->addPerm($s[2], 'read', $t[5], 'A'); + $o[] = $this->addPerm($s[2], 'edit', $t[6], 'A'); + $o[] = $this->addPerm($s[3], 'read', $c[0], 'A'); + $o[] = $this->addPerm($s[4], 'editPerms', $c[1], 'A'); + $o[] = $this->addPerm($s[4], 'editPerms', $t[7], 'D'); + + $o[] = $this->addPerm($s[1], 'addChilds', $t[3], 'A'); + $o[] = $this->addPerm($s[1], 'addChilds', $t[1], 'A'); + $o[] = $this->addPerm($s[5], 'addChilds', $t[3], 'A'); + $o[] = $this->addPerm($s[5], 'addChilds', $t[1], 'A'); + $o[] = $this->addPerm($s[6], 'addChilds', $t[3], 'A'); + $o[] = $this->addPerm($s[6], 'addChilds', $t[1], 'A'); + $o[] = $this->addPerm($s[7], 'addChilds', $t[3], 'A'); + $o[] = $this->addPerm($s[7], 'addChilds', $t[1], 'A'); + $this->tdata['perms'] = $o; + } + + /** + * test + * + * @return boolean/error + **/ + function test() + { + if(PEAR::isError($p = parent::test())) return $p; + $this->deleteData(); + $this->testData(); + $this->test_correct = "_all/A, _all/A, _all/D, read/A, edit/A, read/A, editPerms/A, editPerms/D, addChilds/A, addChilds/A, addChilds/A, addChilds/A, addChilds/A, addChilds/A, addChilds/A, addChilds/A\nno, yes\n"; + $this->test_dump = $this->dumpPerms(). + ($this->checkPerm($this->tdata['subjects'][1], 'edit', $this->tdata['tree'][7])? 'yes':'no').", ". + ($this->checkPerm($this->tdata['subjects'][2], 'read', $this->tdata['tree'][5])? 'yes':'no')."\n" + ; + $this->removePerm($this->tdata['perms'][1]); + $this->removePerm($this->tdata['perms'][3]); + $this->test_correct .= "_all/A, _all/D, edit/A, read/A, editPerms/A, editPerms/D, addChilds/A, addChilds/A, addChilds/A, addChilds/A, addChilds/A, addChilds/A, addChilds/A, addChilds/A\n"; + $this->test_dump .= $this->dumpPerms(); + $this->deleteData(); + if($this->test_dump==$this->test_correct){ $this->test_log.="alib: OK\n"; return TRUE; } + else return PEAR::raiseError('Alib::test', 1, PEAR_ERROR_DIE, '%s'. + "
\ncorrect:\n{$this->test_correct}\ndump:\n{$this->test_dump}\n
\n"); + } + + /** + * install - create tables + initialize + * + * @return void + **/ + function install() + { + parent::install(); + $this->dbc->query("CREATE TABLE {$this->permTable} ( + permid int not null, + subj int, + action varchar(20), + obj int, + type char(1) + )"); + $this->dbc->query("CREATE UNIQUE INDEX {$this->permTable}_permid_idx on {$this->permTable} (permid)"); + $this->dbc->query("CREATE INDEX {$this->permTable}_subj_obj_idx on {$this->permTable} (subj, obj)"); + $this->dbc->createSequence("{$this->permTable}_id_seq"); + + $this->dbc->query("CREATE TABLE {$this->sessTable} ( + sessid char(32) not null, + userid int, + login varchar(255), + ts timestamp + )"); + $this->dbc->query("CREATE UNIQUE INDEX {$this->sessTable}_sessid_idx on {$this->sessTable} (sessid)"); + $this->dbc->query("CREATE INDEX {$this->sessTable}_userid_idx on {$this->sessTable} (userid)"); + $this->dbc->query("CREATE INDEX {$this->sessTable}_login_idx on {$this->sessTable} (login)"); + } + + /** + * uninstall + * + * @return void + **/ + function uninstall() + { + $this->dbc->query("DROP TABLE {$this->permTable}"); + $this->dbc->dropSequence("{$this->permTable}_id_seq"); + $this->dbc->query("DROP TABLE {$this->sessTable}"); + parent::uninstall(); + } +} +?> \ No newline at end of file diff --git a/livesupport/modules/alib/var/class.php b/livesupport/modules/alib/var/class.php new file mode 100644 index 000000000..0c878bf86 --- /dev/null +++ b/livesupport/modules/alib/var/class.php @@ -0,0 +1,265 @@ +classTable = $config['tblNamePrefix'].'classes'; + $this->cmembTable = $config['tblNamePrefix'].'cmemb'; + } + + /* ========== public methods: ========== */ + + /** + * addClass + * + * @param cname string + * @return id/error + **/ + function addClass($cname) + { + $id = $this->dbc->nextId("{$this->treeTable}_id_seq"); if(PEAR::isError($id)) return $id; + $r = $this->dbc->query(" + INSERT INTO {$this->classTable} (id, cname) + VALUES ($id, '$cname') + "); + if(PEAR::isError($r)) return $r; + return $id; + } + + /** + * removeClass + * + * @param cname string + * @return boolean/err + **/ + function removeClass($cname) + { + $cid = $this->getClassId($cname); if(PEAR::isError($cid)) return($cid); + return $this->removeClassById($cid); + } + + /** + * removeClassById + * + * @param cid int + * @return boolean/err + **/ + function removeClassById($cid) + { + $r = $this->dbc->query("DELETE FROM {$this->cmembTable} WHERE cid=$cid"); + if(PEAR::isError($r)) return $r; + $r = $this->dbc->query("DELETE FROM {$this->classTable} WHERE id=$cid"); + if(PEAR::isError($r)) return $r; + return TRUE; + } + + /** + * addObj2Class + * + * @param cid int + * @param oid int + * @return boolean/err + **/ + function addObj2Class($cid, $oid) + { + $r = $this->dbc->query("INSERT INTO {$this->cmembTable} (cid, objid) VALUES ($cid, $oid)"); + if(PEAR::isError($r)) return $r; + return TRUE; + } + + /** + * removeObjFromClass + * + * @param oid int + * @param cid int OPT // if not specified, remove obj from all classes + * @return boolean/err + **/ + function removeObjFromClass($oid, $cid=NULL) + { + $r = $this->dbc->query("DELETE FROM {$this->cmembTable} WHERE objid=$oid".(is_null($cid)? '':" AND cid=$cid")); + if(PEAR::isError($r)) return $r; + return TRUE; + } + + /* --- object tree --- */ + + /** + * removeObj + * + * @param id int + * @return boolean/err + **/ + function removeObj($id) + { + $r = $this->removeObjFromClass($id); if(PEAR::isError($r)) return $r; + return parent::removeObj($id); + } + + /* --- info methods: --- */ + + /** + * getClassId + * + * @param cname string + * @return int/err + **/ + function getClassId($cname) + { + return $this->dbc->getOne($query = "SELECT id FROM {$this->classTable} WHERE cname='$cname'"); + } + + /** + * getClassName + * + * @param id int + * @return string/err + **/ + function getClassName($id) + { + return $this->dbc->getOne($query = "SELECT cname FROM {$this->classTable} WHERE id=$id"); + } + + /** + * isClass + * + * @param id int + * @return boolean/err + **/ + function isClass($id) + { + $r = $this->dbc->getOne("SELECT count(*) FROM {$this->classTable} WHERE id=$id"); + if(PEAR::isError($r)) return $r; + return ($r > 0); + } + + /** + * getClasses + * + * @return array/err + **/ + function getClasses() + { + return $this->dbc->getAll("SELECT * FROM {$this->classTable}"); + } + + /** + * listClass + * + * @param id int + * @return array/err + **/ + function listClass($id) + { + return $this->dbc->getAll("SELECT t.* FROM {$this->cmembTable} cm, {$this->treeTable} t + WHERE cm.cid=$id AND cm.objid=t.id"); + } + + /* ========== test and debug methods: ========== */ + + /** + * dumpClasses + * + * @param id int + * @param indstr string // indentation string + * @param ind string // aktual indentation + * @return string + **/ + function dumpClasses($indstr=' ', $ind='') + { + $r = $ind.join(', ', array_map(create_function('$v', 'return "{$v[\'cname\']} ({$v[\'cnt\']})";'), + $this->dbc->getAll(" + SELECT cname, count(cm.objid)as cnt FROM {$this->classTable} c + LEFT JOIN {$this->cmembTable} cm ON c.id=cm.cid + GROUP BY cname, c.id ORDER BY c.id + ") + ))."\n"; + return $r; + } + + /** + * testData + * + **/ + function deleteData() + { + $this->dbc->query("DELETE FROM {$this->cmembTable}"); + $this->dbc->query("DELETE FROM {$this->classTable}"); + parent::deleteData(); + } + function testData() + { + parent::testData(); + $o[] = $this->addClass('Sections b'); + $o[] = $this->addClass('Class 2'); + $this->addObj2Class($o[1], $this->tdata['tree'][4]); + $this->addObj2Class($o[1], $this->tdata['tree'][9]); + $this->tdata['classes'] = $o; + } + + /** + * test + * + **/ + function test() + { + if(PEAR::isError($p = parent::test())) return $p; + $this->deleteData(); + $this->testData(); + $this->test_correct = "Sections b (0), Class 2 (2)\n"; + $this->test_dump = $this->dumpClasses(); + $this->removeClass('Sections b'); + $this->removeObjFromClass($this->tdata['tree'][4], $this->tdata['classes'][1]); + $this->test_correct .= "Class 2 (1)\n"; + $this->test_dump .= $this->dumpClasses(); + $this->deleteData(); + if($this->test_dump==$this->test_correct){ $this->test_log.="class: OK\n"; return TRUE; } + else return PEAR::raiseError('ObjClasses::test:', 1, PEAR_ERROR_DIE, '%s'. + "
\ncorrect:\n{$this->test_correct}\ndump:\n{$this->test_dump}\n
\n"); + } + + /** + * install - create tables + initialize + * + **/ + function install() + { + parent::install(); + $this->dbc->query("CREATE TABLE {$this->classTable} ( + id int not null, + cname varchar(20) + )"); + $this->dbc->query("CREATE UNIQUE INDEX {$this->classTable}_id_idx on {$this->classTable} (id)"); + $this->dbc->query("CREATE UNIQUE INDEX {$this->classTable}_cname_idx on {$this->classTable} (cname)"); + + $this->dbc->query("CREATE TABLE {$this->cmembTable} ( + objid int not null, + cid int not null + )"); + $this->dbc->query("CREATE UNIQUE INDEX {$this->cmembTable}_idx on {$this->cmembTable} (objid, cid)"); + } + function uninstall() + { + $this->dbc->query("DROP TABLE {$this->classTable}"); + $this->dbc->query("DROP TABLE {$this->cmembTable}"); + parent::uninstall(); + } +} +?> \ No newline at end of file diff --git a/livesupport/modules/alib/var/example/alibExCls.php b/livesupport/modules/alib/var/example/alibExCls.php new file mode 100644 index 000000000..7db05e3de --- /dev/null +++ b/livesupport/modules/alib/var/example/alibExCls.php @@ -0,0 +1,126 @@ + $alib->getClasses(), + 'loggedAs' => $login, + ); +}else{ + $d = array( + 'rows' => $alib->listClass($id), + 'id' => $id, + 'loggedAs' => $login, + 'cname' => $alib->getClassName($id), + 'cls' => $alib->getClasses(), + 'objs' => $alib->getSubTree(null, true) + ); +} +$d['msg'] = $_SESSION['alertMsg']; unset($_SESSION['alertMsg']); + +require_once"alib_f.php"; +// template follows: +?> + +Alib - class editor + + + + + + +

Class editor

+ + +

All classes:

+ +0) foreach($d['cls'] as $k=>$c) {?> + + + +?> + + + + + +
+ delete + permissions +
none
+ +
+Add class with name + + + +
+ + + +

Objects in class :

+ + + + + +0) foreach($d['rows'] as $k=>$row) {?> + + + + + + + + + +
+ All classes +
+ removeFromClass + permissions +
none
+ +
+Add object + +to class + + + +
+ + + + + + + \ No newline at end of file diff --git a/livesupport/modules/alib/var/example/alibExLogin.php b/livesupport/modules/alib/var/example/alibExLogin.php new file mode 100644 index 000000000..18225964e --- /dev/null +++ b/livesupport/modules/alib/var/example/alibExLogin.php @@ -0,0 +1,112 @@ + $alib->getSubjects(), + 'actions' => $alib->getAllActions(), + 'objects' => $alib->getAllObjects(), + 'msg' => $_SESSION['alertMsg'] +); +unset($_SESSION['alertMsg']); + +// forms prefill: +if(is_array($_SESSION['lastPost'])) $d = array_merge($d, array( + 'lastSubj' => $_SESSION['lastPost']['subj'], + 'lastAction'=> $_SESSION['lastPost']['permAction'], + 'lastObj' => $_SESSION['lastPost']['obj'] +)); +unset($_SESSION['lastPost']); + +#header("Content-type: text/plain"); print_r($d); exit; +require_once"alib_f.php"; +// template follows: +?> + +Alib - example login + + + + + +
+ Test accounts/pass: + +
+ +

ALib - tests/example

+ +
+ + + + +
Login:
Password:
+ +
+
+
+ +
+Permission test:
+Subject: +action: +object: + + +
+
+ +
+Permission matrix for subject: + +
+ +
+ +reset db + test all
+ + + + + \ No newline at end of file diff --git a/livesupport/modules/alib/var/example/alibExPList.php b/livesupport/modules/alib/var/example/alibExPList.php new file mode 100644 index 000000000..9c44746d8 --- /dev/null +++ b/livesupport/modules/alib/var/example/alibExPList.php @@ -0,0 +1,75 @@ + $alib->getSubjPerms($id), + 'id' => $id, + 'loggedAs' => $login, + 'actions' => $alib->getAllActions(), + 'name' => $alib->getSubjName($id) + ); + $d['msg'] = $_SESSION['alertMsg']; unset($_SESSION['alertMsg']); + +require_once"alib_f.php"; +// template follows: +?> + +Alib - permission list + + + + + + +

Subject permission list

+ +

Permissions for subject :

+ + + + + +0) foreach($d['rows'] as $k=>$row) {?> + + + + + + + + +
+ All subjects +
+ () + deny' : $row['type']))?> + delete +
none
+ + + + + \ No newline at end of file diff --git a/livesupport/modules/alib/var/example/alibExPMatrix.php b/livesupport/modules/alib/var/example/alibExPMatrix.php new file mode 100644 index 000000000..2869a0f3d --- /dev/null +++ b/livesupport/modules/alib/var/example/alibExPMatrix.php @@ -0,0 +1,44 @@ +getAllObjects() as $it){ + $aa=array(); + foreach($alib->getAllActions() as $a){ + $aa[$a]=$alib->checkPerm($sid, $a, $it['id']); +# if(PEAR::isError($aa[$a])){ errCallback($aa[$a]); } + } + $m[]=array($it['name'], $aa); +} +$u=$alib->getSubjName($sid); + +?> + +ALib - permission matrix + + +

Permission matrix

+

User:

+ + +getAllActions() as $a){?> + + + +$v){ list($obj, $aa)=$v;?> + + + + + + + +
object
+ +Back +
+Tree dump: +
dumpTree()?>
+ diff --git a/livesupport/modules/alib/var/example/alibExPerms.php b/livesupport/modules/alib/var/example/alibExPerms.php new file mode 100644 index 000000000..37b92045f --- /dev/null +++ b/livesupport/modules/alib/var/example/alibExPerms.php @@ -0,0 +1,118 @@ +getRootNode(); +} + +// prefill data structure for template +if(!$alib->isClass($id)){ + $d = array( + 'path' => $alib->getPath($id, 'id,name'), + 'perms' => $alib->getObjPerms($id), + 'actions' => $alib->getAllowedActions($alib->getObjType($id)), + 'subjects' => $alib->getSubjects(), + 'id' => $id, + 'loggedAs' => $login + ); +}else{ + $d = array( + 'path' => '', + 'name' => $alib->getClassName($id), + 'perms' => $alib->getObjPerms($id), + 'actions' => $alib->getAllowedActions('_class'), + 'subjects' => $alib->getSubjects(), + 'id' => $id, + 'loggedAs' => $login + ); +} +$d['msg'] = $_SESSION['alertMsg']; unset($_SESSION['alertMsg']); + +require_once"alib_f.php"; +// template follows: +?> + +Alib - permission editor + + + + + + +

Permission editor

+ +

Path: + $it) {?> +href="?id=">/ + +Class + +

+ + +0) foreach($d['perms'] as $k=>$row) {?> + + + + + + + + + +
deny' : $row['type']))?> + delete +
none
+ +
+Add permission + +for action + +to subject + + + + + +
+ + + + + \ No newline at end of file diff --git a/livesupport/modules/alib/var/example/alibExSubj.php b/livesupport/modules/alib/var/example/alibExSubj.php new file mode 100644 index 000000000..99931f854 --- /dev/null +++ b/livesupport/modules/alib/var/example/alibExSubj.php @@ -0,0 +1,141 @@ + $alib->getSubjectsWCnt(), + 'loggedAs' => $login + ); +}else{ + $d = array( + 'rows' => $alib->listGroup($id), + 'id' => $id, + 'loggedAs' => $login, + 'gname' => $alib->getSubjName($id), + 'subj' => $alib->getSubjects() + ); +} +$d['msg'] = $_SESSION['alertMsg']; unset($_SESSION['alertMsg']); + +require_once"alib_f.php"; +// template follows: +?> + +Alib - subjects editor + + + + + + +

User/Group editor

+ + +

Subjects:

+ +0) foreach($d['subj'] as $k=>$c) {?> + + + (G:) (U) + + + + + +
+ + + + + + delete + permissions + permsMatrix + permsList +
none
+ +
+Add subject with name: +[and password: ] + + +
+ + + +

Subjects in group :

+ + + + + +0) foreach($d['rows'] as $k=>$row) {?> + + + (G) (U) + + + + + +
+ All subjects +
+ + + + + + + removeFromGroup + + permissions +
none
+ +
+Add subject + +to group + + + + +
+ + + + + + + \ No newline at end of file diff --git a/livesupport/modules/alib/var/example/alibExTestAuth.php b/livesupport/modules/alib/var/example/alibExTestAuth.php new file mode 100644 index 000000000..e106f066e --- /dev/null +++ b/livesupport/modules/alib/var/example/alibExTestAuth.php @@ -0,0 +1,9 @@ +getSessLogin($_REQUEST['alibsid']); +if(!isset($login)||$login==''){ + $_SESSION['alertMsg'] = "Login required"; + header("Location: alibExLogin.php"); + exit; +} +?> diff --git a/livesupport/modules/alib/var/example/alibExTree.php b/livesupport/modules/alib/var/example/alibExTree.php new file mode 100644 index 000000000..347a2aef5 --- /dev/null +++ b/livesupport/modules/alib/var/example/alibExTree.php @@ -0,0 +1,111 @@ +getRootNode(); + +// prefill data structure for template +$d = array( + 'parid' => $alib->getParent($id), + 'oname' => $alib->getObjName($id), + 'path' => $alib->getPath($id, 'id, name'), + 'rows' => $alib->getDir($id, 'id, name, type'), + 'addtypes' => $alib->getAllowedChildTypes($alib->getObjType($id)), + 'dump' => $alib->dumpTree($id), + 'id' => $id, + 'loggedAs' => $login +); +$d['msg'] = $_SESSION['alertMsg']; unset($_SESSION['alertMsg']); + +require_once"alib_f.php"; +// template follows: +?> + +Alib - tree editor + + + + + + +

Tree editor

+

Path: +$it) {?> +href="alibExTree.php?id=">/ +

+ + + + + + + +0) foreach($d['rows'] as $k=>$row) {?> + + + + + + + + +
Current node: + + permissions +
+Parent: .. +/ + +
() + delete + permissions +
none
+ +
+Add object of type + +with name + + + + + + +
+ +
Subtree dump:
+; print_r($d); echo"";?> + + + + + \ No newline at end of file diff --git a/livesupport/modules/alib/var/example/alibHttp.php b/livesupport/modules/alib/var/example/alibHttp.php new file mode 100644 index 000000000..d72184b6f --- /dev/null +++ b/livesupport/modules/alib/var/example/alibHttp.php @@ -0,0 +1,125 @@ +getSessUserId($_REQUEST['alibsid']); +$login = $alib->getSessLogin($_REQUEST['alibsid']); + +$redirUrl="alibExTree.php".(($reid=getPGval('reid', '')) ? "?id=$reid":""); +$act = getPGval('act', 'nop'); +switch($act) +{ + case"login"; + if($sessid = $alib->login($_POST['login'], $_POST['pass'])){ + setcookie('alibsid', $sessid); + $redirUrl="alibExTree.php"; + }else{ $redirUrl="alibExLogin.php"; $_SESSION['alertMsg']='Login failed.'; } + break; + case"logout"; + $r = $alib->logout($_REQUEST['alibsid']); + if(PEAR::isError($r)) $_SESSION['alertMsg'] = $r->getMessage().", ".$r->getUserInfo(); + setcookie('alibsid', ''); + $redirUrl="alibExLogin.php"; + break; + case"addNode"; + if($alib->checkPerm($userid, 'addChilds', $_POST['id']) + && $_POST['type']!='' + && $_POST['name']!='' + ){ + $oid = $alib->addObj($_POST['name'], $_POST['type'], $_POST['id'], $_POST['position']); + $alib->addPerm($userid, '_all', $oid); + }else $_SESSION['alertMsg']='Access denied.'; + break; + case"deleteNode"; + if($alib->checkPerm($userid, 'delete', $_REQUEST['id'])) + $alib->removeObj($_GET['id']); + else $_SESSION['alertMsg']='Access denied.'; + break; + case"addPerm"; + $a = $alib->isClass($_POST['id']) ? 'classes':'editPerms'; + $id = $alib->isClass($_POST['id']) ? '':$_POST['id']; + if($alib->checkPerm($userid, $a, $id)) + $alib->addPerm($_POST['subj'], $_POST['permAction'], $_POST['id'], $_POST['allowDeny']); + else $_SESSION['alertMsg']='Access denied.'; + $redirUrl="alibExPerms.php".(($reid=getPGval('reid', '')) ? "?id=$reid":""); + break; + case"removePerm"; + $a = $alib->isClass($_REQUEST['oid']) ? 'classes':'editPerms'; + $oid = $alib->isClass($_REQUEST['oid']) ? '':$_REQUEST['oid']; + if($alib->checkPerm($userid, $a, $oid)) + $alib->removePerm($_GET['permid']); + else $_SESSION['alertMsg']='Access denied.'; + $redirUrl=($_REQUEST['reurl']==plist ? "alibExPList.php":"alibExPerms.php").(($reid=getPGval('reid', '')) ? "?id=$reid":""); + break; + case"checkPerm"; + $res = $alib->checkPerm($_POST['subj'], $_POST['permAction'], $_POST['obj']); + $_SESSION['alertMsg'] = ($res ? "permitted: ":"DENIED: "). + " {$_POST['permAction']} for ".$alib->getSubjName($_POST['subj']). + " on ".$alib->getObjName($_POST['obj']); + $_SESSION['lastPost']=$_POST; + $redirUrl="alibExLogin.php"; + break; + case"addClass"; + if($alib->checkPerm($userid, 'classes')) + $alib->addClass($_POST['name']); + else $_SESSION['alertMsg']='Access denied.'; + $redirUrl="alibExCls.php"; + break; + case"removeClass"; + if($alib->checkPerm($userid, 'classes')) + $alib->removeClassById($_GET['id']); + else $_SESSION['alertMsg']='Access denied.'; + $redirUrl="alibExCls.php"; + break; + case"addSubj"; + if($alib->checkPerm($userid, 'subjects')) + $alib->addSubj($_POST['login'], $_POST['pass']); + else $_SESSION['alertMsg']='Access denied.'; + $redirUrl="alibExSubj.php"; + break; + case"removeSubj"; + if($alib->checkPerm($userid, 'subjects')) + $alib->removeSubj($_GET['login']); + else $_SESSION['alertMsg']='Access denied.'; + $redirUrl="alibExSubj.php"; + break; + case"addSubj2Gr"; + if($alib->checkPerm($userid, 'subjects')) + $alib->addSubj2Gr($_POST['login'], $_POST['gname']); + else $_SESSION['alertMsg']='Access denied.'; + $redirUrl="alibExSubj.php".(($id=getPGval('reid', '')) ? "?id=$reid":""); + break; + case"removeSubjFromGr"; + if($alib->checkPerm($userid, 'subjects')) + $alib->removeSubjFromGr($_GET['login'], $_GET['gname']); + else $_SESSION['alertMsg']='Access denied.'; + $redirUrl="alibExSubj.php".(($id=getPGval('reid', '')) ? "?id=$reid":""); + break; + case"addObj2Class"; + if($alib->checkPerm($userid, 'classes')) + $alib->addObj2Class($_POST['id'], $_POST['oid']); + else $_SESSION['alertMsg']='Access denied. X1'; + $redirUrl="alibExCls.php".(($id=getPGval('id', '')) ? "?id=$id":""); + break; + case"removeObjFromClass"; + $id=getPGval('id', ''); + if($alib->checkPerm($userid, 'classes')) + $alib->removeObjFromClass($_GET['oid'], $id); + else $_SESSION['alertMsg']='Access denied.'; + $redirUrl="alibExCls.php".($id ? "?id=$id":""); + break; + default: + $_SESSION['alertMsg']="Unknown method: $act"; +} + +require_once"alib_f.php"; + +header("Location: $redirUrl"); +?> \ No newline at end of file diff --git a/livesupport/modules/alib/var/example/alib_f.php b/livesupport/modules/alib/var/example/alib_f.php new file mode 100644 index 000000000..b18b01069 --- /dev/null +++ b/livesupport/modules/alib/var/example/alib_f.php @@ -0,0 +1,4 @@ +disconnect(); +?> \ No newline at end of file diff --git a/livesupport/modules/alib/var/example/alib_h.php b/livesupport/modules/alib/var/example/alib_h.php new file mode 100644 index 000000000..aeb4a285b --- /dev/null +++ b/livesupport/modules/alib/var/example/alib_h.php @@ -0,0 +1,31 @@ +\n"); +#PEAR::setErrorHandling(PEAR_ERROR_TRIGGER, E_USER_WARNING); +PEAR::setErrorHandling(PEAR_ERROR_DIE); +PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'errCallback'); + +function errCallback($err) +{ + if(assert_options(ASSERT_ACTIVE)==1) return; + echo "
\n";
+	echo "request: "; print_r($_REQUEST);
+    echo "\ngm:\n".$err->getMessage()."\nui:\n".$err->getUserInfo()."\n";
+    echo "
BackTrace:\n"; + print_r($err->backtrace); + echo "
\n"; + exit; +} + +$dbc = DB::connect($config['dsn'], TRUE); +$dbc->setFetchMode(DB_FETCHMODE_ASSOC); +$alib =& new Alib($dbc, $config); +?> \ No newline at end of file diff --git a/livesupport/modules/alib/var/example/conf.php b/livesupport/modules/alib/var/example/conf.php new file mode 100644 index 000000000..fa9bb769f --- /dev/null +++ b/livesupport/modules/alib/var/example/conf.php @@ -0,0 +1,32 @@ + array( // data source definition + 'username' => 'tomash', + 'password' => '', + 'hostspec' => 'localhost', + 'phptype' => 'pgsql', + 'database' => 'mdlf' + ), + 'tblNamePrefix' => 'al_', +# 'tblNamePrefix' => 'gb_', + 'RootNode' =>'RootNode', + 'objtypes' => array( + 'RootNode' => array('Publication'), + 'Publication' => array('Issue'), + 'Issue' => array('Title', 'Section'), + 'Section' => array('Title', 'Image', 'Par') + ), + 'allowedActions'=> array( + 'RootNode' => array('addChilds', 'editPerms', 'read', 'edit', 'delete', 'classes', 'subjects'), + 'Publication' => array('addChilds', 'editPerms', 'read', 'edit', 'delete'), + 'Issue' => array('addChilds', 'editPerms', 'read', 'edit', 'delete'), + 'Section' => array('addChilds', 'editPerms', 'read', 'edit', 'delete'), + 'Title' => array('editPerms', 'read', 'edit', 'delete'), + 'Image' => array('editPerms', 'read', 'edit', 'delete'), + 'Par' => array('editPerms', 'read', 'edit', 'delete'), + '_class' => array('addChilds', 'editPerms', 'read', 'edit', 'delete') + ), + 'allActions'=> array('editPerms', 'addChilds', 'read', 'edit', 'delete', 'classes', 'subjects') +); +?> \ No newline at end of file diff --git a/livesupport/modules/alib/var/example/default.css b/livesupport/modules/alib/var/example/default.css new file mode 100644 index 000000000..6005b0c32 --- /dev/null +++ b/livesupport/modules/alib/var/example/default.css @@ -0,0 +1,15 @@ + diff --git a/livesupport/modules/alib/var/example/index.php b/livesupport/modules/alib/var/example/index.php new file mode 100644 index 000000000..39de76ae2 --- /dev/null +++ b/livesupport/modules/alib/var/example/index.php @@ -0,0 +1,7 @@ + diff --git a/livesupport/modules/alib/var/index.php b/livesupport/modules/alib/var/index.php new file mode 100644 index 000000000..844fffc2f --- /dev/null +++ b/livesupport/modules/alib/var/index.php @@ -0,0 +1,7 @@ + diff --git a/livesupport/modules/alib/var/install.php b/livesupport/modules/alib/var/install.php new file mode 100644 index 000000000..e0899a4f6 --- /dev/null +++ b/livesupport/modules/alib/var/install.php @@ -0,0 +1,65 @@ +\n"; + echo "request: "; print_r($_REQUEST); + echo "gm:\n".$err->getMessage()."\ndi:\n".$err->getDebugInfo()."\nui:\n".$err->getUserInfo()."\n\n"; + exit; +} + + +PEAR::setErrorHandling(PEAR_ERROR_PRINT, "%s
\n"); +$dbc = DB::connect($config['dsn'], TRUE); +if(PEAR::isError($dbc)){ + echo "Database connection problem.\n"; + echo "Create database '{$config['dsn']['database']}' or change 'dsn' values in conf.php.\n"; + exit; +} + +$dbc->setFetchMode(DB_FETCHMODE_ASSOC); +$alib =& new Alib($dbc, $config); +?> + +ALib install + +

Alib install

+
+setErrorHandling(PEAR_ERROR_RETURN);
+#    $dbc->setErrorHandling(PEAR_ERROR_PRINT, "%s
\n"); + echo "Trying to uninstall all ...\n"; + $alib->uninstall(); + $dbc->setErrorHandling(PEAR_ERROR_PRINT, "%s
\n"); +# $dbc->setErrorHandling(PEAR_ERROR_CALLBACK, 'errCallback'); + echo "Install ...\n"; + $alib->install(); + + echo "Testing ...\n"; + $alib->test(); + $log = $alib->test_log; + echo "TESTS:\n$log\n---\n"; + + echo "Reinstall + testdata insert ...\n"; + $alib->reinstall(); + $alib->testData(); + + echo "TREE DUMP:\n"; + echo $alib->dumpTree(); + echo "\nAlib is probably installed OK\n\n\n"; +} +$dbc->disconnect(); +?> +
+Install/reinstall !
+
+Example
+XmlRpc test + + diff --git a/livesupport/modules/alib/var/mtree.php b/livesupport/modules/alib/var/mtree.php new file mode 100644 index 000000000..5f6b4fcf1 --- /dev/null +++ b/livesupport/modules/alib/var/mtree.php @@ -0,0 +1,521 @@ + array( // data source definition +* 'username' => DBUSER, +* 'password' => DBPASSWORD, +* 'hostspec' => 'localhost', +* 'phptype' => 'pgsql', +* 'database' => DBNAME +* ), +* 'tblNamePrefix' => 'al_', +* 'RootNode' =>'RootNode', +* ); +* (mysql phptype is tested too, but psql is recommended) +**/ +define('ALIBERR_MTREE', 10); + +class Mtree{ + var $dbc; + var $config; + var $treeTable; + var $rootNodeName; + /** Mtree - constructor + * + * @param dbc object + * @param config array + * @return this + **/ + function Mtree(&$dbc, $config) + { + $this->dbc =& $dbc; + $this->config = $config; + $this->treeTable = $config['tblNamePrefix'].'tree'; + $this->rootNodeName = $config['RootNode']; + } + + /* ========== public methods: ========== */ + + /** + * addObj + * + * @param name string + * @param type string + * @param parid int OPT // parent id + * @param aftid int OPT // after id + * @param param string OPT + * @return int/err // new id of inserted object + **/ + function addObj($name, $type, $parid=1, $aftid=NULL, $param='') + { + if($name=='' || $type=='') return PEAR::raiseError('Mtree::addObj: Wrong name or type', ALIBERR_MTREE); + $this->dbc->query("BEGIN"); + $r = $this->dbc->query("LOCK TABLE {$this->treeTable}"); if(PEAR::isError($r)) return $r; + // position resolving: + if(is_null($aftid)){ // add object as last child + $after = $this->dbc->getOne(" + SELECT max(rgt) FROM {$this->treeTable} WHERE parid='$parid' + "); + }else{ // use 'aftid' + $after = $this->dbc->getOne(" + SELECT ".($aftid == $parid ? 'lft' : 'rgt')." + FROM {$this->treeTable} WHERE id='$aftid'"); + } + if(PEAR::isError($after)) return $this->_dbRollback($after); + if(is_null($after)){ // position not specified - add as first child + $after = $this->dbc->getOne(" + SELECT lft FROM {$this->treeTable} WHERE id='$parid' + "); + } + if(PEAR::isError($after)) return $this->_dbRollback($after); + $after = intval($after); + // tree level resolving: + $level = $this->dbc->getOne("SELECT level FROM {$this->treeTable} WHERE id='$parid'"); + if(is_null($level)) return $this->_dbRollback('addObj: parent does not exist'); + if(PEAR::isError($level)) return $this->_dbRollback($level); + $id = $this->dbc->nextId("{$this->treeTable}_id_seq"); + if(PEAR::isError($id)) return $this->_dbRollback($id); + // creating space in rgt/lft sequencies: + $r = $this->dbc->query("UPDATE {$this->treeTable} SET rgt=rgt+2 WHERE rgt>$after"); + if(PEAR::isError($r)) return $this->_dbRollback($r); + $r = $this->dbc->query("UPDATE {$this->treeTable} SET lft=lft+2 WHERE lft>$after"); + if(PEAR::isError($r)) return $this->_dbRollback($r); + // inserting object: + $r = $this->dbc->query(" + INSERT INTO {$this->treeTable} (id, name, type, parid, level, lft, rgt, param) + VALUES ('$id', '$name', '$type', $parid, ".($level+1).", ".($after+1).", ".($after+2).", '$param') + "); + if(PEAR::isError($r)) return $this->_dbRollback($r); + $r = $this->dbc->query("COMMIT"); + if(PEAR::isError($r)) return $this->_dbRollback($r); + return $id; + } + + /** + * copyObj + * + * @param id int + * @param newParid int + * @param after int OPT + * @return int/err + **/ + function copyObj($id, $newParid, $after=NULL) + { + $o = $this->dbc->getRow("SELECT * FROM {$this->treeTable} WHERE id='$id'"); + if(PEAR::isError($o)) return $o; + $nid = $this->addObj($o['name'], $o['type'], $newParid, $after, $o['param']); + return $nid; + } + + /** + * renameObj + * + * @param id int + * @param newName string + * @return int/err + **/ + function renameObj($id, $newName) + { + $r = $this->dbc->query("UPDATE {$this->treeTable} SET name='$newName' WHERE id='$id'"); + if(PEAR::isError($r)) return $r; + return TRUE; + } + + /** + * removeObj + * + * @param id int + * @return boolean/err + **/ + function removeObj($id) + { + $dirarr = $this->getDir($id); if(PEAR::isError($dirarr)) return $dirarr; + foreach($dirarr as $k=>$snod) + { + $this->removeObj($snod['id']); + } + $this->dbc->query("BEGIN"); + $r = $this->dbc->query("LOCK TABLE {$this->treeTable}"); if(PEAR::isError($r)) return $r; + $rgt = $this->dbc->getOne("SELECT rgt FROM {$this->treeTable} WHERE id='$id'"); + if(is_null($rgt)) return $this->_dbRollback('removeObj: object not exists'); + // deleting object: + $r = $this->dbc->query("DELETE FROM {$this->treeTable} WHERE id='$id'"); + if(PEAR::isError($r)) return $this->_dbRollback($r); + // closing the space in rgt/lft sequencies: + $r = $this->dbc->query("UPDATE {$this->treeTable} SET rgt=rgt-2 WHERE rgt>$rgt"); + if(PEAR::isError($r)) return $this->_dbRollback($r); + $r = $this->dbc->query("UPDATE {$this->treeTable} SET lft=lft-2 WHERE lft>$rgt"); + if(PEAR::isError($r)) return $this->_dbRollback($r); + $r = $this->dbc->query("COMMIT"); + if(PEAR::isError($r)) return $this->_dbRollback($r); + return TRUE; + } + + /* --- info methods: --- */ + + /** + * getObjId - search dir for object by name + * + * @param name string + * @param parId int OPT + * @return int/err + **/ + function getObjId($name, $parId=NULL) + { + if($name=='' && is_null($parId)) $name = $this->rootNodeName; + return $this->dbc->getOne( + "SELECT id FROM {$this->treeTable} WHERE name='$name' and ".($parId ? "parid='$parId'":"parid is null") + ); + } + + /** + * getObjName - get one value for object (default: get name) + * + * @param oid int + * @param fld string OPT + * @return string/err + **/ + function getObjName($oid, $fld='name') + { + return $this->dbc->getOne("SELECT $fld FROM {$this->treeTable} WHERE id='$oid'"); + } + + /** + * getObjType + * + * @param oid int + * @return string/err + **/ + function getObjType($oid) + { + return $this->getObjName($oid, 'type'); + } + + /** + * getParent + * + * @param id int + * @return string/err + **/ + function getParent($oid) + { + return $this->getObjName($oid, 'parid'); + } + + /** + * getPath - get array of nodes in object's path + * + * @param id int + * @param flds string OPT + * @return array/err + **/ + function getPath($id, $flds='id') + { + $this->dbc->query("BEGIN"); + $a = $this->dbc->getRow("SELECT name, lft, rgt FROM {$this->treeTable} WHERE id='$id'"); + $res = $this->dbc->getAll(" + SELECT $flds FROM {$this->treeTable} WHERE lft<={$a['lft']} AND rgt>={$a['rgt']} + ORDER by lft + "); + $this->dbc->query("COMMIT"); + return $res; + } + + /** + * getDir - get array of childnodes + * + * @param id int + * @param flds string OPT + * @param order string OPT + * @return array/err + **/ + function getDir($id, $flds='id', $order='lft') + { + return $this->dbc->getAll(" + SELECT $flds FROM {$this->treeTable} WHERE parid='$id' ORDER BY $order + "); + } + + /** + * getSubTree + * + * @param id int OPT + * @param withRoot boolean OPT + * @return array/err + **/ + function getSubTree($id=NULL, $withRoot=FALSE) + { + if(is_null($id)) $id = $this->getRootNode(); + $r = array(); + if($withRoot) $r[] = $re = $this->dbc->getRow("SELECT id, name, level FROM {$this->treeTable} WHERE id='$id'"); + if(PEAR::isError($re)) return $re; + $dirarr = $this->getDir($id); if(PEAR::isError($dirarr)) return $dirarr; + foreach($dirarr as $k=>$snod) + { + $r[] = $re = $this->dbc->getRow("SELECT id, name, level FROM {$this->treeTable} WHERE id={$snod['id']}"); + if(PEAR::isError($re)) return $re; + $r = array_merge($r, $this->getSubTree($snod['id'])); + } + return $r; + } + + /** + * getRootNode - get id of root node + * + * @return int/err + **/ + function getRootNode() + { + return $this->getObjId($this->rootNodeName); + } + + /** + * getAllObjects + * + * @return array/err + **/ + function getAllObjects() + { + return $this->dbc->getAll("SELECT * FROM {$this->treeTable} ORDER BY lft"); + } + + /* --- info methods related to application structure: --- */ + /* (this part should be added/rewritten to allow defining/modifying/using application structure) */ + /* (only very simple structure definition - in config - supported now) */ + + /** + * getAllowedChildTypes + * + * @param type string + * @return array + **/ + function getAllowedChildTypes($type) + { + return $this->config['objtypes'][$type]; + } + + + /* ========== "private" methods: ========== */ + + + /** + * _dbRollback + * + * @param r object/string + * @return err + **/ + function _dbRollback($r) + { + $this->dbc->query("ROLLBACK"); + if(PEAR::isError($r)) return $r; + elseif(is_string($r)) return PEAR::raiseError("ERROR: ".get_class($this).": $r", ALIBERR_MTREE, PEAR_ERROR_RETURN); + else return PEAR::raiseError("ERROR: ".get_class($this).": unknown error", ALIBERR_MTREE, PEAR_ERROR_RETURN); + } + + /** + * _relocateSubtree - move subtree to another node without removing/adding + * + * @param id int + * @param newParid int + * @param after int + * @return boolean/err + **/ + function _relocateSubtree($id, $newParid, $after=NULL) + { + $this->dbc->query("BEGIN"); + $r = $this->dbc->query("LOCK TABLE {$this->treeTable}"); if(PEAR::isError($r)) return $r; + // obtain values for source node: + $a1 = $this->dbc->getRow("SELECT lft, rgt, level FROM {$this->treeTable} WHERE id='$id'"); + if(is_null($a1)) return $this->_dbRollback('_relocateSubtree: object not exists'); + extract($a1); + // values for destination node: + $a2 = $this->dbc->getRow("SELECT rgt, level FROM {$this->treeTable} WHERE id='$newParid'"); + if(is_null($a2)) return $this->_dbRollback('_relocateSubtree: new parent not exists'); + $nprgt = $a2['rgt']; $newLevel = $a2['level']; + // calculate differencies: + if(is_null($after)) $after = $nprgt-1; + $dif1 = $rgt-$lft+1; + $dif2 = $after-$lft+1; + $dif3 = $newLevel-$level+1; + // relocate the object" + $r = $this->dbc->query("UPDATE {$this->treeTable} SET parid='$newParid' WHERE id='$id'"); + if(PEAR::isError($r)) return $this->_dbRollback($r); + if($after>$rgt){ + // relocate subtree to the right: + $r = $this->dbc->query("UPDATE {$this->treeTable} SET rgt=rgt+$dif1 WHERE rgt>$after"); + if(PEAR::isError($r)) return $this->_dbRollback($r); + $r = $this->dbc->query("UPDATE {$this->treeTable} SET lft=lft+$dif1 WHERE lft>$after"); + if(PEAR::isError($r)) return $this->_dbRollback($r); + $r = $this->dbc->query("UPDATE {$this->treeTable} + SET lft=lft+$dif2, rgt=rgt+$dif2, level=level+$dif3 + WHERE lft>=$lft AND rgt <=$rgt"); + if(PEAR::isError($r)) return $this->_dbRollback($r); + $r = $this->dbc->query("UPDATE {$this->treeTable} SET rgt=rgt-$dif1 WHERE rgt>$rgt"); + if(PEAR::isError($r)) return $this->_dbRollback($r); + $r = $this->dbc->query("UPDATE {$this->treeTable} SET lft=lft-$dif1 WHERE lft>$rgt"); + if(PEAR::isError($r)) return $this->_dbRollback($r); + }else{ + // relocate subtree to the left: + $r = $this->dbc->query("UPDATE {$this->treeTable} SET rgt=rgt+$dif1 WHERE rgt>$after"); + if(PEAR::isError($r)) return $this->_dbRollback($r); + $r = $this->dbc->query("UPDATE {$this->treeTable} SET lft=lft+$dif1 WHERE lft>$after"); + if(PEAR::isError($r)) return $this->_dbRollback($r); + $r = $this->dbc->query("UPDATE {$this->treeTable} + SET lft=lft+$dif2-$dif1, rgt=rgt+$dif2-$dif1, level=level+$dif3 + WHERE lft>=$lft+$dif1 AND rgt <=$rgt+$dif1"); + if(PEAR::isError($r)) return $this->_dbRollback($r); + $r = $this->dbc->query("UPDATE {$this->treeTable} SET rgt=rgt-$dif1 WHERE rgt>$rgt+$dif1"); + if(PEAR::isError($r)) return $this->_dbRollback($r); + $r = $this->dbc->query("UPDATE {$this->treeTable} SET lft=lft-$dif1 WHERE lft>$rgt+$dif1"); + if(PEAR::isError($r)) return $this->_dbRollback($r); + } + $r = $this->dbc->query("COMMIT"); + if(PEAR::isError($r)) return $this->_dbRollback($r); + return TRUE; + } + + /** + * _copySubtree - recursive copyObj + * + * @param id int + * @param newParid int + * @param after int + * @return array + **/ + function _copySubtree($id, $newParid, $after=NULL) + { + $nid = $this->copyObj($id, $newParid, $after); + if(PEAR::isError($nid)) return $nid; + $dirarr = $this->getDir($id); if(PEAR::isError($dirarr)) return $dirarr; + foreach($dirarr as $k=>$snod) + { + $r = $this->_copySubtree($snod['id'], $nid); + if(PEAR::isError($r)) return $r; + } + } + + /* ========== test and debug methods: ========== */ + + /** + * dumpTree + * + * @param id int + * @param indstr string // indentation string + * @param ind string // aktual indentation + * @return string + **/ + function dumpTree($id=NULL, $indstr=' ', $ind='', $format='{name}', $withRoot=TRUE) + { + $r=''; + foreach($this->getSubTree($id, $withRoot) as $o) + $r .= str_repeat($indstr, intval($o['level'])). + preg_replace(array('|\{name\}|', '|\{id\}|'), array($o['name'], $o['id']), $format). + "\n"; + return $r; + } + + /** + * deleteData + * + **/ + function deleteData() + { + $this->dbc->query("DELETE FROM {$this->treeTable} WHERE parid is not null"); + } + + /** + * testData + * + * @param id int OPT + * @return array + **/ + function testData() + { + $o[] = $rootId = $this->getRootNode(); + $o[] = $p1 = $this->addObj('Publication A', 'Publication', $rootId); // 1 + $o[] = $p2 = $this->addObj('Publication B', 'Publication', $rootId); // 2 + $o[] = $i1 = $this->addObj('Issue 1', 'Issue', $p1); // 3 + $o[] = $i2 = $this->addObj('Issue 2', 'Issue', $p1); // 4 + $o[] = $s1 = $this->addObj('Section a', 'Section', $i2); + $o[] = $s2 = $this->addObj('Section b', 'Section', $i2); // 6 + $o[] = $s3 = $this->addObj('Section c', 'Section', $i2); + $o[] = $t1 = $this->addObj('Title', 'Title', $s2); + $o[] = $s4 = $this->addObj('Section a', 'Section', $i1); + $o[] = $s5 = $this->addObj('Section b', 'Section', $i1); + $this->tdata['tree'] = $o; + } + + /** + * test + * + **/ + function test() + { + $this->deleteData(); + $this->testData(); + $rootId = $this->getRootNode(); + $this->test_correct ="RootNode\n Publication A\n Issue 1\n Section a\n Section b\n Issue 2\n Section a\n Section b\n Title\n Section c\n Publication B\nRootNode\n"; + $this->test_dump = $this->dumpTree(); + $this->removeObj($this->tdata['tree'][1]); + $this->removeObj($this->tdata['tree'][2]); + $this->test_dump .= $this->dumpTree(); + $this->deleteData(); + if($this->test_dump == $this->test_correct){ $this->test_log.="tree: OK\n"; return TRUE; } + else return PEAR::raiseError('Mtree::test:', 1, PEAR_ERROR_DIE, '%s'. + "
\ncorrect:\n.{$this->test_correct}.\ndump:\n.{$this->test_dump}.\n
\n"); + } + + /** + * install - create tables + initialize + * + **/ + function install() + { + $this->dbc->query("CREATE TABLE {$this->treeTable} ( + id int not null, + name varchar(255) not null default'', + parid int, + lft int, + rgt int, + level int, + type varchar(255) not null default'', + param varchar(255) + )"); + $this->dbc->query("CREATE UNIQUE INDEX {$this->treeTable}_id_idx on {$this->treeTable} (id)"); + $this->dbc->query("CREATE INDEX {$this->treeTable}_name_idx on {$this->treeTable} (name)"); + $this->dbc->createSequence("{$this->treeTable}_id_seq"); + + $id = $this->dbc->nextId("{$this->treeTable}_id_seq"); + $this->dbc->query("INSERT INTO {$this->treeTable} (id, name, parid, level, lft, rgt, type) + VALUES ($id, '{$this->rootNodeName}', NULL, 0, 1, 2, 'RootNode')"); + } + + /** + * uninstall + * + **/ + function uninstall() + { + $this->dbc->query("DROP TABLE {$this->treeTable}"); + $this->dbc->dropSequence("{$this->treeTable}_id_seq"); + } + + /** + * reinstall + * + **/ + function reinstall() + { + $this->uninstall(); + $this->install(); + } +} +?> \ No newline at end of file diff --git a/livesupport/modules/alib/var/subj.php b/livesupport/modules/alib/var/subj.php new file mode 100644 index 000000000..02446fd04 --- /dev/null +++ b/livesupport/modules/alib/var/subj.php @@ -0,0 +1,441 @@ +subjTable = $config['tblNamePrefix'].'subjs'; + $this->smembTable = $config['tblNamePrefix'].'smemb'; + } + + /* ========== public methods: ========== */ + + /** + * addSubj + * + * @param login string + * @param pass string OPT + * @return int/err + **/ + function addSubj($login, $pass=NULL) + { + $id = $this->dbc->nextId("{$this->subjTable}_id_seq"); if(PEAR::isError($id)) return $id; + $r = $this->dbc->query(" + INSERT INTO {$this->subjTable} (id, login, pass, type) + VALUES ($id, '$login', ".(is_null($pass) ? "'!', 'G'" : "'".md5($pass)."', 'U'").") + "); + if(PEAR::isError($r)) return $r; + return $id; + } + + /** + * removeSubj + * + * @param login string + * @param uid int OPT + * @return boolean/err + **/ + function removeSubj($login, $uid=NULL) + { + if(is_null($uid)) $uid = $this->getSubjId($login); + if(PEAR::isError($uid)) return $uid; + $r = $this->dbc->query("DELETE FROM {$this->smembTable} WHERE (uid='$uid' OR gid='$uid') AND mid is null"); + if(PEAR::isError($r)) return $r; + $r = $this->dbc->query("DELETE FROM {$this->subjTable} WHERE login='$login'"); + if(PEAR::isError($r)) return $r; + return $this->_rebuildRels(); + } + + /** + * authenticate + * + * @param login string + * @param pass string OPT + * @return boolean/int/err + **/ + function authenticate($login, $pass='') + { + $cpass = md5($pass); + $id = $this->dbc->getOne(" + SELECT id FROM {$this->subjTable} + WHERE login='$login' AND pass='$cpass' AND type='U' + "); + if(PEAR::isError($id)) return $id; + return (is_null($id) ? FALSE : $id); + } + + /* --- groups --- */ + + /** + * addSubj2Gr - add {login} and direct/indirect members to {gname} and to groups, where {gname} is [in]direct member + * + * @param login string + * @param gname string + * @return int/err + **/ + function addSubj2Gr($login, $gname) + { + $uid = $this->getSubjId($login); if(PEAR::isError($uid)) return $uid; + $gid = $this->getSubjId($gname); if(PEAR::isError($gid)) return $gid; + $isgr = $this->isGroup($gid); if(PEAR::isError($isgr)) return $isgr; + if(!$isgr) return PEAR::raiseError("Subjects::addSubj2Gr: Not a group ($gname)", ALIBERR_NOTGR); + // add subject and all [in]direct members to group $gname: + $mid = $this->_plainAddSubj2Gr($uid, $gid); if(PEAR::isError($mid)) return $mid; + // add it to all groups where $gname is [in]direct member: + $marr = $this->_listRMemb($gid); if(PEAR::isError($marr)) return $marr; + foreach($marr as $k=>$v){ + $r = $this->_plainAddSubj2Gr($uid, $v['gid'], intval($v['level'])+1, $v['id']); + if(PEAR::isError($r)) return $r; + } + return $mid; + } + + /** + * removeSubjFromGr + * + * @param login string + * @param gname string + * @return boolean/err + **/ + function removeSubjFromGr($login, $gname) + { + $uid = $this->getSubjId($login); if(PEAR::isError($uid)) return $uid; + $gid = $this->getSubjId($gname); if(PEAR::isError($gid)) return $gid; + $mid = $this->dbc->getOne($q = "SELECT id FROM {$this->smembTable} WHERE uid='$uid' AND gid='$gid' AND mid is null"); + if(is_null($mid)) return FALSE; + if(PEAR::isError($mid)) return $mid; + // remove it: + $r = $this->_removeMemb($mid); if(PEAR::isError($r)) return $r; + // and rebuild indirect memberships: + $r = $this->_rebuildRels(); if(PEAR::isError($r)) return $r; + return TRUE; + } + + /* --- info methods: --- */ + + /** + * getSubjId + * + * @param login string + * @return int/err + **/ + function getSubjId($login) + { + return $this->dbc->getOne("SELECT id FROM {$this->subjTable} WHERE login='$login'"); + } + + /** + * getSubjName + * + * @param id int + * @param fld string + * @return string/err + **/ + function getSubjName($id, $fld='login') + { + return $this->dbc->getOne("SELECT $fld FROM {$this->subjTable} WHERE id='$id'"); + } + + /** + * getSubjects + * + * @param flds string OPT + * @return array/err + **/ + function getSubjects($flds='id, login') + { + return $this->dbc->getAll("SELECT $flds FROM {$this->subjTable}"); + } + + /** + * getSubjectsWCnt - get subjects with count of direct members + * + * @return array/err + **/ + function getSubjectsWCnt() + { + return $this->dbc->getAll("SELECT count(m.uid)as cnt, s.id, s.login, s.type + FROM {$this->subjTable} s LEFT JOIN {$this->smembTable} m ON m.gid=s.id + WHERE m.mid is null GROUP BY s.id, s.login, s.type ORDER BY s.id"); + } + + /** + * isGroup + * + * @param gid int + * @return boolean/err + **/ + function isGroup($gid) + { + $r = $this->dbc->getOne("SELECT type FROM {$this->subjTable} WHERE id='$gid'"); + if(PEAR::isError($r)) return $r; + return ($r === 'G' ); + } + + /** + * listGroup - list direct members of group + * + * @param gid int + * @return array/err + **/ + function listGroup($gid) + { + return $this->dbc->getAll("SELECT s.id, s.login, s.type FROM {$this->smembTable} m, {$this->subjTable} s + WHERE m.uid=s.id AND m.mid is null AND m.gid='$gid'"); + } + + /* ========== "private" methods: ========== */ + + /** + * _addMemb - create membership record + * + * @param uid int + * @param gid int + * @param level int OPT + * @param mid int OPT + * @return int/err + **/ + function _addMemb($uid, $gid, $level=0, $mid='null') + { + if($uid == $gid) return PEAR::raiseError("Subjects::_addMemb: uid==gid ($uid)", ALIBERR_BADSMEMB); + $a = $this->dbc->getAll("SELECT id, level, mid FROM {$this->smembTable} WHERE uid='$uid' AND gid='$gid' ORDER BY level ASC"); + if(PEAR::isError($a)) return $a; + if(count($a)>0){ + $a0 = $a[0]; + $id = $a0['id']; + if($level < intval($a0['level'])){ + $r = $this->dbc->query("UPDATE {$this->smembTable} SET level='$level', mid='$mid' WHERE id='{$a0['id']}'"); + if(PEAR::isError($r)) return $r; + } + }else{ + $id = $this->dbc->nextId("{$this->smembTable}_id_seq"); if(PEAR::isError($id)) return $id; + $r = $this->dbc->query(" + INSERT INTO {$this->smembTable} (id, uid, gid, level, mid) VALUES ($id, $uid, $gid, $level, $mid) + "); + if(PEAR::isError($r)) return $r; + } + return $id; + } + + /** + * _removeMemb + * + * @param mid int + * @return null/err + **/ + function _removeMemb($mid) + { + return $this->dbc->query("DELETE FROM {$this->smembTable} WHERE id='$mid'"); + } + + /** + * _listMemb - list [in]direct members of group + * + * @param gid int + * @param uid int OPT + * @return array/err + **/ + function _listMemb($gid, $uid=NULL) + { + return $this->dbc->getAll("SELECT id, uid, level FROM {$this->smembTable} WHERE gid='$gid'".(is_null($uid) ? '' : " AND uid='$uid'")); + } + + /** + * _listRMemb - list groups where uid is [in]direct member + * + * @param gid int + * @param uid int OPT + * @return array/err + **/ + function _listRMemb($uid, $gid=NULL) + { + return $this->dbc->getAll("SELECT id, gid, level FROM {$this->smembTable} WHERE uid='$uid'".(is_null($gid) ? '' : " AND gid='$gid'")); + } + + /** + * _plainAddSubj2Gr - add uid and its [in]direct members to gid + * + * @param uid int + * @param gid int + * @param level int + * @param rmid int // + * @return int/err + **/ + function _plainAddSubj2Gr($uid, $gid, $level=0, $rmid='null') + { + $mid = $this->_addMemb($uid, $gid, $level, $rmid); if(PEAR::isError($mid)) return $mid; + $marr = $this->_listMemb($uid); if(PEAR::isError($marr)) return $marr; + foreach($marr as $k=>$v){ + $r = $this->_addMemb($v['uid'], $gid, intval($v['level'])+$level+1, $mid); + if(PEAR::isError($r)) return $r; + } + return $mid; + } + + /** + * _rebuildRels - rebuild indirect membership records + * + * @return true/err + **/ + function _rebuildRels() + { + $this->dbc->query("BEGIN"); + $r = $this->dbc->query("LOCK TABLE {$this->smembTable}"); if(PEAR::isError($r)) return $r; + $r = $this->dbc->query("DELETE FROM {$this->smembTable} WHERE mid is not null"); + if(PEAR::isError($r)) return $r; + $arr = $this->dbc->getAll("SELECT uid, gid FROM {$this->smembTable}"); // WHERE mid is null + if(PEAR::isError($arr)) return $arr; + foreach($arr as $it){ + $marr = $this->_listRMemb($it['gid']); if(PEAR::isError($marr)) return $marr; + foreach($marr as $k=>$v){ + $r = $this->_plainAddSubj2Gr($it['uid'], $v['gid'], intval($v['level'])+1, $v['id']); + if(PEAR::isError($r)) return $r; + } + } + $r = $this->dbc->query("COMMIT"); if(PEAR::isError($r)) return $r; + return TRUE; + } + + /* ========== test and debug methods: ========== */ + + /** + * dumpSubjects + * + * @param indstr string // indentation string + * @param ind string // aktual indentation + * @return string + **/ + function dumpSubjects($indstr=' ', $ind='') + { +# $r = $ind.join(', ', $this->dbc->getCol("SELECT login FROM {$this->subjTable}"))."\n"; + $r = $ind.join(', ', array_map(create_function('$v', 'return "{$v[\'login\']}({$v[\'cnt\']})";'), $this->getSubjectsWCnt()))."\n"; + return $r; + } + + /** + * deleteData + * + * @return void + **/ + function deleteData() + { + $this->dbc->query("DELETE FROM {$this->subjTable}"); + $this->dbc->query("DELETE FROM {$this->smembTable}"); + parent::deleteData(); + } + + /** + * testData + * + * @return array + **/ + function testData() + { + parent::testData(); + $o[] = $this->addSubj('root', 'q'); + $o[] = $this->addSubj('test1', 'a'); + $o[] = $this->addSubj('test2', 'a'); + $o[] = $this->addSubj('test3', 'a'); + $o[] = $this->addSubj('test4', 'a'); + $o[] = $this->addSubj('gr1'); + $o[] = $this->addSubj('gr2'); +# $this->addSubj2Gr('test1', 'gr1'); + $this->addSubj2Gr('test2', 'gr1'); + $this->addSubj2Gr('test3', 'gr1'); + $this->addSubj2Gr('test4', 'gr2'); + $this->addSubj2Gr('gr2', 'gr1'); + $o[] = $this->addSubj('gr3'); + $this->addSubj2Gr('test3', 'gr3'); + $this->addSubj2Gr('test1', 'gr3'); + $this->addSubj2Gr('gr3', 'gr2'); + return $this->tdata['subjects'] = $o; + } + + /** + * test + * + **/ + function test() + { + if(PEAR::isError($p = parent::test())) return $p; + $this->deleteData(); + $this->testData(); + $this->test_correct = "root(0), test1(0), test2(0), test3(0), test4(0), gr1(3), gr2(2), gr3(2)\n"; + $this->test_dump = $this->dumpSubjects(); + $this->removeSubj('test1'); + $this->removeSubj('test3'); + $this->removeSubjFromGr('test2', 'gr1'); + $this->removeSubjFromGr('gr3', 'gr2'); + $this->test_correct .= "root(0), test2(0), test4(0), gr1(1), gr2(1), gr3(0)\n"; + $this->test_dump .= $this->dumpSubjects(); + $this->deleteData(); + if($this->test_dump == $this->test_correct){ $this->test_log.="subj: OK\n"; return TRUE; } + else return PEAR::raiseError('Subjects::test:', 1, PEAR_ERROR_DIE, '%s'. + "
\ncorrect:\n{$this->test_correct}\ndump:\n{$this->test_dump}\n
\n"); + } + + /** + * install - create tables + initialize + * + **/ + function install() + { + parent::install(); + $this->dbc->query("CREATE TABLE {$this->subjTable} ( + id int not null, + login varchar(255) not null default'', + pass varchar(255) not null default'', + type char(1) not null default 'U' + )"); + $this->dbc->query("CREATE UNIQUE INDEX {$this->subjTable}_id_idx on {$this->subjTable} (id)"); + $this->dbc->query("CREATE UNIQUE INDEX {$this->subjTable}_login_idx on {$this->subjTable} (login)"); + $this->dbc->createSequence("{$this->subjTable}_id_seq"); + + $this->dbc->query("CREATE TABLE {$this->smembTable} ( + id int not null, + uid int not null default 0, + gid int not null default 0, + level int not null default 0, + mid int + )"); + $this->dbc->query("CREATE UNIQUE INDEX {$this->smembTable}_id_idx on {$this->smembTable} (id)"); + $this->dbc->createSequence("{$this->smembTable}_id_seq"); + + } + + /** + * uninstall + * + * @return void + **/ + function uninstall() + { + $this->dbc->query("DROP TABLE {$this->subjTable}"); + $this->dbc->dropSequence("{$this->subjTable}_id_seq"); + $this->dbc->query("DROP TABLE {$this->smembTable}"); + $this->dbc->dropSequence("{$this->smembTable}_id_seq"); + parent::uninstall(); + } +} +?> \ No newline at end of file diff --git a/livesupport/modules/alib/var/xmlrpc/alib_xr.php b/livesupport/modules/alib/var/xmlrpc/alib_xr.php new file mode 100644 index 000000000..a51d976b3 --- /dev/null +++ b/livesupport/modules/alib/var/xmlrpc/alib_xr.php @@ -0,0 +1,99 @@ +$v) if($struct) $r[$k]=v2xr($v); else $r[]=v2xr($v); + return new xmlrpcval($r, ($struct?"struct":"array")); + }else if(is_int($var)){ + return new xmlrpcval($var, "int"); + }else{ + return new xmlrpcval($var, "string"); + } +} + +class XR_Alib extends alib{ + function xr_test($input){ + $p1=$input->getParam(0); + if(isset($p1) && $p1->scalartyp()=="string") $s=$p1->scalarval(); + else return new xmlrpcresp(0, 801, "xr_login: wrong 1st parameter, string expected."); + $p2=$input->getParam(1); + if(isset($p2) && $p2->scalartyp()=="string") $sessid=$p2->scalarval(); + else return new xmlrpcresp(0, 801, "xr_login: wrong 2nd parameter, string expected."); + return new xmlrpcresp(v2xr(strtoupper($s)."_".$this->getSessLogin($sessid)."_".$sessid, false)); + } + function xr_login($input){ + $p1=$input->getParam(0); + if(isset($p1) && $p1->scalartyp()=="string") $login=$p1->scalarval(); + else return new xmlrpcresp(0, 801, "xr_login: wrong 1st parameter, string expected."); + $p2=$input->getParam(1); + if(isset($p2) && $p2->scalartyp()=="string") $pass=$p2->scalarval(); + else return new xmlrpcresp(0, 801, "xr_login: wrong 2nd parameter, string expected."); + if(!($res = $this->login($login, $pass))) + return new xmlrpcresp(0, 802, "xr_login: login failed - incorrect username or password."); + else + return new xmlrpcresp(v2xr($res, false)); + } + function xr_logout($input){ + $p1=$input->getParam(0); + if(isset($p1) && $p1->scalartyp()=="string") $sessid=$p1->scalarval(); + else return new xmlrpcresp(0, 801, "xr_login: wrong 2nd parameter, string expected."); + $res = $this->logout($sessid); + if(!PEAR::isError($res)) return new xmlrpcresp(v2xr('Bye', false)); + else return new xmlrpcresp(0, 803, "xr_logout: logout failed - not logged."); + } + function xr_getDir($input){ + $p1=$input->getParam(0); + if(isset($p1) && ($p1->scalartyp()=="int") && is_numeric($id=$p1->scalarval())); + else return new xmlrpcresp(0, 801, "xr_getDir: wrong 1st parameter, int expected."); + $res = $this->getDir($id, 'name'); + return new xmlrpcresp(v2xr($res, false)); + } + function xr_getPath($input){ + $p1=$input->getParam(0); + if(isset($p1) && ($p1->scalartyp()=="int") && is_numeric($id=$p1->scalarval())); + else return new xmlrpcresp(0, 801, "xr_getPath: wrong 1st parameter, int expected."); + $res = $this->getPath($id, 'id, name'); + return new xmlrpcresp(v2xr($res, false)); + } +} + +$alib = &new XR_Alib($dbc, $config); + +$s=new xmlrpc_server( array( + "alib.xrTest" => array( + "function" => array(&$alib, 'xr_test'), + "signature" => array(array($xmlrpcString, $xmlrpcString, $xmlrpcString)), + "docstring" => "" + ), + "alib.login" => array( + "function" => array(&$alib, 'xr_login'), + "signature" => array(array($xmlrpcString, $xmlrpcString, $xmlrpcString)), + "docstring" => "" + ), + "alib.logout" => array( + "function" => array(&$alib, 'xr_logout'), + "signature" => array(array($xmlrpcString, $xmlrpcString)), + "docstring" => "" + ), + "alib.getDir" => array( + "function" => array(&$alib, 'xr_getDir'), + "signature" => array(array($xmlrpcArray, $xmlrpcInt)), + "docstring" => "returns directory listing of object with given id" + ), + "alib.getPath" => array( + "function" => array(&$alib, 'xr_getPath'), + "signature" => array(array($xmlrpcArray, $xmlrpcInt)), + "docstring" => "returns listing of object in path from rootnode to object with given id" + ) +)); + +#header("Content-type: text/plain"); +#print_r($dirlist = getDir()); + +require_once"../example/alib_f.php"; +?> \ No newline at end of file diff --git a/livesupport/modules/alib/var/xmlrpc/index.php b/livesupport/modules/alib/var/xmlrpc/index.php new file mode 100644 index 000000000..f4ead1066 --- /dev/null +++ b/livesupport/modules/alib/var/xmlrpc/index.php @@ -0,0 +1,7 @@ + diff --git a/livesupport/modules/alib/var/xmlrpc/xmlrpc.inc b/livesupport/modules/alib/var/xmlrpc/xmlrpc.inc new file mode 100644 index 000000000..99a7af3da --- /dev/null +++ b/livesupport/modules/alib/var/xmlrpc/xmlrpc.inc @@ -0,0 +1,1489 @@ + +// $Id: xmlrpc.inc,v 1.1 2004/07/23 00:22:13 tomas Exp $ + + +// Copyright (c) 1999,2000,2002 Edd Dumbill. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// * Neither the name of the "XML-RPC for PHP" nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. + + if (!function_exists('xml_parser_create')) + { + // Win 32 fix. From: 'Leo West' + if($WINDIR) + { + dl('php3_xml.dll'); + } + else + { + dl('xml.so'); + } + } + + $xmlrpcI4='i4'; + $xmlrpcInt='int'; + $xmlrpcBoolean='boolean'; + $xmlrpcDouble='double'; + $xmlrpcString='string'; + $xmlrpcDateTime='dateTime.iso8601'; + $xmlrpcBase64='base64'; + $xmlrpcArray='array'; + $xmlrpcStruct='struct'; + + $xmlrpcTypes=array( + $xmlrpcI4 => 1, + $xmlrpcInt => 1, + $xmlrpcBoolean => 1, + $xmlrpcString => 1, + $xmlrpcDouble => 1, + $xmlrpcDateTime => 1, + $xmlrpcBase64 => 1, + $xmlrpcArray => 2, + $xmlrpcStruct => 3 + ); + + $xmlEntities=array( + 'amp' => '&', + 'quot' => '"', + 'lt' => '<', + 'gt' => '>', + 'apos' => "'" + ); + + $xmlrpcerr['unknown_method']=1; + $xmlrpcstr['unknown_method']='Unknown method'; + $xmlrpcerr['invalid_return']=2; + $xmlrpcstr['invalid_return']='Invalid return payload: enabling debugging to examine incoming payload'; + $xmlrpcerr['incorrect_params']=3; + $xmlrpcstr['incorrect_params']='Incorrect parameters passed to method'; + $xmlrpcerr['introspect_unknown']=4; + $xmlrpcstr['introspect_unknown']="Can't introspect: method unknown"; + $xmlrpcerr['http_error']=5; + $xmlrpcstr['http_error']="Didn't receive 200 OK from remote server."; + $xmlrpcerr['no_data']=6; + $xmlrpcstr['no_data']='No data received from server.'; + $xmlrpcerr['no_ssl']=7; + $xmlrpcstr['no_ssl']='No SSL support compiled in.'; + $xmlrpcerr['curl_fail']=8; + $xmlrpcstr['curl_fail']='CURL error'; + + + $xmlrpcerr["multicall_notstruct"] = 9; + $xmlrpcstr["multicall_notstruct"] = "system.multicall expected struct"; + $xmlrpcerr["multicall_nomethod"] = 10; + $xmlrpcstr["multicall_nomethod"] = "missing methodName"; + $xmlrpcerr["multicall_notstring"] = 11; + $xmlrpcstr["multicall_notstring"] = "methodName is not a string"; + $xmlrpcerr["multicall_recursion"] = 12; + $xmlrpcstr["multicall_recursion"] = "recursive system.multicall forbidden"; + $xmlrpcerr["multicall_noparams"] = 13; + $xmlrpcstr["multicall_noparams"] = "missing params"; + $xmlrpcerr["multicall_notarray"] = 14; + $xmlrpcstr["multicall_notarray"] = "params is not an array"; + + $xmlrpc_defencoding='UTF-8'; + + $xmlrpcName='XML-RPC for PHP'; + $xmlrpcVersion='1.0.99'; + + // let user errors start at 800 + $xmlrpcerruser=800; + // let XML parse errors start at 100 + $xmlrpcerrxml=100; + + // formulate backslashes for escaping regexp + $xmlrpc_backslash=chr(92).chr(92); + + // used to store state during parsing + // quick explanation of components: + // st - used to build up a string for evaluation + // ac - used to accumulate values + // qt - used to decide if quotes are needed for evaluation + // cm - used to denote struct or array (comma needed) + // isf - used to indicate a fault + // lv - used to indicate "looking for a value": implements + // the logic to allow values with no types to be strings + // params - used to store parameters in method calls + // method - used to store method name + + $_xh=array(); + + function xmlrpc_entity_decode($string) + { + $top=split('&', $string); + $op=''; + $i=0; + while($i "; + break; + case 'BOOLEAN': + // special case here: we translate boolean 1 or 0 into PHP + // constants true or false + if ($_xh[$parser]['ac']=='1') + { + $_xh[$parser]['ac']='true'; + } + else + { + $_xh[$parser]['ac']='false'; + $_xh[$parser]['vt']=strtolower($name); + // Drop through intentionally. + } + case 'I4': + case 'INT': + case 'STRING': + case 'DOUBLE': + case 'DATETIME.ISO8601': + case 'BASE64': + if ($_xh[$parser]['qt']==1) + { + // we use double quotes rather than single so backslashification works OK + $_xh[$parser]['st'].='"'. $_xh[$parser]['ac'] . '"'; + } + elseif ($_xh[$parser]['qt']==2) + { + $_xh[$parser]['st'].="base64_decode('". $_xh[$parser]['ac'] . "')"; + } + elseif ($name=='BOOLEAN') + { + $_xh[$parser]['st'].=$_xh[$parser]['ac']; + } + else + { + // we have an I4, INT or a DOUBLE + // we must check that only 0123456789-. are characters here + if (!ereg("^\-?[0123456789 \t\.]+$", $_xh[$parser]['ac'])) + { + // TODO: find a better way of throwing an error + // than this! + error_log('XML-RPC: non numeric value received in INT or DOUBLE'); + $_xh[$parser]['st'].='ERROR_NON_NUMERIC_FOUND'; + } + else + { + // it's ok, add it on + $_xh[$parser]['st'].=$_xh[$parser]['ac']; + } + } + $_xh[$parser]['ac']=''; $_xh[$parser]['qt']=0; + $_xh[$parser]['lv']=3; // indicate we've found a value + break; + case 'VALUE': + // deal with a string value + if (strlen($_xh[$parser]['ac'])>0 && + $_xh[$parser]['vt']==$xmlrpcString) + { + $_xh[$parser]['st'].='"'. $_xh[$parser]['ac'] . '"'; + } + // This if() detects if no scalar was inside + // and pads an empty ''. + if($_xh[$parser]['st'][strlen($_xh[$parser]['st'])-1] == '(') + { + $_xh[$parser]['st'].= '""'; + } + $_xh[$parser]['st'].=", '" . $_xh[$parser]['vt'] . "')"; + if ($_xh[$parser]['cm']) + { + $_xh[$parser]['st'].=','; + } + break; + case 'MEMBER': + $_xh[$parser]['ac']=''; $_xh[$parser]['qt']=0; + break; + case 'DATA': + $_xh[$parser]['ac']=''; $_xh[$parser]['qt']=0; + break; + case 'PARAM': + $_xh[$parser]['params'][]=$_xh[$parser]['st']; + break; + case 'METHODNAME': + $_xh[$parser]['method']=ereg_replace("^[\n\r\t ]+", '', $_xh[$parser]['ac']); + break; + case 'BOOLEAN': + // special case here: we translate boolean 1 or 0 into PHP + // constants true or false + if ($_xh[$parser]['ac']=='1') + { + $_xh[$parser]['ac']='true'; + } + else + { + $_xh[$parser]['ac']='false'; + $_xh[$parser]['vt']=strtolower($name); + } + break; + default: + break; + } + // if it's a valid type name, set the type + if (isset($xmlrpcTypes[strtolower($name)])) + { + $_xh[$parser]['vt']=strtolower($name); + } + } + + function xmlrpc_cd($parser, $data) + { + global $_xh, $xmlrpc_backslash; + + //if (ereg("^[\n\r \t]+$", $data)) return; + // print "adding [${data}]\n"; + + if ($_xh[$parser]['lv']!=3) + { + // "lookforvalue==3" means that we've found an entire value + // and should discard any further character data + if ($_xh[$parser]['lv']==1) + { + // if we've found text and we're just in a then + // turn quoting on, as this will be a string + $_xh[$parser]['qt']=1; + // and say we've found a value + $_xh[$parser]['lv']=2; + } + if(!@isset($_xh[$parser]['ac'])) + { + $_xh[$parser]['ac'] = ''; + } + $_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data))); + } + } + + function xmlrpc_dh($parser, $data) + { + global $_xh; + if (substr($data, 0, 1) == '&' && substr($data, -1, 1) == ';') + { + if ($_xh[$parser]['lv']==1) + { + $_xh[$parser]['qt']=1; + $_xh[$parser]['lv']=2; + } + $_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data))); + } + } + + class xmlrpc_client + { + var $path; + var $server; + var $port; + var $errno; + var $errstring; + var $debug=0; + var $username=''; + var $password=''; + var $cert=''; + var $certpass=''; + var $verifypeer=1; + var $verifyhost=1; + var $no_multicall=false; + + function xmlrpc_client($path, $server, $port=0) + { + $this->port=$port; $this->server=$server; $this->path=$path; + } + + function setDebug($in) + { + if ($in) + { + $this->debug=1; + } + else + { + $this->debug=0; + } + } + + function setCredentials($u, $p) + { + $this->username=$u; + $this->password=$p; + } + + function setCertificate($cert, $certpass) + { + $this->cert = $cert; + $this->certpass = $certpass; + } + + function setSSLVerifyPeer($i) + { + $this->verifypeer = $i; + } + + function setSSLVerifyHost($i) + { + $this->verifyhost = $i; + } + + function send($msg, $timeout=0, $method='http') + { + if (is_array($msg)) + { + // $msg is an array of xmlrpcmsg's + return $this->multicall($msg, $timeout, $method); + } + + // where msg is an xmlrpcmsg + $msg->debug=$this->debug; + + if ($method == 'https') + { + return $this->sendPayloadHTTPS($msg, + $this->server, + $this->port, $timeout, + $this->username, $this->password, + $this->cert, + $this->certpass); + } + else + { + return $this->sendPayloadHTTP10($msg, $this->server, $this->port, + $timeout, $this->username, + $this->password); + } + } + + function sendPayloadHTTP10($msg, $server, $port, $timeout=0,$username='', $password='') + { + global $xmlrpcerr, $xmlrpcstr; + if ($port==0) + { + $port=80; + } + if($timeout>0) + { + $fp=fsockopen($server, $port,$this->errno, $this->errstr, $timeout); + } + else + { + $fp=fsockopen($server, $port,$this->errno, $this->errstr); + } + if (!$fp) + { + $this->errstr='Connect error'; + $r=new xmlrpcresp(0, $xmlrpcerr['http_error'],$xmlrpcstr['http_error']); + return $r; + } + // Only create the payload if it was not created previously + if(empty($msg->payload)) + { + $msg->createPayload(); + } + + // thanks to Grant Rauscher + // for this + $credentials=''; + if ($username!='') + { + $credentials='Authorization: Basic ' . base64_encode($username . ':' . $password) . "\r\n"; + } + + // "Host: ". $this->server . ":" . $this->port . "\r\n" . + + $op= "POST " . $this->path. " HTTP/1.0\r\nUser-Agent: PHP XMLRPC 1.0\r\n" . + "Host: ". $this->server . "\r\n" . + $credentials . + "Content-Type: text/xml\r\nContent-Length: " . + strlen($msg->payload) . "\r\n\r\n" . + $msg->payload; + + if (!fputs($fp, $op, strlen($op))) + { + $this->errstr='Write error'; + $r=new xmlrpcresp(0, $xmlrpcerr['http_error'], $xmlrpcstr['http_error']); + return $r; + } + $resp=$msg->parseResponseFile($fp); + fclose($fp); + return $resp; + } + + // contributed by Justin Miller + // requires curl to be built into PHP + function sendPayloadHTTPS($msg, $server, $port, $timeout=0,$username='', $password='', $cert='',$certpass='') + { + global $xmlrpcerr, $xmlrpcstr; + if ($port == 0) + { + $port = 443; + } + + // Only create the payload if it was not created previously + if(empty($msg->payload)) + { + $msg->createPayload(); + } + + if (!function_exists('curl_init')) + { + $this->errstr='SSL unavailable on this install'; + $r=new xmlrpcresp(0, $xmlrpcerr['no_ssl'], $xmlrpcstr['no_ssl']); + return $r; + } + + $curl = curl_init("https://" . $server . ':' . $port . $this->path); + + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + // results into variable + if ($this->debug) + { + curl_setopt($curl, CURLOPT_VERBOSE, 1); + } + curl_setopt($curl, CURLOPT_USERAGENT, 'PHP XMLRPC 1.0'); + // required for XMLRPC + curl_setopt($curl, CURLOPT_POST, 1); + // post the data + curl_setopt($curl, CURLOPT_POSTFIELDS, $msg->payload); + // the data + curl_setopt($curl, CURLOPT_HEADER, 1); + // return the header too + curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: text/xml')); + // whether to verify remote host's cert + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verifypeer); + // whether to verify cert's common name (CN); 0 for no, 1 to verify that it exists, and 2 to verify that it matches the hostname used + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $this->verifyhost); + // required for XMLRPC + if ($timeout) + { + curl_setopt($curl, CURLOPT_TIMEOUT, $timeout == 1 ? 1 : $timeout - 1); + } + // timeout is borked + if ($username && $password) + { + curl_setopt($curl, CURLOPT_USERPWD,"$username:$password"); + } + // set auth stuff + if ($cert) + { + curl_setopt($curl, CURLOPT_SSLCERT, $cert); + } + // set cert file + if ($certpass) + { + curl_setopt($curl, CURLOPT_SSLCERTPASSWD,$certpass); + } + // set cert password + + $result = curl_exec($curl); + + if (!$result) + { + $this->errstr='no response'; + $resp=new xmlrpcresp(0, $xmlrpcerr['curl_fail'], $xmlrpcstr['curl_fail']. ': '. curl_error($curl)); + } + else + { + $resp = $msg->parseResponse($result); + } + curl_close($curl); + return $resp; + } + + function multicall($msgs, $timeout=0, $method='http') + { + $results = false; + + if (! $this->no_multicall) + { + $results = $this->_try_multicall($msgs, $timeout, $method); + /* TODO - this is not php3-friendly */ + // if($results !== false) + if($results != false) + { + // Either the system.multicall succeeded, or the send + // failed (e.g. due to HTTP timeout). In either case, + // we're done for now. + return $results; + } + else + { + // system.multicall unsupported by server, + // don't try it next time... + $this->no_multicall = true; + } + } + + // system.multicall is unupported by server: + // Emulate multicall via multiple requests + $results = array(); + //foreach($msgs as $msg) + @reset($msgs); + while(list(,$msg) = @each($msgs)) + { + $results[] = $this->send($msg, $timeout, $method); + } + return $results; + } + + // Attempt to boxcar $msgs via system.multicall. + function _try_multicall($msgs, $timeout, $method) + { + // Construct multicall message + $calls = array(); + //foreach($msgs as $msg) + @reset($msgs); + while(list(,$msg) = @each($msgs)) + { + $call['methodName'] = new xmlrpcval($msg->method(),'string'); + $numParams = $msg->getNumParams(); + $params = array(); + for ($i = 0; $i < $numParams; $i++) + { + $params[$i] = $msg->getParam($i); + } + $call['params'] = new xmlrpcval($params, 'array'); + $calls[] = new xmlrpcval($call, 'struct'); + } + $multicall = new xmlrpcmsg('system.multicall'); + $multicall->addParam(new xmlrpcval($calls, 'array')); + + // Attempt RPC call + $result = $this->send($multicall, $timeout, $method); + if (!is_object($result)) + return ($result || 0); // transport failed + + if ($result->faultCode() != 0) + return false; // system.multicall failed + + // Unpack responses. + $rets = $result->value(); + if ($rets->kindOf() != 'array') + return false; // bad return type from system.multicall + $numRets = $rets->arraysize(); + if ($numRets != count($msgs)) + return false; // wrong number of return values. + + $response = array(); + for ($i = 0; $i < $numRets; $i++) + { + $val = $rets->arraymem($i); + switch ($val->kindOf()) + { + case 'array': + if ($val->arraysize() != 1) + return false; // Bad value + // Normal return value + $response[$i] = new xmlrpcresp($val->arraymem(0)); + break; + case 'struct': + $code = $val->structmem('faultCode'); + if ($code->kindOf() != 'scalar' || $code->scalartyp() != 'int') + return false; + $str = $val->structmem('faultString'); + if ($str->kindOf() != 'scalar' || $str->scalartyp() != 'string') + return false; + $response[$i] = new xmlrpcresp(0, $code->scalarval(), $str->scalarval()); + break; + default: + return false; + } + } + return $response; + } + } // end class xmlrpc_client + + class xmlrpcresp + { + var $xv; + var $fn; + var $fs; + var $hdrs; + + function xmlrpcresp($val, $fcode=0, $fstr='',$waserror=0) + { + //print "waserror=$waserror
"; + if(($fcode != 0) || ($waserror != 0)) + { + $this->xv = 0; + $this->fn = $fcode; + $this->fs = htmlspecialchars($fstr); + } + else + { + $this->xv = $val; + $this->fn = 0; + } + } + + function faultCode() + { + if(isset($this->fn)) + { + if($this->fn == 0) + { + return -1; + } + else + { + return $this->fn; + } + } + else + { + return 0; + } + } + + function faultString() + { + return $this->fs; + } + + function value() + { + return $this->xv; + } + + function serialize() + { + $rs="\n"; + if ($this->fn) + { + $rs.=' + + + +faultCode +' . $this->fn . ' + + +faultString +' . $this->fs . ' + + + +'; + } + else + { + $rs.="\n\n" . $this->xv->serialize() . + "\n"; + } + $rs.="\n"; + return $rs; + } + } + + class xmlrpcmsg + { + var $payload; + var $methodname; + var $params=array(); + var $debug=0; + + function xmlrpcmsg($meth, $pars=0) + { + $this->methodname=$meth; + if (is_array($pars) && sizeof($pars)>0) + { + for($i=0; $iaddParam($pars[$i]); + } + } + } + + function xml_header() + { + return "\n\n"; + } + + function xml_footer() + { + return "\n"; + } + + function createPayload() + { + $this->payload=$this->xml_header(); + $this->payload.="" . $this->methodname . "\n"; + // if (sizeof($this->params)) { + $this->payload.="\n"; + for($i=0; $iparams); $i++) + { + $p=$this->params[$i]; + $this->payload.="\n" . $p->serialize() . + "\n"; + } + $this->payload.="\n"; + // } + $this->payload.=$this->xml_footer(); + $this->payload=str_replace("\n", "\r\n", $this->payload); + } + + function method($meth='') + { + if ($meth!='') + { + $this->methodname=$meth; + } + return $this->methodname; + } + + function serialize() + { + $this->createPayload(); + return $this->payload; + } + + function addParam($par) { $this->params[]=$par; } + function getParam($i) { return $this->params[$i]; } + function getNumParams() { return sizeof($this->params); } + + function parseResponseFile($fp) + { + $ipd=''; + while($data=fread($fp, 32768)) + { + $ipd.=$data; + } + return $this->parseResponse($ipd); + } + + function parseResponse($data='') + { + global $_xh,$xmlrpcerr,$xmlrpcstr; + global $xmlrpc_defencoding; + + $parser = xml_parser_create($xmlrpc_defencoding); + + $_xh[$parser]=array(); + + $_xh[$parser]['st']=''; + $_xh[$parser]['cm']=0; + $_xh[$parser]['isf']=0; + $_xh[$parser]['ac']=''; + $_xh[$parser]['qt']=''; + $_xh[$parser]['ha']=''; + + xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); + xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee'); + xml_set_character_data_handler($parser, 'xmlrpc_cd'); + xml_set_default_handler($parser, 'xmlrpc_dh'); + $xmlrpc_value=new xmlrpcval; + + $hdrfnd = 0; + if($this->debug) + { + //by maHo, replaced htmlspecialchars with htmlentities + print "
---GOT---\n" . htmlentities($data) . "\n---END---\n
"; + } + if($data == '') + { + error_log('No response received from server.'); + $r = new xmlrpcresp(0, $xmlrpcerr['no_data'], $xmlrpcstr['no_data']); + xml_parser_free($parser); + return $r; + } + // see if we got an HTTP 200 OK, else bomb + // but only do this if we're using the HTTP protocol. + if(ereg("^HTTP",$data) && !ereg("^HTTP/[0-9\.]+ 200 ", $data)) + { + $errstr= substr($data, 0, strpos($data, "\n")-1); + error_log('HTTP error, got response: ' .$errstr); + $r=new xmlrpcresp(0, $xmlrpcerr['http_error'], $xmlrpcstr['http_error']. ' (' . $errstr . ')'); + xml_parser_free($parser); + return $r; + } + + // if using HTTP, then gotta get rid of HTTP headers here + // and we store them in the 'ha' bit of our data array + if (ereg("^HTTP", $data)) + { + $ar=explode("\r\n", $data); + $newdata=''; + $hdrfnd=0; + for ($i=0; $i0) + { + $_xh[$parser]['ha'].=$ar[$i]. "\r\n"; + } + else + { + $hdrfnd=1; + } + } + else + { + $newdata.=$ar[$i] . "\r\n"; + } + } + $data=$newdata; + } + + if ($this->debug) + { + @reset($_xh[$parser]['ha']); + while (list($x,$header) = @each($_xh[$parser]['ha'])) + { + echo "HEADER: $header\n"; + } + } + // end Patch + if (!xml_parse($parser, $data, sizeof($data))) + { + // thanks to Peter Kocks + if((xml_get_current_line_number($parser)) == 1) + { + $errstr = 'XML error at line 1, check URL'; + } + else + { + $errstr = sprintf('XML error: %s at line %d', + xml_error_string(xml_get_error_code($parser)), + xml_get_current_line_number($parser)); + error_log($errstr); + $r=new xmlrpcresp(0, $xmlrpcerr['invalid_return'], $xmlrpcstr['invalid_return']); + xml_parser_free($parser); + echo $errstr; + return $r; + } + } + xml_parser_free($parser); + if ($this->debug) + { + print "
---EVALING---[" . 
+				strlen($_xh[$parser]['st']) . " chars]---\n" . 
+				htmlspecialchars($_xh[$parser]['st']) . ";\n---END---
"; + } + if (strlen($_xh[$parser]['st'])==0) + { + // then something odd has happened + // and it's time to generate a client side error + // indicating something odd went on + $r=new xmlrpcresp(0, $xmlrpcerr["invalid_return"], + $xmlrpcstr["invalid_return"]); + } + else + { + eval('$v=' . $_xh[$parser]['st'] . '; $allOK=1;'); + if ($_xh[$parser]['isf']) + { + $f=$v->structmem('faultCode'); + $fs=$v->structmem('faultString'); + + $r = new xmlrpcresp($v, $f->scalarval(), + $fs->scalarval(),1 /* even if errornum=0, indicate that there is error. modified by maHo */ + ); + + } + else + { + $r=new xmlrpcresp($v); + } + } + $r->hdrs = @split("\r?\n", $_xh[$parser]['ha'][1]); + return $r; + } + } + + class xmlrpcval + { + var $me=array(); + var $mytype=0; + + function xmlrpcval($val=-1, $type='') + { + global $xmlrpcTypes; + $this->me=array(); + $this->mytype=0; + if ($val!=-1 || $type!='') + { + if ($type=='') + { + $type='string'; + } + if ($xmlrpcTypes[$type]==1) + { + $this->addScalar($val,$type); + } + elseif ($xmlrpcTypes[$type]==2) + { + $this->addArray($val); + } + elseif ($xmlrpcTypes[$type]==3) + { + $this->addStruct($val); + } + } + } + + function addScalar($val, $type='string') + { + global $xmlrpcTypes, $xmlrpcBoolean; + + if ($this->mytype==1) + { + echo 'xmlrpcval: scalar can have only one value
'; + return 0; + } + $typeof=$xmlrpcTypes[$type]; + if ($typeof!=1) + { + echo 'xmlrpcval: not a scalar type (${typeof})
'; + return 0; + } + + if ($type==$xmlrpcBoolean) + { + if (strcasecmp($val,'true')==0 || $val==1 || ($val==true && strcasecmp($val,'false'))) + { + $val=1; + } + else + { + $val=0; + } + } + + if ($this->mytype==2) + { + // we're adding to an array here + $ar=$this->me['array']; + $ar[]=new xmlrpcval($val, $type); + $this->me['array']=$ar; + } + else + { + // a scalar, so set the value and remember we're scalar + $this->me[$type]=$val; + $this->mytype=$typeof; + } + return 1; + } + + function addArray($vals) + { + global $xmlrpcTypes; + if ($this->mytype!=0) + { + echo 'xmlrpcval: already initialized as a [' . $this->kindOf() . ']
'; + return 0; + } + + $this->mytype=$xmlrpcTypes['array']; + $this->me['array']=$vals; + return 1; + } + + function addStruct($vals) + { + global $xmlrpcTypes; + if ($this->mytype!=0) + { + echo 'xmlrpcval: already initialized as a [' . $this->kindOf() . ']
'; + return 0; + } + $this->mytype=$xmlrpcTypes['struct']; + $this->me['struct']=$vals; + return 1; + } + + function dump($ar) + { + reset($ar); + while ( list( $key, $val ) = each( $ar ) ) + { + echo "$key => $val
"; + if ($key == 'array') + { + while ( list( $key2, $val2 ) = each( $val ) ) + { + echo "-- $key2 => $val2
"; + } + } + } + } + + function kindOf() + { + switch($this->mytype) + { + case 3: + return 'struct'; + break; + case 2: + return 'array'; + break; + case 1: + return 'scalar'; + break; + default: + return 'undef'; + } + } + + function serializedata($typ, $val) + { + $rs=''; + global $xmlrpcTypes, $xmlrpcBase64, $xmlrpcString, + $xmlrpcBoolean; + switch($xmlrpcTypes[$typ]) + { + case 3: + // struct + $rs.="\n"; + reset($val); + while(list($key2, $val2)=each($val)) + { + $rs.="${key2}\n"; + $rs.=$this->serializeval($val2); + $rs.="\n"; + } + $rs.=''; + break; + case 2: + // array + $rs.="\n\n"; + for($i=0; $iserializeval($val[$i]); + } + $rs.="\n"; + break; + case 1: + switch ($typ) + { + case $xmlrpcBase64: + $rs.="<${typ}>" . base64_encode($val) . ""; + break; + case $xmlrpcBoolean: + $rs.="<${typ}>" . ($val ? "1" : "0") . ""; + break; + case $xmlrpcString: + $rs.="<${typ}>" . rawurlencode($val). ""; // micsik + //$rs.="<${typ}>" . htmlspecialchars($val). ""; + break; + default: + $rs.="<${typ}>${val}"; + } + break; + default: + break; + } + return $rs; + } + + function serialize() + { + return $this->serializeval($this); + } + + function serializeval($o) + { + global $xmlrpcTypes; + $rs=''; + $ar=$o->me; + reset($ar); + list($typ, $val) = each($ar); + $rs.=''; + $rs.=$this->serializedata($typ, $val); + $rs.="\n"; + return $rs; + } + + function structmem($m) + { + $nv=$this->me['struct'][$m]; + return $nv; + } + + function structreset() + { + reset($this->me['struct']); + } + + function structeach() + { + return each($this->me['struct']); + } + + function getval() + { + // UNSTABLE + global $xmlrpcBoolean, $xmlrpcBase64; + reset($this->me); + list($a,$b)=each($this->me); + // contributed by I Sofer, 2001-03-24 + // add support for nested arrays to scalarval + // i've created a new method here, so as to + // preserve back compatibility + + if (is_array($b)) + { + @reset($b); + while(list($id,$cont) = @each($b)) + { + $b[$id] = $cont->scalarval(); + } + } + + // add support for structures directly encoding php objects + if (is_object($b)) + { + $t = get_object_vars($b); + @reset($t); + while(list($id,$cont) = @each($t)) + { + $t[$id] = $cont->scalarval(); + } + @reset($t); + while(list($id,$cont) = @each($t)) + { + eval('$b->'.$id.' = $cont;'); + } + } + // end contrib + return $b; + } + + function scalarval() + { + global $xmlrpcBoolean, $xmlrpcBase64; + reset($this->me); + list($a,$b)=each($this->me); + return rawurldecode($b); // micsik + } + + function scalartyp() + { + global $xmlrpcI4, $xmlrpcInt; + reset($this->me); + list($a,$b)=each($this->me); + if ($a==$xmlrpcI4) + { + $a=$xmlrpcInt; + } + return $a; + } + + function arraymem($m) + { + $nv=$this->me['array'][$m]; + return $nv; + } + + function arraysize() + { + reset($this->me); + list($a,$b)=each($this->me); + return sizeof($b); + } + } + + // date helpers + function iso8601_encode($timet, $utc=0) + { + // return an ISO8601 encoded string + // really, timezones ought to be supported + // but the XML-RPC spec says: + // + // "Don't assume a timezone. It should be specified by the server in its + // documentation what assumptions it makes about timezones." + // + // these routines always assume localtime unless + // $utc is set to 1, in which case UTC is assumed + // and an adjustment for locale is made when encoding + if (!$utc) + { + $t=strftime("%Y%m%dT%H:%M:%S", $timet); + } + else + { + if (function_exists('gmstrftime')) + { + // gmstrftime doesn't exist in some versions + // of PHP + $t=gmstrftime("%Y%m%dT%H:%M:%S", $timet); + } + else + { + $t=strftime("%Y%m%dT%H:%M:%S", $timet-date('Z')); + } + } + return $t; + } + + function iso8601_decode($idate, $utc=0) + { + // return a timet in the localtime, or UTC + $t=0; + if (ereg("([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})", $idate, $regs)) + { + if ($utc) + { + $t=gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); + } + else + { + $t=mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); + } + } + return $t; + } + + /**************************************************************** + * xmlrpc_decode takes a message in PHP xmlrpc object format and * + * tranlates it into native PHP types. * + * * + * author: Dan Libby (dan@libby.com) * + ****************************************************************/ + function xmlrpc_decoder($xmlrpc_val) + { + $kind = $xmlrpc_val->kindOf(); + + if($kind == 'scalar') + { + return $xmlrpc_val->scalarval(); + } + elseif($kind == 'array') + { + $size = $xmlrpc_val->arraysize(); + $arr = array(); + + for($i = 0; $i < $size; $i++) + { + $arr[]=xmlrpc_decoder($xmlrpc_val->arraymem($i)); + } + return $arr; + } + elseif($kind == 'struct') + { + $xmlrpc_val->structreset(); + $arr = array(); + + while(list($key,$value)=$xmlrpc_val->structeach()) + { + $arr[$key] = xmlrpc_decoder($value); + } + return $arr; + } + } + + /**************************************************************** + * xmlrpc_encode takes native php types and encodes them into * + * xmlrpc PHP object format. * + * BUG: All sequential arrays are turned into structs. I don't * + * know of a good way to determine if an array is sequential * + * only. * + * * + * feature creep -- could support more types via optional type * + * argument. * + * * + * author: Dan Libby (dan@libby.com) * + ****************************************************************/ + function xmlrpc_encoder($php_val) + { + global $xmlrpcInt; + global $xmlrpcDouble; + global $xmlrpcString; + global $xmlrpcArray; + global $xmlrpcStruct; + global $xmlrpcBoolean; + + $type = gettype($php_val); + $xmlrpc_val = new xmlrpcval; + + switch($type) + { + case 'array': + case 'object': + $arr = array(); + while (list($k,$v) = each($php_val)) + { + $arr[$k] = xmlrpc_encoder($v); + } + $xmlrpc_val->addStruct($arr); + break; + case 'integer': + $xmlrpc_val->addScalar($php_val, $xmlrpcInt); + break; + case 'double': + $xmlrpc_val->addScalar($php_val, $xmlrpcDouble); + break; + case 'string': + $xmlrpc_val->addScalar($php_val, $xmlrpcString); + break; + // + // Add support for encoding/decoding of booleans, since they are supported in PHP + case 'boolean': + $xmlrpc_val->addScalar($php_val, $xmlrpcBoolean); + break; + // + case 'unknown type': + default: + // giancarlo pinerolo + // it has to return + // an empty object in case (which is already + // at this point), not a boolean. + break; + } + return $xmlrpc_val; + } +?> diff --git a/livesupport/modules/alib/var/xmlrpc/xmlrpcs.inc b/livesupport/modules/alib/var/xmlrpc/xmlrpcs.inc new file mode 100644 index 000000000..0a2833c83 --- /dev/null +++ b/livesupport/modules/alib/var/xmlrpc/xmlrpcs.inc @@ -0,0 +1,450 @@ + +// $Id: xmlrpcs.inc,v 1.1 2004/07/23 00:22:13 tomas Exp $ + +// Copyright (c) 1999,2000,2002 Edd Dumbill. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// * Neither the name of the "XML-RPC for PHP" nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. + + // XML RPC Server class + // requires: xmlrpc.inc + + // listMethods: either a string, or nothing + $_xmlrpcs_listMethods_sig=array(array($xmlrpcArray, $xmlrpcString), array($xmlrpcArray)); + $_xmlrpcs_listMethods_doc='This method lists all the methods that the XML-RPC server knows how to dispatch'; + function _xmlrpcs_listMethods($server, $m) + { + global $xmlrpcerr, $xmlrpcstr, $_xmlrpcs_dmap; + $v=new xmlrpcval(); + $dmap=$server->dmap; + $outAr=array(); + for(reset($dmap); list($key, $val)=each($dmap); ) + { + $outAr[]=new xmlrpcval($key, 'string'); + } + $dmap=$_xmlrpcs_dmap; + for(reset($dmap); list($key, $val)=each($dmap); ) + { + $outAr[]=new xmlrpcval($key, 'string'); + } + $v->addArray($outAr); + return new xmlrpcresp($v); + } + + $_xmlrpcs_methodSignature_sig=array(array($xmlrpcArray, $xmlrpcString)); + $_xmlrpcs_methodSignature_doc='Returns an array of known signatures (an array of arrays) for the method name passed. If no signatures are known, returns a none-array (test for type != array to detect missing signature)'; + function _xmlrpcs_methodSignature($server, $m) + { + global $xmlrpcerr, $xmlrpcstr, $_xmlrpcs_dmap; + + $methName=$m->getParam(0); + $methName=$methName->scalarval(); + if (ereg("^system\.", $methName)) + { + $dmap=$_xmlrpcs_dmap; $sysCall=1; + } + else + { + $dmap=$server->dmap; $sysCall=0; + } + // print "\n"; + if (isset($dmap[$methName])) + { + if ($dmap[$methName]['signature']) + { + $sigs=array(); + $thesigs=$dmap[$methName]['signature']; + for($i=0; $igetParam(0); + $methName=$methName->scalarval(); + if (ereg("^system\.", $methName)) + { + $dmap=$_xmlrpcs_dmap; $sysCall=1; + } + else + { + $dmap=$server->dmap; $sysCall=0; + } + // print "\n"; + if (isset($dmap[$methName])) + { + if ($dmap[$methName]['docstring']) + { + $r=new xmlrpcresp(new xmlrpcval($dmap[$methName]["docstring"]), 'string'); + } + else + { + $r=new xmlrpcresp(new xmlrpcval('', 'string')); + } + } + else + { + $r=new xmlrpcresp(0, $xmlrpcerr['introspect_unknown'], $xmlrpcstr['introspect_unknown']); + } + return $r; + } + + $_xmlrpcs_multicall_sig = array(array($xmlrpcArray, $xmlrpcArray)); + $_xmlrpcs_multicall_doc = 'Boxcar multiple RPC calls in one request. See http://www.xmlrpc.com/discuss/msgReader$1208 for details'; + + function _xmlrpcs_multicall_error($err) + { + if (is_string($err)) + { + global $xmlrpcerr, $xmlrpcstr; + $str = $xmlrpcstr["multicall_${err}"]; + $code = $xmlrpcerr["multicall_${err}"]; + } + else + { + $code = $err->faultCode(); + $str = $err->faultString(); + } + $struct['faultCode'] = new xmlrpcval($code, 'int'); + $struct['faultString'] = new xmlrpcval($str, 'string'); + return new xmlrpcval($struct, 'struct'); + } + + function _xmlrpcs_multicall_do_call($server, $call) + { + if ($call->kindOf() != 'struct') + return _xmlrpcs_multicall_error('notstruct'); + $methName = $call->structmem('methodName'); + if (!$methName) + return _xmlrpcs_multicall_error('nomethod'); + if ($methName->kindOf() != 'scalar' || $methName->scalartyp() != 'string') + return _xmlrpcs_multicall_error('notstring'); + if ($methName->scalarval() == 'system.multicall') + return _xmlrpcs_multicall_error('recursion'); + + $params = $call->structmem('params'); + if (!$params) + return _xmlrpcs_multicall_error('noparams'); + if ($params->kindOf() != 'array') + return _xmlrpcs_multicall_error('notarray'); + $numParams = $params->arraysize(); + + $msg = new xmlrpcmsg($methName->scalarval()); + for ($i = 0; $i < $numParams; $i++) + $msg->addParam($params->arraymem($i)); + + $result = $server->execute($msg); + + if ($result->faultCode() != 0) + return _xmlrpcs_multicall_error($result); // Method returned fault. + + return new xmlrpcval(array($result->value()), "array"); + } + + function _xmlrpcs_multicall($server, $m) + { + $calls = $m->getParam(0); + $numCalls = $calls->arraysize(); + $result = array(); + + for ($i = 0; $i < $numCalls; $i++) + { + $call = $calls->arraymem($i); + $result[$i] = _xmlrpcs_multicall_do_call($server, $call); + } + + return new xmlrpcresp(new xmlrpcval($result, 'array')); + } + + $_xmlrpcs_dmap=array( + 'system.listMethods' => array( + 'function' => '_xmlrpcs_listMethods', + 'signature' => $_xmlrpcs_listMethods_sig, + 'docstring' => $_xmlrpcs_listMethods_doc), + 'system.methodHelp' => array( + 'function' => '_xmlrpcs_methodHelp', + 'signature' => $_xmlrpcs_methodHelp_sig, + 'docstring' => $_xmlrpcs_methodHelp_doc), + 'system.methodSignature' => array( + 'function' => '_xmlrpcs_methodSignature', + 'signature' => $_xmlrpcs_methodSignature_sig, + 'docstring' => $_xmlrpcs_methodSignature_doc), + 'system.multicall' => array( + 'function' => '_xmlrpcs_multicall', + 'signature' => $_xmlrpcs_multicall_sig, + 'docstring' => $_xmlrpcs_multicall_doc + ) + ); + + $_xmlrpc_debuginfo=''; + function xmlrpc_debugmsg($m) + { + global $_xmlrpc_debuginfo; + $_xmlrpc_debuginfo=$_xmlrpc_debuginfo . $m . "\n"; + } + + class xmlrpc_server + { + var $dmap=array(); + + function xmlrpc_server($dispMap='', $serviceNow=1) + { + global $HTTP_RAW_POST_DATA; + // dispMap is a dispatch array of methods + // mapped to function names and signatures + // if a method + // doesn't appear in the map then an unknown + // method error is generated + /* milosch - changed to make passing dispMap optional. + * instead, you can use the class add_to_map() function + * to add functions manually (borrowed from SOAPX4) + */ + if($dispMap) + { + $this->dmap = $dispMap; + if($serviceNow) + { + $this->service(); + } + } + } + + function serializeDebug() + { + global $_xmlrpc_debuginfo; + if ($_xmlrpc_debuginfo!='') + { + return "\n"; + } + else + { + return ''; + } + } + + function service() + { + global $xmlrpc_defencoding; + + $r=$this->parseRequest(); + $payload='' . "\n" + . $this->serializeDebug() + . $r->serialize(); + Header("Content-type: text/xml\r\nContent-length: " . + strlen($payload)); + print $payload; + } + + /* + add a method to the dispatch map + */ + function add_to_map($methodname,$function,$sig,$doc) + { + $this->dmap[$methodname] = array( + 'function' => $function, + 'signature' => $sig, + 'docstring' => $doc + ); + } + + function verifySignature($in, $sig) + { + for($i=0; $igetNumParams()+1) + { + $itsOK=1; + for($n=0; $n<$in->getNumParams(); $n++) + { + $p=$in->getParam($n); + // print "\n"; + if ($p->kindOf() == 'scalar') + { + $pt=$p->scalartyp(); + } + else + { + $pt=$p->kindOf(); + } + // $n+1 as first type of sig is return type + if ($pt != $cursig[$n+1]) + { + $itsOK=0; + $pno=$n+1; $wanted=$cursig[$n+1]; $got=$pt; + break; + } + } + if ($itsOK) + { + return array(1); + } + } + } + return array(0, "Wanted ${wanted}, got ${got} at param ${pno})"); + } + + function parseRequest($data='') + { + global $_xh,$HTTP_RAW_POST_DATA; + global $xmlrpcerr, $xmlrpcstr, $xmlrpcerrxml, $xmlrpc_defencoding, + $_xmlrpcs_dmap; + + if ($data=="") + { + $data=$HTTP_RAW_POST_DATA; + } + $parser = xml_parser_create($xmlrpc_defencoding); + + $_xh[$parser]=array(); + $_xh[$parser]['st']=''; + $_xh[$parser]['cm']=0; + $_xh[$parser]['isf']=0; + $_xh[$parser]['params']=array(); + $_xh[$parser]['method']=''; + + // decompose incoming XML into request structure + + xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); + xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee'); + xml_set_character_data_handler($parser, 'xmlrpc_cd'); + xml_set_default_handler($parser, 'xmlrpc_dh'); + if (!xml_parse($parser, $data, 1)) + { + // return XML error as a faultCode + $r=new xmlrpcresp(0, + $xmlrpcerrxml+xml_get_error_code($parser), + sprintf("XML error: %s at line %d", + xml_error_string(xml_get_error_code($parser)), + xml_get_current_line_number($parser))); + xml_parser_free($parser); + } + else + { + xml_parser_free($parser); + $m=new xmlrpcmsg($_xh[$parser]['method']); + // now add parameters in + $plist=""; + for($i=0; $i\n"; + $plist.="$i - " . $_xh[$parser]['params'][$i]. " \n"; + eval('$m->addParam(' . $_xh[$parser]['params'][$i]. ");"); + } + // uncomment this to really see what the server's getting! + // xmlrpc_debugmsg($plist); + + $r = $this->execute($m); + } + return $r; + } + + function execute ($m) + { + global $xmlrpcerr, $xmlrpcstr, $_xmlrpcs_dmap; + // now to deal with the method + $methName = $m->method(); + $sysCall = ereg("^system\.", $methName); + $dmap = $sysCall ? $_xmlrpcs_dmap : $this->dmap; + + if (!isset($dmap[$methName]['function'])) + { + // No such method + return new xmlrpcresp(0, + $xmlrpcerr['unknown_method'], + $xmlrpcstr['unknown_method']); + } + + // Check signature. + if (isset($dmap[$methName]['signature'])) + { + $sig = $dmap[$methName]['signature']; + list ($ok, $errstr) = $this->verifySignature($m, $sig); + if (!$ok) + { + // Didn't match. + return new xmlrpcresp(0, + $xmlrpcerr['incorrect_params'], + $xmlrpcstr['incorrect_params'] . ": ${errstr}"); + } + } + + $func = $dmap[$methName]['function']; + + if ($sysCall) + { + return call_user_func($func, $this, $m); + } + else + { + return call_user_func($func, $m); + } + } + + function echoInput() + { + global $HTTP_RAW_POST_DATA; + + // a debugging routine: just echos back the input + // packet as a string value + + $r=new xmlrpcresp; + $r->xv=new xmlrpcval( "'Aha said I: '" . $HTTP_RAW_POST_DATA, 'string'); + print $r->serialize(); + } + } +?> diff --git a/livesupport/modules/alib/var/xmlrpc/xr_cli_pok.py b/livesupport/modules/alib/var/xmlrpc/xr_cli_pok.py new file mode 100755 index 000000000..88ac61343 --- /dev/null +++ b/livesupport/modules/alib/var/xmlrpc/xr_cli_pok.py @@ -0,0 +1,55 @@ +#!/usr/bin/python + +# $Id: xr_cli_pok.py,v 1.1 2004/07/23 00:22:13 tomas Exp $ + +from xmlrpclib import * +import sys + +if len(sys.argv)<3: + print """ + Usage: xr_cli_pok.py http:////xmlrpc/alib_xr.php + commands and args: + test [] + login + logout +""" + sys.exit(1) +elif sys.argv[2]=="test": + if len(sys.argv)>3: + tstr=sys.argv[3] + if len(sys.argv)>4: + sessid=sys.argv[4] + else: + sessid='' + path=sys.argv[1] + server = Server(path) + try: + r = server.alib.xrTest(tstr, sessid) + print r + except Error, v: + print "XML-RPC Error:",v +elif sys.argv[2]=="login": + login=sys.argv[3] + passwd=sys.argv[4] + path=sys.argv[1] + server = Server(path) + try: + r = server.alib.login(login, passwd) + print r + except Error, v: + print "XML-RPC Error:",v +elif sys.argv[2]=="logout": + sessid=sys.argv[3] + path=sys.argv[1] + server = Server(path) + try: + r = server.alib.logout(sessid) + print r + except Error, v: + print "XML-RPC Error:",v +else: + print "Unknown command: "+sys.argv[2] + sys.exit(1) + + + diff --git a/livesupport/modules/alib/var/xmlrpc/xr_cli_test.php b/livesupport/modules/alib/var/xmlrpc/xr_cli_test.php new file mode 100644 index 000000000..eb12b4633 --- /dev/null +++ b/livesupport/modules/alib/var/xmlrpc/xr_cli_test.php @@ -0,0 +1,84 @@ +setDebug(1); + $r=$c->send($f); + if (!($r->faultCode()>0)) { + $v=$r->value(); + $log = $v->serialize(); + if($ak=='test') + { $log = split('_',$log); $log="{$log[0]}\nusername: {$log[1]}\ntoken: {$log[2]}"; } + if($ak=='login') $sessid = $v->scalarval(); + if($ak=='logout') $sessid = ''; + } else { + $log = "Fault:\n Code: ".$r->faultCode()."\nReason:'".$r->faultString()."'
\n"; + } + break; +} + +?> + +Alib XMLRPC test client + +

Alib XMLRPC test client

+XMLRPC server:
+ +Output:':'')?> +
+ +
+

test

+flip teststring to uppercase and print username and session token
+
+test string:
+token:
+ + +
+
+

login

+
+username:
+password:
+ + +
+
+

logout

+
+token:
+ + +
+
+Back +