PageRenderTime 21ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Fetchmail.php

https://github.com/Excito/imp
PHP | 457 lines | 190 code | 39 blank | 228 comment | 24 complexity | 3827900b4b34bd2f26fb3483e8733c8b MD5 | raw file
  1. <?php
  2. /**
  3. * The IMP_Fetchmail:: class provides an interface to download mail from
  4. * remote mail servers.
  5. *
  6. * $Horde: imp/lib/Fetchmail.php,v 1.41.8.15 2009/01/06 15:24:03 jan Exp $
  7. *
  8. * Copyright 2002-2009 The Horde Project (http://www.horde.org/)
  9. *
  10. * See the enclosed file COPYING for license information (GPL). If you
  11. * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
  12. *
  13. * @author Nuno Loureiro <nuno@co.sapo.pt>
  14. * @author Michael Slusarz <slusarz@horde.org>
  15. * @package IMP
  16. */
  17. class IMP_Fetchmail {
  18. /**
  19. * Parameters used by the driver.
  20. *
  21. * @var array
  22. */
  23. var $_params;
  24. /**
  25. * The list of active fetchmail parameters for the current driver.
  26. * ALL DRIVERS SHOULD UNSET ANY FETCHMAIL PARAMETERS THEY DO NOT USE
  27. * OR ELSE THEY WILL APPEAR IN THE PREFERENCES PAGE.
  28. * The following parameters are available:
  29. * 'id' -- The account name.
  30. * 'driver' -- The driver to use.
  31. * 'protocol' -- The protocol type.
  32. * 'username' -- The username on the remote server.
  33. * 'password' -- The password on the remote server.
  34. * 'server' -- The remote server name/address.
  35. * 'rmailbox' -- The remote mailbox name.
  36. * 'lmailbox' -- The local mailbox to download messages to.
  37. * 'onlynew' -- Only retrieve new messages?
  38. * 'markseen' -- Mark messages as seen?
  39. * 'del' -- Delete messages after fetching?
  40. * 'loginfetch' -- Fetch mail from other accounts on login?
  41. * 'acctcolor' -- Should these messages be colored differently
  42. * in mailbox view?
  43. *
  44. * @var array
  45. */
  46. var $_activeparams = array(
  47. 'id', 'driver', 'type', 'protocol', 'username', 'password', 'server',
  48. 'rmailbox', 'lmailbox', 'onlynew', 'markseen', 'del', 'loginfetch',
  49. 'acctcolor'
  50. );
  51. /**
  52. * Attempts to return a concrete IMP_Fetchmail instance based on $driver.
  53. *
  54. * @param string $driver The type of concrete IMP_Fetchmail subclass to
  55. * return, based on the driver indicated. The code
  56. * is dynamically included.
  57. *
  58. * @param array $params The configuration parameter array.
  59. *
  60. * @return mixed The newly created concrete IMP_Fetchmail instance, or
  61. * false on error.
  62. */
  63. function &factory($driver, $params = array())
  64. {
  65. $driver = basename($driver);
  66. require_once dirname(__FILE__) . '/Fetchmail/' . $driver . '.php';
  67. $class = 'IMP_Fetchmail_' . $driver;
  68. if (class_exists($class)) {
  69. $fetchmail = new $class($params);
  70. } else {
  71. $fetchmail = false;
  72. }
  73. return $fetchmail;
  74. }
  75. /**
  76. * Returns a list of available drivers, with a description of each.
  77. * This function can be called statically:
  78. * $list = IMP_Fetchmail::listDrivers();
  79. *
  80. * @return array The list of available drivers, with the driver name as
  81. * the key and the description as the value.
  82. */
  83. function listDrivers()
  84. {
  85. $drivers = array();
  86. if (($dir = opendir(dirname(__FILE__) . '/Fetchmail'))) {
  87. while (false !== ($file = readdir($dir))) {
  88. if (!is_dir($file)) {
  89. $driver = basename($file, '.php');
  90. $class = 'IMP_Fetchmail_' . $driver;
  91. require_once dirname(__FILE__) . '/Fetchmail/' . $file;
  92. if (is_callable(array($class, 'description')) &&
  93. ($descrip = call_user_func(array($class, 'description')))) {
  94. $drivers[$driver] = $descrip;
  95. }
  96. }
  97. }
  98. closedir($dir);
  99. }
  100. return $drivers;
  101. }
  102. /**
  103. * List the colors available for coloring fetched messages.
  104. * This function can be called statically:
  105. * $list = IMP_Fetchmail::listColors();
  106. *
  107. * @return array The list of available colors;
  108. */
  109. function listColors()
  110. {
  111. return array(
  112. 'purple', 'lime', 'teal', 'blue', 'olive', 'fuchsia', 'navy',
  113. 'aqua'
  114. );
  115. }
  116. /**
  117. * Returns a description of the driver.
  118. * This function can be called statically:
  119. * $description = IMP_Fetchmail::description();
  120. *
  121. * @abstract
  122. *
  123. * @return string The description of the driver.
  124. */
  125. function description()
  126. {
  127. return '';
  128. }
  129. /**
  130. * Constructor.
  131. *
  132. * @param array $params The configuration parameter array.
  133. */
  134. function IMP_Fetchmail($params)
  135. {
  136. /* Check for missing params. */
  137. $paramlist = $this->getParameterList();
  138. if (array_diff($paramlist, array_keys($params))) {
  139. // TODO: Error message here
  140. }
  141. $this->_params = $params;
  142. }
  143. /**
  144. * Return the list of parameters valid for this driver.
  145. *
  146. * @return array The list of active parameters.
  147. */
  148. function getParameterList()
  149. {
  150. return $this->_activeparams;
  151. }
  152. /**
  153. * Return a list of protocols supported by this driver.
  154. *
  155. * @abstract
  156. *
  157. * @return array The list of protocols.
  158. * KEY: protocol ID
  159. * VAL: protocol description
  160. */
  161. function getProtocolList()
  162. {
  163. return array();
  164. }
  165. /**
  166. * Gets the mail using the data in this object.
  167. *
  168. * @abstract
  169. *
  170. * @return mixed Returns the number of messages retrieved on success.
  171. * Returns PEAR_Error on error.
  172. */
  173. function getMail()
  174. {
  175. return PEAR::raiseError('not implemented');
  176. }
  177. /**
  178. * Processes a single mail message by calling any user defined functions,
  179. * stripping bare newlines, and adding color information to the headers.
  180. *
  181. * @access private
  182. *
  183. * @param string $header The message header text.
  184. * @param string $body The message body text.
  185. *
  186. * @return string The complete message.
  187. */
  188. function _processMailMessage($header, $body)
  189. {
  190. $msg = rtrim($header);
  191. if (empty($this->_params['acctcolor'])) {
  192. $msg .= "\nX-color: " . $this->_params['acctcolor'];
  193. }
  194. $msg .= "\n\n" . $body;
  195. /* If there is a user defined function, call it with the current
  196. * message as an argument. */
  197. if ($GLOBALS['conf']['hooks']['fetchmail_filter']) {
  198. $msg = Horde::callHook('_imp_hook_fetchmail_filter', array($msg), 'imp');
  199. }
  200. return IMP::removeBareNewlines($msg);
  201. }
  202. /**
  203. * Checks the message size to see if it exceeds the maximum value
  204. * allowable in the configuration file.
  205. *
  206. * @access private
  207. *
  208. * @param integer $size The size of the message.
  209. * @param string $subject The subject of the message.
  210. * @param string $from The message sender.
  211. *
  212. * @return boolean False if message is too large, true if OK.
  213. */
  214. function _checkMessageSize($size, $subject, $from)
  215. {
  216. if (!empty($GLOBALS['conf']['fetchmail']['size_limit']) &&
  217. ($size > $GLOBALS['conf']['fetchmail']['size_limit'])) {
  218. require_once 'Horde/MIME.php';
  219. $GLOBALS['notification']->push(sprintf(_("The message \"%s\" from \"%s\" (%d bytes) exceeds fetch size limit."), MIME::Decode($subject), MIME::Decode($from), $size), 'horde.warning');
  220. return false;
  221. } else {
  222. return true;
  223. }
  224. }
  225. /**
  226. * Add the message to the requested local mailbox.
  227. *
  228. * @access private
  229. *
  230. * @param string $msg The message text.
  231. *
  232. * @return boolean True on success, false on failure.
  233. */
  234. function _addMessage($msg)
  235. {
  236. $imp_imap = &IMP_IMAP::singleton();
  237. return @imap_append($imp_imap->stream(), IMP::serverString($this->_params['lmailbox']), $msg);
  238. }
  239. /**
  240. * Perform fetchmail on the list of accounts given. Outputs informaton
  241. * to the global notification driver.
  242. * This function can be called statically.
  243. *
  244. * @param array $accounts The list of account identifiers to fetch mail
  245. * for.
  246. */
  247. function fetchMail($accounts)
  248. {
  249. $fm_account = new IMP_Fetchmail_Account();
  250. foreach ($accounts as $val) {
  251. $params = $fm_account->getAllValues($val);
  252. $driver = &IMP_Fetchmail::factory($params['driver'], $params);
  253. if ($driver === false) {
  254. continue;
  255. }
  256. $res = $driver->getMail();
  257. if (is_a($res, 'PEAR_Error')) {
  258. $GLOBALS['notification']->push(_("Fetchmail: ") . $res->getMessage(), 'horde.warning');
  259. } elseif ($res == 1) {
  260. $GLOBALS['notification']->push(_("Fetchmail: ") . sprintf(_("Fetched 1 message from %s"), $fm_account->getValue('id', $val)), 'horde.success');
  261. } elseif ($res >= 0) {
  262. $GLOBALS['notification']->push(_("Fetchmail: ") . sprintf(_("Fetched %d messages from %s"), $res, $fm_account->getValue('id', $val)), 'horde.success');
  263. } else {
  264. $GLOBALS['notification']->push(_("Fetchmail: no new messages."), 'horde.success');
  265. }
  266. }
  267. }
  268. }
  269. /**
  270. * The IMP_Fetchmail_Account:: class provides an interface to accessing
  271. * fetchmail preferences for all mail accounts a user might have.
  272. *
  273. * @author Nuno Loureiro <nuno@co.sapo.pt>
  274. * @package IMP
  275. */
  276. class IMP_Fetchmail_Account {
  277. /**
  278. * Array containing all the user's accounts.
  279. *
  280. * @var array
  281. */
  282. var $_accounts = array();
  283. /**
  284. * Constructor.
  285. */
  286. function IMP_Fetchmail_Account()
  287. {
  288. /* Read all the user's accounts from the prefs object or build
  289. * a new account from the standard values given in prefs.php. */
  290. $accounts = @unserialize($GLOBALS['prefs']->getValue('fm_accounts'));
  291. if (is_array($accounts)) {
  292. $this->_accounts = $accounts;
  293. }
  294. }
  295. /**
  296. * Return the number of accounts.
  297. *
  298. * @return integer Number of active accounts.
  299. */
  300. function count()
  301. {
  302. return count($this->_accounts);
  303. }
  304. /**
  305. * Saves all accounts in the prefs backend.
  306. *
  307. * @access private
  308. */
  309. function _save()
  310. {
  311. $GLOBALS['prefs']->setValue('fm_accounts', serialize($this->_accounts));
  312. }
  313. /**
  314. * Adds a new empty account to the array of accounts.
  315. *
  316. * @return integer The pointer to the created account.
  317. */
  318. function add()
  319. {
  320. $this->_accounts[] = array();
  321. $this->_save();
  322. return count($this->_accounts) - 1;
  323. }
  324. /**
  325. * Remove an account from the array of accounts
  326. *
  327. * @param integer $account The pointer to the account to be removed.
  328. *
  329. * @return array The removed account.
  330. */
  331. function delete($account)
  332. {
  333. $deleted = $this->_accounts[$account];
  334. unset($this->_accounts[$account]);
  335. $this->_accounts = array_values($this->_accounts);
  336. $this->_save();
  337. return $deleted;
  338. }
  339. /**
  340. * Returns a property from one of the accounts.
  341. *
  342. * @param string $key The property to retrieve.
  343. * @param integer $account The account to retrieve the property from.
  344. *
  345. * @return mixed The value of the property or false if the property
  346. * doesn't exist.
  347. */
  348. function getValue($key, $account)
  349. {
  350. return (isset($this->_accounts[$account][$key])) ? $this->_accounts[$account][$key] : false;
  351. }
  352. /**
  353. * Returns all properties from the requested accounts.
  354. *
  355. * @param integer $account The account to retrieve the properties from.
  356. *
  357. * @return array The entire properties array, or false on error.
  358. */
  359. function getAllValues($account)
  360. {
  361. return (isset($this->_accounts[$account])) ? $this->_accounts[$account] : false;
  362. }
  363. /**
  364. * Returns an array with the specified property from all existing accounts.
  365. *
  366. * @param string $key The property to retrieve.
  367. *
  368. * @return array The array with the values from all accounts.
  369. */
  370. function getAll($key)
  371. {
  372. $list = array();
  373. foreach (array_keys($this->_accounts) as $account) {
  374. $list[$account] = $this->getValue($key, $account);
  375. }
  376. return $list;
  377. }
  378. /**
  379. * Sets a property with a specified value.
  380. *
  381. * @param string $key The property to set.
  382. * @param mixed $val The value the property should be set to.
  383. * @param integer $account The account to set the property in.
  384. */
  385. function setValue($key, $val, $account)
  386. {
  387. /* These parameters are checkbox items - make sure they are stored
  388. * as boolean values. */
  389. $list = array('del', 'onlynew', 'markseen', 'loginfetch');
  390. if (in_array($key, $list) && !is_bool($val)) {
  391. if (($val == 'yes') || (intval($val) != 0)) {
  392. $val = true;
  393. } else {
  394. $val = false;
  395. }
  396. }
  397. $this->_accounts[$account][$key] = $val;
  398. $this->_save();
  399. }
  400. /**
  401. * Returns true if the pair key/value is already in the accounts array.
  402. *
  403. * @param string $key The account key to search.
  404. * @param string $val The value to search for in $key.
  405. *
  406. * @return boolean True if the value was found in $key.
  407. */
  408. function hasValue($key, $val)
  409. {
  410. $list = $this->getAll($key);
  411. foreach ($list as $val2) {
  412. if (strpos(String::lower($val), String::lower($val2)) !== false) {
  413. return true;
  414. }
  415. }
  416. return false;
  417. }
  418. }