addressbook.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. <?php
  2. /**
  3. ** addressbook.php
  4. **
  5. ** Functions and classes for the addressbook system.
  6. **
  7. **/
  8. $addressbook_php = true;
  9. // Include backends here.
  10. include("../functions/abook_local_file.php");
  11. include("../functions/abook_ldap_server.php");
  12. // Create and initialize an addressbook object.
  13. // Returns the created object
  14. function addressbook_init($showerr = true, $onlylocal = false) {
  15. global $data_dir, $username, $ldap_server;
  16. // Create a new addressbook object
  17. $abook = new AddressBook;
  18. // Always add a local backend
  19. $filename = sprintf("%s%s.abook", $data_dir, $username);
  20. $r = $abook->add_backend("local_file", Array("filename" => $filename,
  21. "create" => true));
  22. if(!$r && $showerr) {
  23. printf(_("Error opening file %s"), $filename);
  24. exit;
  25. }
  26. if($onlylocal)
  27. return $abook;
  28. // Load configured LDAP servers (if PHP has LDAP support)
  29. if(is_array($ldap_server) && function_exists("ldap_connect")) {
  30. reset($ldap_server);
  31. while(list($undef,$param) = each($ldap_server)) {
  32. if(is_array($param)) {
  33. $r = $abook->add_backend("ldap_server", $param);
  34. if(!$r && $showerr) {
  35. printf("&nbsp;"._("Error initializing LDAP server %s:").
  36. "<BR>\n", $param["host"]);
  37. printf("&nbsp;".$abook->error);
  38. exit;
  39. }
  40. }
  41. }
  42. }
  43. // Return the initialized object
  44. return $abook;
  45. }
  46. /**
  47. ** This is the main address book class that connect all the
  48. ** backends and provide services to the functions above.
  49. **
  50. **/
  51. class AddressBook {
  52. var $backends = array();
  53. var $numbackends = 0;
  54. var $error = "";
  55. var $localbackend = 0;
  56. var $localbackendname = "";
  57. // Constructor function.
  58. function AddressBook() {
  59. $localbackendname = _("Personal address book");
  60. }
  61. // Return an array of backends of a given type,
  62. // or all backends if no type is specified.
  63. function get_backend_list($type = "") {
  64. $ret = array();
  65. for($i = 1 ; $i <= $this->numbackends ; $i++) {
  66. if(empty($type) || $type == $this->backends[$i]->btype) {
  67. array_push($ret, &$this->backends[$i]);
  68. }
  69. }
  70. return $ret;
  71. }
  72. // ========================== Public ========================
  73. // Add a new backend. $backend is the name of a backend
  74. // (without the abook_ prefix), and $param is an optional
  75. // mixed variable that is passed to the backend constructor.
  76. // See each of the backend classes for valid parameters.
  77. function add_backend($backend, $param = "") {
  78. $backend_name = "abook_".$backend;
  79. eval("\$newback = new $backend_name(\$param);");
  80. if(!empty($newback->error)) {
  81. $this->error = $newback->error;
  82. return false;
  83. }
  84. $this->numbackends++;
  85. $newback->bnum = $this->numbackends;
  86. $this->backends[$this->numbackends] = $newback;
  87. // Store ID of first local backend added
  88. if($this->localbackend == 0 && $newback->btype == "local") {
  89. $this->localbackend = $this->numbackends;
  90. $this->localbackendname = $newback->sname;
  91. }
  92. return $this->numbackends;
  93. }
  94. // Return a list of addresses matching expression in
  95. // all backends of a given type.
  96. function search($expression, $bnum = -1) {
  97. $ret = array();
  98. $this->error = "";
  99. // Search all backends
  100. if($bnum == -1) {
  101. $sel = $this->get_backend_list("");
  102. $failed = 0;
  103. for($i = 0 ; $i < sizeof($sel) ; $i++) {
  104. $backend = &$sel[$i];
  105. $backend->error = "";
  106. $res = $backend->search($expression);
  107. if(is_array($res)) {
  108. $ret = array_merge($ret, $res);
  109. } else {
  110. $this->error = $this->error . "<br>\n". $backend->error;
  111. $failed++;
  112. }
  113. }
  114. // Only fail if all backends failed
  115. if($failed >= sizeof($sel))
  116. return false;
  117. }
  118. // Search only one backend
  119. else {
  120. $ret = $this->backends[$bnum]->search($expression);
  121. if(!is_array($ret)) {
  122. $this->error = $this->error . "<br>\n". $this->backends[$bnum]->error;
  123. return false;
  124. }
  125. }
  126. return $ret;
  127. }
  128. // Return a sorted search
  129. function s_search($expression, $bnum = -1) {
  130. $ret = $this->search($expression, $bnum);
  131. if(!is_array($ret))
  132. return $ret;
  133. // Inline function - Not nice, but still..
  134. function cmp($a,$b) {
  135. if($a["backend"] > $b["backend"])
  136. return 1;
  137. else if($a["backend"] < $b["backend"])
  138. return -1;
  139. return (strtolower($a["name"]) > strtolower($b["name"])) ? 1 : -1;
  140. }
  141. usort($ret, 'cmp');
  142. return $ret;
  143. }
  144. // Lookup an address by alias. Only possible in
  145. // local backends.
  146. function lookup($alias, $bnum = -1) {
  147. $ret = array();
  148. if($bnum > -1) {
  149. $res = $this->backends[$bnum]->lookup($alias);
  150. if(is_array($res)) {
  151. return $res;
  152. } else {
  153. $this->error = $backend->error;
  154. return false;
  155. }
  156. }
  157. $sel = $this->get_backend_list("local");
  158. for($i = 0 ; $i < sizeof($sel) ; $i++) {
  159. $backend = &$sel[$i];
  160. $backend->error = "";
  161. $res = $backend->lookup($alias);
  162. if(is_array($res)) {
  163. if(!empty($res))
  164. return $res;
  165. } else {
  166. $this->error = $backend->error;
  167. return false;
  168. }
  169. }
  170. return $ret;
  171. }
  172. // Return all addresses
  173. function list_addr($bnum = -1) {
  174. $ret = array();
  175. if($bnum == -1)
  176. $sel = $this->get_backend_list("local");
  177. else
  178. $sel = array(0 => &$this->backends[$bnum]);
  179. for($i = 0 ; $i < sizeof($sel) ; $i++) {
  180. $backend = &$sel[$i];
  181. $backend->error = "";
  182. $res = $backend->list_addr();
  183. if(is_array($res)) {
  184. $ret = array_merge($ret, $res);
  185. } else {
  186. $this->error = $backend->error;
  187. return false;
  188. }
  189. }
  190. return $ret;
  191. }
  192. // Create a new address from $userdata, in backend $bnum.
  193. // Return the backend number that the/ address was added
  194. // to, or false if it failed.
  195. function add($userdata, $bnum) {
  196. // Validate data
  197. if(!is_array($userdata)) {
  198. $this->error = _("Invalid input data");
  199. return false;
  200. }
  201. if(empty($userdata["firstname"]) &&
  202. empty($userdata["lastname"])) {
  203. $this->error = _("Name is missing");
  204. return false;
  205. }
  206. if(empty($userdata["email"])) {
  207. $this->error = _("E-mail address is missing");
  208. return false;
  209. }
  210. if(empty($userdata["nickname"])) {
  211. $userdata["nickname"] = $userdata["email"];
  212. }
  213. if(eregi("[\: \|\#\"\!]", $userdata["nickname"])) {
  214. $this->error = _("Nickname contain illegal characters");
  215. return false;
  216. }
  217. // Check that specified backend accept new entries
  218. if(!$this->backends[$bnum]->writeable) {
  219. $this->error = _("Addressbook is read-only");
  220. return false;
  221. }
  222. // Add address to backend
  223. $res = $this->backends[$bnum]->add($userdata);
  224. if($res) {
  225. return $bnum;
  226. } else {
  227. $this->error = $this->backends[$bnum]->error;
  228. return false;
  229. }
  230. return false; // Not reached
  231. } // end of add()
  232. // Remove the user identified by $alias from backend $bnum
  233. // If $alias is an array, all users in the array are removed.
  234. function remove($alias, $bnum) {
  235. // Check input
  236. if(empty($alias))
  237. return true;
  238. // Convert string to single element array
  239. if(!is_array($alias))
  240. $alias = array(0 => $alias);
  241. // Check that specified backend is writable
  242. if(!$this->backends[$bnum]->writeable) {
  243. $this->error = _("Addressbook is read-only");
  244. return false;
  245. }
  246. // Remove user from backend
  247. $res = $this->backends[$bnum]->remove($alias);
  248. if($res) {
  249. return $bnum;
  250. } else {
  251. $this->error = $this->backends[$bnum]->error;
  252. return false;
  253. }
  254. return false; // Not reached
  255. } // end of remove()
  256. // Remove the user identified by $alias from backend $bnum
  257. // If $alias is an array, all users in the array are removed.
  258. function modify($alias, $userdata, $bnum) {
  259. // Check input
  260. if(empty($alias) || !is_string($alias))
  261. return true;
  262. // Validate data
  263. if(!is_array($userdata)) {
  264. $this->error = _("Invalid input data");
  265. return false;
  266. }
  267. if(empty($userdata["firstname"]) &&
  268. empty($userdata["lastname"])) {
  269. $this->error = _("Name is missing");
  270. return false;
  271. }
  272. if(empty($userdata["email"])) {
  273. $this->error = _("E-mail address is missing");
  274. return false;
  275. }
  276. if(empty($userdata["nickname"])) {
  277. $userdata["nickname"] = $userdata["email"];
  278. }
  279. // Check that specified backend is writable
  280. if(!$this->backends[$bnum]->writeable) {
  281. $this->error = sprintf(_("Addressbook %s is read-only", $bnum));
  282. return false;
  283. }
  284. // Modify user in backend
  285. $res = $this->backends[$bnum]->modify($alias, $userdata);
  286. if($res) {
  287. return $bnum;
  288. } else {
  289. $this->error = $this->backends[$bnum]->error;
  290. return false;
  291. }
  292. return false; // Not reached
  293. } // end of modify()
  294. } // End of class Addressbook
  295. /**
  296. ** Generic backend that all other backends extend
  297. **/
  298. class addressbook_backend {
  299. // Variables that all backends must provide.
  300. var $btype = "dummy";
  301. var $bname = "dummy";
  302. var $sname = "Dummy backend";
  303. // Variables common for all backends, but that
  304. // should not be changed by the backends.
  305. var $bnum = -1;
  306. var $error = "";
  307. var $writeable = false;
  308. function set_error($string) {
  309. $this->error = "[" . $this->sname . "] " . $string;
  310. return false;
  311. }
  312. // ========================== Public ========================
  313. function search($expression) {
  314. $this->set_error("search not implemented");
  315. return false;
  316. }
  317. function lookup($alias) {
  318. $this->set_error("lookup not implemented");
  319. return false;
  320. }
  321. function list_addr() {
  322. $this->set_error("list_addr not implemented");
  323. return false;
  324. }
  325. function add($userdata) {
  326. $this->set_error("add not implemented");
  327. return false;
  328. }
  329. function remove($alias) {
  330. $this->set_error("delete not implemented");
  331. return false;
  332. }
  333. function modify($alias, $newuserdata) {
  334. $this->set_error("modify not implemented");
  335. return false;
  336. }
  337. }
  338. ?>