1<?php
2/**
3 * EGroupware Api: Support for Cyrus IMAP
4 *
5 * @link http://www.stylite.de
6 * @package api
7 * @subpackage mail
8 * @author Ralf Becker <rb@stylite.de>
9 * @author Klaus Leithoff <kl@stylite.de>
10 * @author Lars Kneschke
11 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
12 * @version $Id$
13 */
14
15namespace EGroupware\Api\Mail\Imap;
16
17use EGroupware\Api\Mail;
18
19use Horde_Imap_Client_Exception;
20
21/**
22 * Manages connection to Cyrus IMAP server
23 */
24class Cyrus extends Mail\Imap
25{
26	/**
27	 * Label shown in EMailAdmin
28	 */
29	const DESCRIPTION = 'Cyrus';
30
31	/**
32	 * Capabilities of this class (pipe-separated): default, sieve, admin, logintypeemail
33	 */
34	const CAPABILITIES = 'default|sieve|timedsieve|admin|logintypeemail';
35
36	/**
37	 * prefix for groupnames, when using groups in ACL Management
38	 */
39	const ACL_GROUP_PREFIX = 'group:';
40
41	// mailbox delimiter
42	var $mailboxDelimiter = '.';
43
44	// mailbox prefix
45	var $mailboxPrefix = '';
46
47	/**
48	 * Updates an account
49	 *
50	 * @param array $_hookValues only value for key 'account_lid' and 'account_passwd' is used
51	 */
52	function addAccount($_hookValues)
53	{
54		return $this->updateAccount($_hookValues);
55	}
56
57	/**
58	 * Delete an account
59	 *
60	 * @param array $_hookValues only value for key 'account_lid' is used
61	 */
62	function deleteAccount($_hookValues)
63	{
64		// some precausion to really delete just _one_ account
65		if (strpos($_hookValues['account_lid'],'%') !== false ||
66			strpos($_hookValues['account_lid'],'*') !== false)
67		{
68			return false;
69		}
70		return !!$this->deleteUsers($_hookValues['account_lid']);
71	}
72
73	/**
74	 * Delete multiple (user-)mailboxes via a wildcard, eg. '%' for whole domain
75	 *
76	 * Domain is the configured domain and it uses the Cyrus admin user
77	 *
78	 * @return string $username='%' username containing wildcards, default '%' for all users of a domain
79	 * @return int|boolean number of deleted mailboxes on success or false on error
80	 */
81	function deleteUsers($username='%')
82	{
83		if(!$this->acc_imap_administration || empty($username))
84		{
85			return false;
86		}
87
88		// we need a admin connection
89		$this->adminConnection();
90
91		$mailboxName = $this->getUserMailboxString($username);
92
93		try {
94			$mboxes = (array)$this->getMailboxes($mailboxName, 1);
95			//error_log(__METHOD__."('$username') getMailboxes('$reference','$username$restriction') = ".array2string($mboxes));
96
97			foreach(array_keys($mboxes) as $mbox)
98			{
99				// give the admin account the rights to delete this mailbox
100				$this->setACL($mbox, $this->acc_imap_admin_username, array('rights' => 'aeiklprstwx'));
101				$this->deleteMailbox($mbox);
102			}
103		}
104		catch(Horde_Imap_Client_Exception $e) {
105			_egw_log_exception($e);
106			$this->disconnect();
107			return false;
108		}
109		$this->disconnect();
110
111		return count($mboxes);
112	}
113
114	/**
115	 * returns information about a user
116	 * currently only supported information is the current quota
117	 *
118	 * @param string $_username
119	 * @return array userdata
120	 */
121	function getUserData($_username)
122	{
123		// no need to switch to admin-connection for reading quota of current user
124		if ($_username !== $GLOBALS['egw_info']['user']['account_lid']) $this->adminConnection();
125		$userData = array();
126
127		if(($quota = $this->getQuotaByUser($_username,'ALL')))
128		{
129			$userData['quotaLimit'] = (int)($quota['limit'] / 1024);
130			$userData['quotaUsed'] = (int)($quota['usage'] / 1024);
131		}
132		//error_log(__LINE__.': '.__METHOD__."('$_username') quota=".array2string($quota).' returning '.array2string($userData));
133
134		if ($_username !== $GLOBALS['egw_info']['user']['account_lid']) $this->disconnect();
135
136		return $userData;
137	}
138
139	/**
140	 * Set information about a user
141	 * currently only supported information is the current quota
142	 *
143	 * @param string $_username
144	 * @param int $_quota
145	 */
146	function setUserData($_username, $_quota)
147	{
148		if(!$this->acc_imap_administration)
149		{
150			return false;
151		}
152
153		// create a admin connection
154		$this->adminConnection();
155
156		$mailboxName = $this->getUserMailboxString($_username);
157
158		$this->setQuota($mailboxName, array('STORAGE' => (int)$_quota > 0 ? (int)$_quota*1024 : -1));
159
160		$this->disconnect();
161
162		return true;
163	}
164
165	/**
166	 * Updates an account
167	 *
168	 * @param array $_hookValues only value for key 'account_lid' and 'account_passwd' is used
169	 */
170	function updateAccount($_hookValues)
171	{
172		if(!$this->acc_imap_administration)
173		{
174			return false;
175		}
176
177		// we need a admin connection
178		$this->adminConnection();
179
180		// create the mailbox, with the account_lid, as it is passed from the hook values (gets transformed there if needed)
181		$mailboxName = $this->getUserMailboxString($_hookValues['account_lid'], $mailboxName);
182		// make sure we use the correct username here.
183		$username = $this->getMailBoxUserName($_hookValues['account_lid']);
184		$folderInfo = $this->getMailboxes('', $mailboxName, true);
185		if(empty($folderInfo))
186		{
187			try {
188				$this->createMailbox($mailboxName);
189				$this->setACL($mailboxName, $username, array('rights' => 'aeiklprstwx'));
190				// create defined folders and subscribe them (have to use user-credentials to subscribe!)
191				$userimap = null;
192				foreach($this->params as $name => $value)
193				{
194					if (substr($name, 0, 11) == 'acc_folder_' && !empty($value))
195					{
196						if (!isset($userimap))
197						{
198							$params = $this->params;
199							$params['acc_imap_username'] = $username;
200							$params['acc_imap_password'] = $_hookValues['account_passwd'];
201							$userimap = new Cyrus($params);
202						}
203						$userimap->createMailbox($value);
204						$userimap->subscribeMailbox($value);
205					}
206				}
207				if (isset($userimap)) $userimap->logout();
208			}
209			catch(Horde_Imap_Client_Exception $e) {
210				_egw_log_exception($e);
211			}
212		}
213		$this->disconnect();
214	}
215
216	/**
217	 * Proxy former bosieve methods to internal Mail\Sieve instance
218	 *
219	 * @param string $name
220	 * @param array $params
221	 * @throws Exception
222	 */
223	public function __call($name,array $params=null)
224	{
225		switch($name)
226		{
227			case 'setRules':	// call setRules with 3. param of true, to enable utf7imap fileinto for Cyrus
228				$params += array(null, null, true);
229				break;
230		}
231		return parent::__call($name, $params);
232	}
233}
234