PageRenderTime 47ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/mnemo/lib/Driver.php

https://github.com/wrobel/horde-fw3
PHP | 368 lines | 175 code | 40 blank | 153 comment | 32 complexity | 7aa9bd198de109419518ae36bf72c3c9 MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, LGPL-2.1, BSD-2-Clause
  1. <?php
  2. /**
  3. * Mnemo_Driver:: defines an API for implementing storage backends for Mnemo.
  4. *
  5. * $Horde: mnemo/lib/Driver.php,v 1.25.2.14 2009-01-06 15:24:58 jan Exp $
  6. *
  7. * Copyright 2001-2009 The Horde Project (http://www.horde.org/)
  8. *
  9. * See the enclosed file LICENSE for license information (ASL). If you
  10. * did not receive this file, see http://www.horde.org/licenses/asl.php.
  11. *
  12. * @author Jon Parise <jon@horde.org>
  13. * @since Mnemo 1.0
  14. * @package Mnemo
  15. */
  16. class Mnemo_Driver {
  17. /**
  18. * Array holding the current memo list. Each array entry is a hash
  19. * describing a memo. The array is indexed numerically by memo ID.
  20. *
  21. * @var array
  22. */
  23. var $_memos = array();
  24. /**
  25. * String containing the current notepad name.
  26. *
  27. * @var string
  28. */
  29. var $_notepad = '';
  30. /**
  31. * Crypting processor.
  32. *
  33. * @var Horde_Crypt_pgp
  34. */
  35. var $_pgp;
  36. /**
  37. * An error message to throw when something is wrong.
  38. *
  39. * @var string
  40. */
  41. var $_errormsg;
  42. /**
  43. * Constructor - All real work is done by initialize().
  44. */
  45. function Mnemo_Driver($errormsg = null)
  46. {
  47. if (is_null($errormsg)) {
  48. $this->_errormsg = _("The Notes backend is not currently available.");
  49. } else {
  50. $this->_errormsg = $errormsg;
  51. }
  52. }
  53. /**
  54. * Lists memos based on the given criteria. All memos will be
  55. * returned by default.
  56. *
  57. * @return array Returns a list of the requested memos.
  58. */
  59. function listMemos()
  60. {
  61. return $this->_memos;
  62. }
  63. /**
  64. * Generate a universal / unique identifier for a task. This is
  65. * NOT something that we expect to be able to parse into a
  66. * tasklist and a taskId.
  67. *
  68. * @return string A nice unique string (should be 255 chars or less).
  69. */
  70. function generateUID()
  71. {
  72. return date('YmdHis') . '.'
  73. . substr(str_pad(base_convert(microtime(), 10, 36), 16, uniqid(mt_rand()), STR_PAD_LEFT), -16)
  74. . '@' . $GLOBALS['conf']['server']['name'];
  75. }
  76. /**
  77. * Update the description (short summary) of a memo.
  78. *
  79. * @param integer $memo_id The memo to update.
  80. */
  81. function getMemoDescription($body)
  82. {
  83. if (!strstr($body, "\n") && String::length($body) <= 64) {
  84. return trim($body);
  85. }
  86. $lines = explode("\n", $body);
  87. if (!is_array($lines)) {
  88. return trim(String::substr($body, 0, 64));
  89. }
  90. // Move to a line with more than spaces.
  91. $i = 0;
  92. while (isset($lines[$i]) && !preg_match('|[^\s]|', $lines[$i])) {
  93. $i++;
  94. }
  95. if (String::length($lines[$i]) <= 64) {
  96. return trim($lines[$i]);
  97. } else {
  98. return trim(String::substr($lines[$i], 0, 64));
  99. }
  100. }
  101. /**
  102. * Loads the PGP encryption driver.
  103. */
  104. function loadPGP()
  105. {
  106. if (empty($GLOBALS['conf']['utils']['gnupg'])) {
  107. $this->_pgp = PEAR::raiseError(_("Encryption support has not been configured, please contact your administrator."));
  108. return;
  109. }
  110. require_once 'Horde/Crypt.php';
  111. $this->_pgp = Horde_Crypt::factory('pgp',
  112. array('program' => $GLOBALS['conf']['utils']['gnupg'],
  113. 'temp' => Horde::getTempDir()));
  114. }
  115. /**
  116. * Encrypts a note.
  117. *
  118. * @param string $note The note text.
  119. * @param string $passphrase The passphrase to encrypt the note with.
  120. *
  121. * @return string|PEAR_Error The encrypted text or PEAR_Error on failure.
  122. */
  123. function encrypt($note, $passphrase)
  124. {
  125. $this->loadPGP();
  126. if (is_a($this->_pgp, 'PEAR_Error')) {
  127. return $this->_pgp;
  128. }
  129. return $this->_pgp->encrypt($note, array('type' => 'message', 'symmetric' => true, 'passphrase' => $passphrase));
  130. }
  131. /**
  132. * Decrypts a note.
  133. *
  134. * @param string $note The encrypted note text.
  135. * @param string $passphrase The passphrase to decrypt the note with.
  136. *
  137. * @return string|PEAR_Error The decrypted text or PEAR_Error on failure.
  138. */
  139. function decrypt($note, $passphrase)
  140. {
  141. $this->loadPGP();
  142. if (is_a($this->_pgp, 'PEAR_Error')) {
  143. return $this->_pgp;
  144. }
  145. return $this->_pgp->decrypt($note, array('type' => 'message', 'passphrase' => $passphrase));
  146. }
  147. /**
  148. * Returns an error message if we are not using a secure connection.
  149. *
  150. * @return PEAR_Error Returns a PEAR_Error object if there is no secure
  151. * connection.
  152. */
  153. function requireSecureConnection()
  154. {
  155. $this->loadPGP();
  156. if (is_a($this->_pgp, 'PEAR_Error')) {
  157. return $this->_pgp;
  158. }
  159. return $this->_pgp->requireSecureConnection();
  160. }
  161. /**
  162. * Returns whether note encryption is supported.
  163. *
  164. * Checks if PGP support could be loaded, if it supports symmetric
  165. * encryption, and if we have a secure connection.
  166. *
  167. * @return boolean Whether encryption is suppoted.
  168. */
  169. function encryptionSupported()
  170. {
  171. $this->loadPGP();
  172. return !is_a($this->_pgp, 'PEAR_Error') &&
  173. is_callable(array($this->_pgp, 'encryptedSymmetrically')) &&
  174. !is_a($this->requireSecureConnection(), 'PEAR_Error');
  175. }
  176. /**
  177. * Attempts to return a concrete Mnemo_Driver instance based on $driver.
  178. *
  179. * @param string $notepad The name of the current notepad.
  180. *
  181. * @param string $driver The type of concrete Mnemo_Driver subclass
  182. * to return. The is based on the storage
  183. * driver ($driver). The code is dynamically
  184. * included.
  185. *
  186. * @param array $params (optional) A hash containing any additional
  187. * configuration or connection parameters a
  188. * subclass might need.
  189. *
  190. * @return mixed The newly created concrete Mnemo_Driver instance, or
  191. * dummy instance containing an error message.
  192. */
  193. function &factory($notepad = '', $driver = null, $params = null)
  194. {
  195. if (is_null($driver)) {
  196. $driver = $GLOBALS['conf']['storage']['driver'];
  197. }
  198. $driver = basename($driver);
  199. if (is_null($params)) {
  200. $params = Horde::getDriverConfig('storage', $driver);
  201. }
  202. require_once dirname(__FILE__) . '/Driver/' . $driver . '.php';
  203. $class = 'Mnemo_Driver_' . $driver;
  204. if (class_exists($class)) {
  205. $mnemo = &new $class($notepad, $params);
  206. $result = $mnemo->initialize();
  207. if (is_a($result, 'PEAR_Error')) {
  208. $mnemo = &new Mnemo_Driver(sprintf(_("The Notes backend is not currently available: %s"), $result->getMessage()));
  209. }
  210. } else {
  211. $mnemo = &new Mnemo_Driver(sprintf(_("Unable to load the definition of %s."), $class));
  212. }
  213. return $mnemo;
  214. }
  215. /**
  216. * Attempts to return a reference to a concrete Mnemo_Driver instance based
  217. * on $driver.
  218. *
  219. * It will only create a new instance if no Mnemo_Driver instance with the
  220. * same parameters currently exists.
  221. *
  222. * This should be used if multiple storage sources are required.
  223. *
  224. * This method must be invoked as: $var = &Mnemo_Driver::singleton()
  225. *
  226. * @param string $notepad The name of the current notepad.
  227. *
  228. * @param string $driver The type of concrete Mnemo_Driver subclass
  229. * to return. The is based on the storage
  230. * driver ($driver). The code is dynamically
  231. * included.
  232. *
  233. * @param array $params (optional) A hash containing any additional
  234. * configuration or connection parameters a
  235. * subclass might need.
  236. *
  237. * @return mixed The created concrete Mnemo_Driver instance, or false
  238. * on error.
  239. */
  240. function &singleton($notepad = '', $driver = null, $params = null)
  241. {
  242. static $instances = array();
  243. if (is_null($driver)) {
  244. $driver = $GLOBALS['conf']['storage']['driver'];
  245. }
  246. if (is_null($params)) {
  247. $params = Horde::getDriverConfig('storage', $driver);
  248. }
  249. $signature = serialize(array($notepad, $driver, $params));
  250. if (!isset($instances[$signature])) {
  251. $instances[$signature] = &Mnemo_Driver::factory($notepad, $driver, $params);
  252. }
  253. return $instances[$signature];
  254. }
  255. /**
  256. * Export this memo in iCalendar format.
  257. *
  258. * @param array memo the memo (hash array) to export
  259. * @param object vcal a Horde_iCalendar object that acts as container.
  260. *
  261. * @return object Horde_iCalendar_vnote object for this event.
  262. */
  263. function toiCalendar($memo, &$calendar)
  264. {
  265. global $prefs;
  266. $vnote = &Horde_iCalendar::newComponent('vnote', $calendar);
  267. $vnote->setAttribute('UID', $memo['uid']);
  268. $vnote->setAttribute('BODY', $memo['body']);
  269. $vnote->setAttribute('SUMMARY', $this->getMemoDescription($memo['body']));
  270. if (!empty($memo['category'])) {
  271. $vnote->setAttribute('CATEGORIES', $memo['category']);
  272. }
  273. /* Get the note's history. */
  274. $history = &Horde_History::singleton();
  275. $log = $history->getHistory('mnemo:' . $memo['memolist_id'] . ':' . $memo['uid']);
  276. if ($log && !is_a($log, 'PEAR_Error')) {
  277. foreach ($log->getData() as $entry) {
  278. switch ($entry['action']) {
  279. case 'add':
  280. $created = $entry['ts'];
  281. break;
  282. case 'modify':
  283. $modified = $entry['ts'];
  284. break;
  285. }
  286. }
  287. }
  288. if (!empty($created)) {
  289. $vnote->setAttribute('DCREATED', $created);
  290. }
  291. if (!empty($modified)) {
  292. $vnote->setAttribute('LAST-MODIFIED', $modified);
  293. }
  294. return $vnote;
  295. }
  296. /**
  297. * Create a memo (hash array) from a Horde_iCalendar_vnote object.
  298. *
  299. * @param Horde_iCalendar_vnote $vnote The iCalendar data to update from.
  300. *
  301. * @return array Memo (hash array) created from the vNote.
  302. */
  303. function fromiCalendar($vNote)
  304. {
  305. $memo = array();
  306. $body = $vNote->getAttribute('BODY');
  307. if (!is_array($body) && !is_a($body, 'PEAR_Error')) {
  308. $memo['body'] = $body;
  309. } else {
  310. $memo['body'] = '';
  311. }
  312. $memo['desc'] = $this->getMemoDescription($memo['body']);
  313. $cat = $vNote->getAttribute('CATEGORIES');
  314. if (!is_array($cat) && !is_a($cat, 'PEAR_Error')) {
  315. $memo['category'] = $cat;
  316. }
  317. return $memo;
  318. }
  319. /**
  320. * Retrieves notes from the database.
  321. *
  322. * @return mixed True on success, PEAR_Error on failure.
  323. */
  324. function retrieve()
  325. {
  326. return PEAR::raiseError($this->_errormsg);
  327. }
  328. }