1: <?php
2: /**
3: * This code is licensed under AGPLv3 license or Afterlogic Software License
4: * if commercial version of the product was purchased.
5: * For full statements of the licenses see LICENSE-AFTERLOGIC and LICENSE-AGPL3 files.
6: */
7:
8: namespace Aurora\Modules\Mail;
9:
10: use Aurora\Api;
11: use Aurora\Modules\Core\Models\Tenant;
12: use Aurora\Modules\Core\Models\User;
13: use Aurora\Modules\Mail\Classes\Message;
14: use Aurora\Modules\Mail\Enums\SearchInFoldersType;
15: use Aurora\Modules\Mail\Models\Identity;
16: use Aurora\Modules\Mail\Models\TrustedSender;
17: use Aurora\System\Exceptions\InvalidArgumentException;
18: use PHPMailer\DKIMValidator\Validator as DKIMValidator;
19: use PHPMailer\DKIMValidator\DKIMException;
20:
21: /**
22: * @license https://www.gnu.org/licenses/agpl-3.0.html AGPL-3.0
23: * @license https://afterlogic.com/products/common-licensing Afterlogic Software License
24: * @copyright Copyright (c) 2023, Afterlogic Corp.
25: *
26: * @package Modules
27: */
28: class Module extends \Aurora\System\Module\AbstractModule
29: {
30: /*
31: * @var $oMailManager Managers\Main
32: */
33: protected $oMailManager = null;
34:
35: /*
36: * @var $oAccountsManager Managers\Accounts
37: */
38: protected $oAccountsManager = null;
39:
40: /*
41: * @var $oServersManager Managers\Servers
42: */
43: protected $oServersManager = null;
44:
45: /*
46: * @var $oIdentitiesManager Managers\Identities
47: */
48: protected $oIdentitiesManager = null;
49:
50: /*
51: * @var $oSieveManager Managers\Sieve
52: */
53: protected $oSieveManager = null;
54:
55: /*
56: * @var $oFilecacheManager \Aurora\System\Managers\Filecache
57: */
58: protected $oFilecacheManager = null;
59:
60: /**
61: *
62: * @return Module
63: */
64: public static function getInstance()
65: {
66: return \Aurora\System\Api::GetModule(self::GetName());
67: }
68:
69: /**
70: * Initializes Mail Module.
71: *
72: * @ignore
73: */
74: public function init()
75: {
76: $this->aErrors = [
77: Enums\ErrorCodes::CannotConnectToMailServer => $this->i18N('ERROR_CONNECT_TO_MAIL_SERVER'),
78: Enums\ErrorCodes::CannotLoginCredentialsIncorrect => $this->i18N('ERROR_CREDENTIALS_INCORRECT'),
79: Enums\ErrorCodes::FolderAlreadyExists => $this->i18N('ERROR_FOLDER_EXISTS'),
80: Enums\ErrorCodes::FolderNameContainsDelimiter => $this->i18N('ERROR_FOLDER_NAME_CONTAINS_DELIMITER'),
81: Enums\ErrorCodes::CannotRenameNonExistenFolder => $this->i18N('ERROR_RENAME_NONEXISTEN_FOLDER'),
82: Enums\ErrorCodes::CannotGetMessage => $this->i18N('ERROR_GET_MESSAGE'),
83: Enums\ErrorCodes::CannotMoveMessage => $this->i18N('ERROR_MOVE_MESSAGE'),
84: Enums\ErrorCodes::CannotSendMessageInvalidRecipients => $this->i18N('ERROR_SEND_MESSAGE_INVALID_RECIPIENTS'),
85: Enums\ErrorCodes::CannotSendMessageToRecipients => $this->i18N('ERROR_SEND_MESSAGE_TO_RECIPIENTS'),
86: Enums\ErrorCodes::CannotSendMessageToExternalRecipients => $this->i18N('ERROR_SEND_MESSAGE_TO_EXTERNAL_RECIPIENTS'),
87: Enums\ErrorCodes::CannotSaveMessageToSentItems => $this->i18N('ERROR_SEND_MESSAGE_NOT_SAVED'),
88: Enums\ErrorCodes::CannotUploadMessage => $this->i18N('ERROR_UPLOAD_MESSAGE'),
89: Enums\ErrorCodes::CannotUploadMessageFileNotEml => $this->i18N('ERROR_UPLOAD_MESSAGE_FILE_NOT_EML'),
90: Enums\ErrorCodes::DomainIsNotAllowedForLoggingIn => $this->i18N('DOMAIN_IS_NOT_ALLOWED_FOR_LOGGING_IN'),
91: Enums\ErrorCodes::TenantQuotaExceeded => $this->i18N('ERROR_TENANT_QUOTA_EXCEEDED'),
92: ];
93:
94: $this->AddEntries(
95: array(
96: 'message-newtab' => 'EntryMessageNewtab',
97: 'mail-attachment' => 'EntryDownloadAttachment',
98: 'mail-attachments-cookieless' => 'EntryDownloadAttachmentCookieless'
99: )
100: );
101:
102: $this->subscribeEvent('Login', array($this, 'onLogin'));
103: $this->subscribeEvent('Core::DeleteUser::before', array($this, 'onBeforeDeleteUser'));
104: $this->subscribeEvent('Core::GetAccounts', array($this, 'onGetAccounts'));
105: $this->subscribeEvent('Autodiscover::GetAutodiscover::after', array($this, 'onAfterGetAutodiscover'));
106: $this->subscribeEvent('Core::DeleteTenant::after', array($this, 'onAfterDeleteTenant'));
107: $this->subscribeEvent('Core::DeleteUser::after', array($this, 'onAfterDeleteUser'));
108: $this->subscribeEvent('Core::GetDigestHash', array($this, 'onGetDigestHash'));
109: $this->subscribeEvent('Core::GetAccountUsedToAuthorize', array($this, 'onGetAccountUsedToAuthorize'));
110: $this->subscribeEvent('System::RunEntry::before', array($this, 'onBeforeRunEntry'));
111: $this->subscribeEvent('System::CastExtendedProp', array($this, 'onCastExtendedProp'));
112:
113: \MailSo\Config::$PreferStartTlsIfAutoDetect = !!$this->getConfig('PreferStarttls', true);
114: }
115:
116: /**
117: * @return Module
118: */
119: public static function Decorator()
120: {
121: return parent::Decorator();
122: }
123:
124: /**
125: *
126: * @return \Aurora\Modules\Mail\Managers\Accounts\Manager
127: */
128: public function getAccountsManager()
129: {
130: if ($this->oAccountsManager === null) {
131: $this->oAccountsManager = new Managers\Accounts\Manager($this);
132: }
133:
134: return $this->oAccountsManager;
135: }
136:
137: public function setAccountsManager($oManager)
138: {
139: $this->oAccountsManager = $oManager;
140: }
141:
142: /**
143: *
144: * @return \Aurora\Modules\Mail\Managers\Servers\Manager
145: */
146: public function getServersManager()
147: {
148: if ($this->oServersManager === null) {
149: $this->oServersManager = new Managers\Servers\Manager($this);
150: }
151:
152: return $this->oServersManager;
153: }
154:
155: /**
156: *
157: * @return \Aurora\Modules\Mail\Managers\Identities\Manager
158: */
159: public function getIdentitiesManager()
160: {
161: if ($this->oIdentitiesManager === null) {
162: $this->oIdentitiesManager = new Managers\Identities\Manager($this);
163: }
164:
165: return $this->oIdentitiesManager;
166: }
167:
168: /**
169: *
170: * @return \Aurora\Modules\Mail\Managers\Main\Manager
171: */
172: public function getMailManager()
173: {
174: if ($this->oMailManager === null) {
175: $this->oMailManager = new Managers\Main\Manager($this);
176: }
177:
178: return $this->oMailManager;
179: }
180:
181: /**
182: *
183: * @return \Aurora\Modules\Mail\Managers\Sieve\Manager
184: */
185: public function getSieveManager()
186: {
187: if ($this->oSieveManager === null) {
188: $this->oSieveManager = new Managers\Sieve\Manager($this);
189: }
190:
191: return $this->oSieveManager;
192: }
193:
194: /**
195: *
196: * @return \Aurora\System\Managers\Filecache
197: */
198: public function getFilecacheManager()
199: {
200: if ($this->oFilecacheManager === null) {
201: $this->oFilecacheManager = new \Aurora\System\Managers\Filecache();
202: }
203:
204: return $this->oFilecacheManager;
205: }
206:
207: /**
208: * Checks if actions are allowed for authenticated user.
209: * @param \Aurora\Modules\Mail\Models\MailAccount $oAccount Account should be checked if it belongs to authenticated user. If it's null check is not needed.
210: * @param int $iUserId User identifier should be checked if it's identifier of authenticated user. If it's null check is not needed.
211: * @throws \Aurora\System\Exceptions\ApiException
212: */
213: public static function checkAccess($oAccount = null, $iUserId = null)
214: {
215: if (\Aurora\System\Api::accessCheckIsSkipped()) {
216: // if access check should be skipped don't check at all
217: return;
218: }
219:
220: $bAccessDenied = true;
221: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
222: $iUserRole = $oAuthenticatedUser instanceof \Aurora\Modules\Core\Models\User ? $oAuthenticatedUser->Role : \Aurora\System\Enums\UserRole::Anonymous;
223: switch ($iUserRole) {
224: case (\Aurora\System\Enums\UserRole::SuperAdmin):
225: // everything is allowed for SuperAdmin
226: $bAccessDenied = false;
227: break;
228: case (\Aurora\System\Enums\UserRole::TenantAdmin):
229: // everything is allowed for TenantAdmin
230: $oUser = null;
231: if ($oAccount !== null) {
232: $oUser = \Aurora\Modules\Core\Module::getInstance()->GetUser($oAccount->IdUser);
233: }
234: if ($iUserId !== null) {
235: $oUser = \Aurora\Modules\Core\Module::getInstance()->GetUser($iUserId);
236: }
237: if ($oUser instanceof \Aurora\Modules\Core\Models\User) {
238: if ($oAuthenticatedUser->IdTenant === $oUser->IdTenant) {
239: $bAccessDenied = false;
240: }
241: }
242: break;
243: case (\Aurora\System\Enums\UserRole::NormalUser):
244: // User identifier shoud be checked
245: if ($iUserId !== null) {
246: if ($iUserId === $oAuthenticatedUser->Id) {
247: $bAccessDenied = false;
248: }
249: }
250:
251: // Account shoud be checked
252: if ($oAccount !== null) {
253: if ($oAccount instanceof Models\MailAccount && $oAccount->IdUser === $oAuthenticatedUser->Id) {
254: $bAccessDenied = false;
255: }
256: }
257: break;
258: case (\Aurora\System\Enums\UserRole::Customer):
259: case (\Aurora\System\Enums\UserRole::Anonymous):
260: // everything is forbidden for Customer and Anonymous users
261: break;
262: }
263: if ($bAccessDenied) {
264: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::AccessDenied);
265: }
266: }
267:
268: /***** public functions might be called with web API *****/
269: /**
270: * @apiDefine Mail Mail Module
271: * Main Mail module. It provides PHP and Web APIs for managing mail accounts, folders and messages.
272: */
273:
274: /**
275: * @api {post} ?/Api/ GetSettings
276: * @apiName GetSettings
277: * @apiGroup Mail
278: * @apiDescription Obtains list of module settings for authenticated user.
279: *
280: * @apiHeader {string} [Authorization] "Bearer " + Authentication token which was received as the result of Core.Login method.
281: * @apiHeaderExample {json} Header-Example:
282: * {
283: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
284: * }
285: *
286: * @apiParam {string=Mail} Module Module name
287: * @apiParam {string=GetSettings} Method Method name
288: *
289: * @apiParamExample {json} Request-Example:
290: * {
291: * Module: 'Mail',
292: * Method: 'GetSettings'
293: * }
294: *
295: * @apiSuccess {object[]} Result Array of response objects.
296: * @apiSuccess {string} Result.Module Module name.
297: * @apiSuccess {string} Result.Method Method name.
298: * @apiSuccess {mixed} Result.Result List of module settings in case of success, otherwise **false**.
299: *
300: * @apiSuccess {array} Result.Result.Accounts="[]" List of accounts.
301: * @apiSuccess {boolean} Result.Result.AllowAddAccounts=false Indicates if adding of new account is allowed.
302: * @apiSuccess {boolean} Result.Result.AllowAutosaveInDrafts=false Indicates if autosave in Drafts folder on compose is allowed.
303: * @apiSuccess {boolean} Result.Result.AllowDefaultAccountForUser=false Indicates if default account is allowed.
304: * @apiSuccess {boolean} Result.Result.AllowIdentities=false Indicates if identities are allowed.
305: * @apiSuccess {boolean} Result.Result.AllowInsertImage=false Indicates if insert of images in composed message body is allowed.
306: * @apiSuccess {int} Result.Result.AutoSaveIntervalSeconds=60 Interval for autosave of message on compose in seconds.
307: * @apiSuccess {int} Result.Result.ImageUploadSizeLimit=0 Max size of upload image in message text in bytes.
308: *
309: * @apiSuccess {int} [Result.ErrorCode] Error code
310: *
311: * @apiSuccessExample {json} Success response example:
312: * {
313: * Module: 'Mail',
314: * Method: 'GetSettings',
315: * Result: { Accounts: [], AllowAddAccounts: true, AllowAutosaveInDrafts: true,
316: * AllowDefaultAccountForUser: true, AllowIdentities: true, AllowInsertImage: true,
317: * AutoSaveIntervalSeconds: 60, ImageUploadSizeLimit: 0 }
318: * }
319: *
320: * @apiSuccessExample {json} Error response example:
321: * {
322: * Module: 'Mail',
323: * Method: 'GetSettings',
324: * Result: false,
325: * ErrorCode: 102
326: * }
327: */
328: /**
329: * Obtains list of module settings for authenticated user.
330: * @return array
331: */
332: public function GetSettings()
333: {
334: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous);
335:
336: $aSettings = array(
337: 'Accounts' => array(),
338: 'AllowAddAccounts' => $this->getConfig('AllowAddAccounts', false),
339: 'AllowAutosaveInDrafts' => (bool)$this->getConfig('AllowAutosaveInDrafts', false),
340: 'AllowChangeMailQuotaOnMailServer' => $this->getConfig('AllowChangeMailQuotaOnMailServer', false),
341: 'AllowDefaultAccountForUser' => $this->getConfig('AllowDefaultAccountForUser', false),
342: 'AllowIdentities' => $this->getConfig('AllowIdentities', false),
343: 'OnlyUserEmailsInIdentities' => $this->getConfig('OnlyUserEmailsInIdentities', false),
344: 'AllowInsertImage' => $this->getConfig('AllowInsertImage', false),
345: 'AutoSaveIntervalSeconds' => $this->getConfig('AutoSaveIntervalSeconds', 60),
346: 'AllowTemplateFolders' => $this->getConfig('AllowTemplateFolders', false),
347: 'AllowInsertTemplateOnCompose' => $this->getConfig('AllowInsertTemplateOnCompose', false),
348: 'MaxTemplatesCountOnCompose' => $this->getConfig('MaxTemplatesCountOnCompose', 100),
349: 'AllowAlwaysRefreshFolders' => $this->getConfig('AllowAlwaysRefreshFolders', false),
350: 'AutocreateMailAccountOnNewUserFirstLogin' => $this->getConfig('AutocreateMailAccountOnNewUserFirstLogin', false),
351: 'IgnoreImapSubscription' => $this->getConfig('IgnoreImapSubscription', false),
352: 'ImageUploadSizeLimit' => $this->getConfig('ImageUploadSizeLimit', 0),
353: 'AllowUnifiedInbox' => $this->getConfig('AllowUnifiedInbox', false),
354: 'SmtpAuthType' => (new \Aurora\Modules\Mail\Enums\SmtpAuthType())->getMap(),
355: 'MessagesSortBy' => $this->getConfig('MessagesSortBy', [])
356: );
357:
358: $oUser = \Aurora\System\Api::getAuthenticatedUser();
359: if ($oUser && $oUser->isNormalOrTenant()) {
360: $aAcc = $this->GetAccounts($oUser->Id);
361: $aResponseAcc = [];
362: foreach ($aAcc as $oAccount) {
363: $aResponseAcc[] = $oAccount->toResponseArray();
364: }
365: $aSettings['Accounts'] = $aResponseAcc;
366:
367: if (isset($oUser->{self::GetName().'::AllowAutosaveInDrafts'})) {
368: $aSettings['AllowAutosaveInDrafts'] = $oUser->{self::GetName().'::AllowAutosaveInDrafts'};
369: }
370: }
371:
372: return $aSettings;
373: }
374:
375: /**
376: * @api {post} ?/Api/ UpdateSettings
377: * @apiName UpdateSettings
378: * @apiGroup Mail
379: * @apiDescription Updates module global or per user settings.
380: *
381: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
382: * @apiHeaderExample {json} Header-Example:
383: * {
384: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
385: * }
386: *
387: * @apiParam {string=Files} Module Module name
388: * @apiParam {string=UpdateSettings} Method Method name
389: * @apiParam {string} Parameters JSON.stringified object<br>
390: * {<br>
391: * &emsp; **AutocreateMailAccountOnNewUserFirstLogin** *boolean* Allows auto-provisioning of new users.<br>
392: * &emsp; **AllowAddAccounts** *boolean* Allows users to add external mailboxes.<br>
393: * &emsp; **AllowAutosaveInDrafts** *boolean* Indicates if message should be saved automatically while compose.<br>
394: * }
395: *
396: * @apiParamExample {json} Request-Example:
397: * {
398: * Module: 'Mail',
399: * Method: 'UpdateSettings',
400: * Parameters: '{ AllowAutosaveInDrafts: false }'
401: * }
402: *
403: * @apiSuccess {object[]} Result Array of response objects.
404: * @apiSuccess {string} Result.Module Module name
405: * @apiSuccess {string} Result.Method Method name
406: * @apiSuccess {boolean} Result.Result Indicates if settings were updated successfully.
407: * @apiSuccess {int} [Result.ErrorCode] Error code
408: *
409: * @apiSuccessExample {json} Success response example:
410: * {
411: * Module: 'Mail',
412: * Method: 'UpdateSettings',
413: * Result: true
414: * }
415: *
416: * @apiSuccessExample {json} Error response example:
417: * {
418: * Module: 'Files',
419: * Method: 'UpdateSettings',
420: * Result: false,
421: * ErrorCode: 102
422: * }
423: */
424: /**
425: * Updates module global or per user settings.
426: * @param boolean $AutocreateMailAccountOnNewUserFirstLogin Allows auto-provisioning of new users.
427: * @param boolean $AllowAddAccounts Allows users to add external mailboxes.
428: * @param boolean $AllowAutosaveInDrafts Indicates if message should be saved automatically while compose.
429: * @return boolean
430: */
431: public function UpdateSettings($AutocreateMailAccountOnNewUserFirstLogin = null, $AllowAddAccounts = null, $AllowAutosaveInDrafts = null)
432: {
433: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
434:
435: $oUser = \Aurora\System\Api::getAuthenticatedUser();
436: if ($oUser) {
437: if ($oUser->isNormalOrTenant()) {
438: if ($AllowAutosaveInDrafts !== null) {
439: $oUser->setExtendedProp(self::GetName().'::AllowAutosaveInDrafts', $AllowAutosaveInDrafts);
440: }
441: $oCoreDecorator = \Aurora\Modules\Core\Module::Decorator();
442: return $oCoreDecorator->UpdateUserObject($oUser);
443: }
444: if ($oUser->Role === \Aurora\System\Enums\UserRole::SuperAdmin) {
445: if ($AutocreateMailAccountOnNewUserFirstLogin !== null) {
446: $this->setConfig('AutocreateMailAccountOnNewUserFirstLogin', $AutocreateMailAccountOnNewUserFirstLogin);
447: }
448: if ($AllowAddAccounts !== null) {
449: $this->setConfig('AllowAddAccounts', $AllowAddAccounts);
450: }
451: return $this->saveModuleConfig();
452: }
453: }
454:
455: return false;
456: }
457:
458: public function GetEntitySpaceLimits($Type, $UserId = null, $TenantId = null)
459: {
460: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
461: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
462:
463: if ($Type === 'User' && is_int($UserId) && $UserId > 0) {
464: $oUser = \Aurora\Modules\Core\Module::Decorator()->GetUserUnchecked($UserId);
465: if ($oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::SuperAdmin ||
466: $oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::TenantAdmin && $oAuthenticatedUser->IdTenant === $oUser->IdTenant) {
467: $oTenant = \Aurora\System\Api::getTenantById($oUser->IdTenant);
468: return [
469: 'UserSpaceLimitMb' => $oUser->{self::GetName() . '::UserSpaceLimitMb'},
470: 'AllowChangeUserSpaceLimit' => $oTenant->{self::GetName() . '::AllowChangeUserSpaceLimit'},
471: ];
472: }
473: }
474:
475: if ($Type === 'Tenant' && is_int($TenantId) && $TenantId > 0) {
476: $oTenant = \Aurora\System\Api::getTenantById($TenantId);
477: if ($oTenant instanceof \Aurora\Modules\Core\Models\Tenant && $oAuthenticatedUser instanceof \Aurora\Modules\Core\Models\User &&
478: ($oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::SuperAdmin ||
479: $oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::TenantAdmin && $oAuthenticatedUser->IdTenant === $TenantId)) {
480: return [
481: 'TenantSpaceLimitMb' => $oTenant->{self::GetName() . '::TenantSpaceLimitMb'},
482: 'UserSpaceLimitMb' => $oTenant->{self::GetName() . '::UserSpaceLimitMb'},
483: 'AllowChangeUserSpaceLimit' => $oTenant->{self::GetName() . '::AllowChangeUserSpaceLimit'},
484: 'AllocatedSpaceMb' => $oTenant->{self::GetName() . '::AllocatedSpaceMb'},
485: ];
486: }
487: }
488:
489: return [];
490: }
491:
492: protected function updateAllocatedTenantSpace($iTenantId, $iNewUserQuota, $iPrevUserQuota)
493: {
494: $oTenant = \Aurora\System\Api::getTenantById($iTenantId);
495: $iAllocatedSpaceMb = $oTenant->{self::GetName() . '::AllocatedSpaceMb'};
496: $iAllocatedSpaceMb += $iNewUserQuota - $iPrevUserQuota;
497: if ($iAllocatedSpaceMb < 0) {
498: $iAllocatedSpaceMb = 0;
499: }
500: $oTenant->setExtendedProp(self::GetName() . '::AllocatedSpaceMb', $iAllocatedSpaceMb);
501: \Aurora\Modules\Core\Module::Decorator()->getTenantsManager()->updateTenant($oTenant);
502: }
503:
504: public function UpdateEntitySpaceLimits($Type, $UserId, $TenantId, $TenantSpaceLimitMb, $UserSpaceLimitMb = null)
505: {
506: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
507: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
508:
509: if ($oAuthenticatedUser instanceof \Aurora\Modules\Core\Models\User && $Type === 'User' && is_int($UserId) && $UserId > 0) {
510: $oUser = \Aurora\Modules\Core\Module::Decorator()->GetUserUnchecked($UserId);
511: if ($oUser instanceof \Aurora\Modules\Core\Models\User
512: && ($oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::SuperAdmin
513: || $oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::TenantAdmin && $oAuthenticatedUser->IdTenant === $oUser->IdTenant)) {
514: $aPrevUserQuota = self::Decorator()->GetEntitySpaceLimits('User', $UserId, $oUser->IdTenant);
515: $aTenantQuota = self::Decorator()->GetEntitySpaceLimits('Tenant', $UserId, $oUser->IdTenant);
516: $mResult = false;
517: if (is_array($aTenantQuota) && isset($aTenantQuota['AllocatedSpaceMb']) && is_array($aPrevUserQuota) && isset($aPrevUserQuota['UserSpaceLimitMb'])) {
518: $iNewAllocatedSpaceMb = $aTenantQuota['AllocatedSpaceMb'] - $aPrevUserQuota['UserSpaceLimitMb'] + $UserSpaceLimitMb;
519: if ($aTenantQuota['TenantSpaceLimitMb'] > 0 && $aTenantQuota['TenantSpaceLimitMb'] < $iNewAllocatedSpaceMb) {
520: throw new \Aurora\Modules\Mail\Exceptions\Exception(Enums\ErrorCodes::TenantQuotaExceeded);
521: }
522: $aArgs = [
523: 'TenantId' => $TenantId,
524: 'Email' => $oUser->PublicId,
525: 'QuotaMb' => $UserSpaceLimitMb
526: ];
527: $this->broadcastEvent(
528: 'UpdateQuota',
529: $aArgs,
530: $mResult
531: );
532: }
533: if ($mResult !== false) {
534: $this->updateAllocatedTenantSpace($TenantId, $UserSpaceLimitMb, $aPrevUserQuota['UserSpaceLimitMb']);
535: $oUser->setExtendedProp(self::GetName() . '::UserSpaceLimitMb', $UserSpaceLimitMb);
536: $oUser->save();
537: }
538: return $mResult;
539: }
540: }
541:
542: if ($Type === 'Tenant' && is_int($TenantId) && $TenantId > 0) {
543: $oTenant = \Aurora\Modules\Core\Module::Decorator()->GetTenantUnchecked($TenantId);
544: if ($oTenant && ($oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::SuperAdmin ||
545: $oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::TenantAdmin && $oAuthenticatedUser->IdTenant === $TenantId)) {
546: $oTenant->setExtendedProp(self::GetName() . '::TenantSpaceLimitMb', $TenantSpaceLimitMb);
547: if (is_int($UserSpaceLimitMb)) {
548: $oTenant->setExtendedProp(self::GetName() . '::UserSpaceLimitMb', $UserSpaceLimitMb);
549: }
550: return $oTenant->save();
551: }
552: }
553:
554: return false;
555: }
556:
557: /**
558: * @api {post} ?/Api/ GetAccounts
559: * @apiName GetAccounts
560: * @apiGroup Mail
561: * @apiDescription Obtains list of mail accounts for user.
562: *
563: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
564: * @apiHeaderExample {json} Header-Example:
565: * {
566: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
567: * }
568: *
569: * @apiParam {string=Mail} Module Module name
570: * @apiParam {string=GetAccounts} Method Method name
571: * @apiParam {string} [Parameters] JSON.stringified object<br>
572: * {<br>
573: * &emsp; **UserId** *int* User identifier.<br>
574: * }
575: *
576: * @apiParamExample {json} Request-Example:
577: * {
578: * Module: 'Mail',
579: * Method: 'GetAccounts'
580: * }
581: *
582: * @apiSuccess {object[]} Result Array of response objects.
583: * @apiSuccess {string} Result.Module Module name.
584: * @apiSuccess {string} Result.Method Method name.
585: * @apiSuccess {mixed} Result.Result List of mail accounts in case of success, otherwise **false**. Description of account properties are placed in GetAccount method description.
586: * @apiSuccess {int} [Result.ErrorCode] Error code
587: *
588: * @apiSuccessExample {json} Success response example:
589: * {
590: * Module: 'Mail',
591: * Method: 'GetAccounts',
592: * Result: [ { "AccountID": 12, "UUID": "uuid_value", "UseToAuthorize": true, "Email": "test@email",
593: * "FriendlyName": "", "IncomingLogin": "test@email", "UseSignature": false, "Signature": "",
594: * "ServerId": 10, "Server": { "Id": 10, "UUID": "uuid_value", "TenantId": 0, "Name": "Mail server",
595: * "IncomingServer": "mail.email", "IncomingPort": 143, "IncomingUseSsl": false, "OutgoingServer": "mail.email",
596: * "OutgoingPort": 25, "OutgoingUseSsl": false, "SmtpAuthType": "0", "OwnerType": "superadmin",
597: * "Domains": "", "ServerId": 10 }, "CanBeUsedToAuthorize": true, "UseThreading": true,
598: * "AllowAutoresponder": false, "AllowAutoresponder": false, "AllowAutoresponder": false } ]
599: * }
600: *
601: * @apiSuccessExample {json} Error response example:
602: * {
603: * Module: 'Mail',
604: * Method: 'GetAccounts',
605: * Result: false,
606: * ErrorCode: 102
607: * }
608: */
609: /**
610: * Obtains list of mail accounts for user.
611: * @param int $UserId User identifier.
612: * @return array|boolean
613: */
614: public function GetAccounts($UserId)
615: {
616: $mResult = false;
617:
618: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
619: if ($oAuthenticatedUser && $oAuthenticatedUser->Id === $UserId) {
620: // If $UserId is equal to identifier of authenticated user, it is a situation when normal user is logged in.
621: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
622: } else {
623: // Otherwise it is a super administrator or some code that is executed after \Aurora\System\Api::skipCheckUserRole method was called.
624: // If it is a second case user identifier shouldn't be checked. It could be even an anonymous user.
625: // There is no $oAuthenticatedUser for anonymous user.
626: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
627: }
628:
629: $aAccounts = $this->getAccountsManager()->getUserAccounts($UserId);
630:
631: $mResult = [];
632: foreach ($aAccounts as $oAccount) {
633: if ($oAuthenticatedUser && $oAccount->IncomingLogin === $oAuthenticatedUser->PublicId) {
634: array_unshift($mResult, $oAccount);
635: } else {
636: $mResult[] = $oAccount;
637: }
638: }
639:
640:
641: return $mResult;
642: }
643:
644: /**
645: * @api {post} ?/Api/ GetAccount
646: * @apiName GetAccount
647: * @apiGroup Mail
648: * @apiDescription Obtains mail account with specified identifier.
649: *
650: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
651: * @apiHeaderExample {json} Header-Example:
652: * {
653: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
654: * }
655: *
656: * @apiParam {string=Mail} Module Module name
657: * @apiParam {string=GetAccount} Method Method name
658: * @apiParam {string} Parameters JSON.stringified object<br>
659: * {<br>
660: * &emsp; **AccountId** *int* Identifier of mail account to obtain.<br>
661: * }
662: *
663: * @apiParamExample {json} Request-Example:
664: * {
665: * Module: 'Mail',
666: * Method: 'GetAccount',
667: * Parameters: '{ "AccountId": 12 }'
668: * }
669: *
670: * @apiSuccess {object[]} Result Array of response objects.
671: * @apiSuccess {string} Result.Module Module name.
672: * @apiSuccess {string} Result.Method Method name.
673: * @apiSuccess {mixed} Result.Result Mail account properties in case of success, otherwise **false**.
674: * @apiSuccess {int} Result.Result.AccountID Account identifier.
675: * @apiSuccess {string} Result.Result.UUID Account UUID.
676: * @apiSuccess {boolean} Result.Result.UseToAuthorize Indicates if account is used for authentication.
677: * @apiSuccess {string} Result.Result.Email Account email.
678: * @apiSuccess {string} Result.Result.FriendlyName Account friendly name.
679: * @apiSuccess {string} Result.Result.IncomingLogin Login for connection to IMAP server.
680: * @apiSuccess {boolean} Result.Result.UseSignature Indicates if signature should be used in outgoing messages.
681: * @apiSuccess {string} Result.Result.Signature Signature in outgoing messages.
682: * @apiSuccess {int} Result.Result.ServerId Server identifier.
683: * @apiSuccess {object} Result.Result.Server Server properties that are used for connection to IMAP and SMTP servers.
684: * @apiSuccess {boolean} Result.Result.CanBeUsedToAuthorize Indicates if account can be used for authentication. It is forbidden to use account for authentication if another user has account with the same credentials and it is allowed to authenticate.
685: * @apiSuccess {boolean} Result.Result.UseThreading Indicates if account uses mail threading.
686: * @apiSuccess {int} [Result.ErrorCode] Error code
687: *
688: * @apiSuccessExample {json} Success response example:
689: * {
690: * Module: 'Mail',
691: * Method: 'GetAccount',
692: * Result: { "AccountID": 12, "UUID": "uuid_value", "UseToAuthorize": true, "Email": "test@email",
693: * "FriendlyName": "", "IncomingLogin": "test@email", "UseSignature": false, "Signature": "",
694: * "ServerId": 10, "Server": { "Id": 10, "UUID": "uuid_value", "TenantId": 0, "Name": "Mail server",
695: * "IncomingServer": "mail.email", "IncomingPort": 143, "IncomingUseSsl": false, "OutgoingServer": "mail.email",
696: * "OutgoingPort": 25, "OutgoingUseSsl": false, "SmtpAuthType": "0", "OwnerType": "superadmin",
697: * "Domains": "", "ServerId": 10 }, "CanBeUsedToAuthorize": true, "UseThreading": true }
698: * }
699: *
700: * @apiSuccessExample {json} Error response example:
701: * {
702: * Module: 'Mail',
703: * Method: 'GetAccount',
704: * Result: false,
705: * ErrorCode: 102
706: * }
707: */
708: /**
709: * Obtains mail account with specified identifier.
710: * @param int $AccountId Identifier of mail account to obtain.
711: * @return \Aurora\Modules\Mail\Models\MailAccount|boolean
712: */
713: public function GetAccount($AccountId)
714: {
715: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
716:
717: $oAccount = $this->getAccountsManager()->getAccountById($AccountId);
718:
719: self::checkAccess($oAccount);
720:
721: return $oAccount;
722: }
723:
724: public function GetAccountByEmail($Email, $UserId = 0)
725: {
726: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
727: $oUser = $UserId !== 0 ? \Aurora\Modules\Core\Module::Decorator()->GetUserUnchecked($UserId) : null;
728:
729: // Method has its specific access check so checkAccess method isn't used.
730: if ($oAuthenticatedUser instanceof \Aurora\Modules\Core\Models\User && $oUser instanceof \Aurora\Modules\Core\Models\User) {
731: if ($oUser->Id === $oAuthenticatedUser->Id) {
732: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
733: } elseif ($oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::TenantAdmin && $oUser->IdTenant === $oAuthenticatedUser->IdTenant) {
734: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
735: }
736: } else {
737: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
738: }
739:
740: $mResult = false;
741: $oAccount = $this->getAccountsManager()->getAccountByEmail($Email, $UserId);
742: if ($oAccount instanceof \Aurora\Modules\Mail\Models\MailAccount && $UserId === $oAccount->IdUser) {
743: $mResult = $oAccount;
744: }
745:
746: return $mResult;
747: }
748:
749: /**
750: * @api {post} ?/Api/ CreateAccount
751: * @apiName CreateAccount
752: * @apiGroup Mail
753: * @apiDescription Creates mail account.
754: *
755: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
756: * @apiHeaderExample {json} Header-Example:
757: * {
758: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
759: * }
760: *
761: * @apiParam {string=Mail} Module Module name
762: * @apiParam {string=CreateAccount} Method Method name
763: * @apiParam {string} Parameters JSON.stringified object<br>
764: * {<br>
765: * &emsp; **UserId** *int* (optional) User identifier.<br>
766: * &emsp; **FriendlyName** *string* (optional) Friendly name.<br>
767: * &emsp; **Email** *string* Email.<br>
768: * &emsp; **IncomingLogin** *string* Login for IMAP connection.<br>
769: * &emsp; **IncomingPassword** *string* Password for IMAP connection.<br>
770: * &emsp; **Server** *object* List of settings for IMAP and SMTP connections.<br>
771: * }
772: *
773: * @apiParamExample {json} Request-Example:
774: * {
775: * Module: 'Mail',
776: * Method: 'CreateAccount',
777: * Parameters: '{ "Email": "test@email", "IncomingLogin": "test@email", "IncomingPassword": "pass_value",
778: * "Server": { "ServerId": 10 } }'
779: * }
780: *
781: * @apiSuccess {object[]} Result Array of response objects.
782: * @apiSuccess {string} Result.Module Module name.
783: * @apiSuccess {string} Result.Method Method name.
784: * @apiSuccess {mixed} Result.Result Mail account properties in case of success, otherwise **false**.
785: * @apiSuccess {int} Result.Result.AccountID Created account identifier.
786: * @apiSuccess {string} Result.Result.UUID Created account UUID.
787: * @apiSuccess {boolean} Result.Result.UseToAuthorize Indicates if account is used for authentication.
788: * @apiSuccess {string} Result.Result.Email Account email.
789: * @apiSuccess {string} Result.Result.FriendlyName Account friendly name.
790: * @apiSuccess {string} Result.Result.IncomingLogin Login for connection to IMAP server.
791: * @apiSuccess {boolean} Result.Result.UseSignature Indicates if signature should be used in outgoing messages.
792: * @apiSuccess {string} Result.Result.Signature Signature in outgoing messages.
793: * @apiSuccess {int} Result.Result.ServerId Server identifier.
794: * @apiSuccess {object} Result.Result.Server Server properties that are used for connection to IMAP and SMTP servers.
795: * @apiSuccess {boolean} Result.Result.CanBeUsedToAuthorize Indicates if account can be used for authentication. It is forbidden to use account for authentication if another user has account with the same credentials and it is allowed to authenticate.
796: * @apiSuccess {int} [Result.ErrorCode] Error code
797: *
798: * @apiSuccessExample {json} Success response example:
799: * {
800: * Module: 'Mail',
801: * Method: 'CreateAccount',
802: * Result: { "AccountID": 12, "UUID": "uuid_value", "UseToAuthorize": true, "Email": "test@email",
803: * "FriendlyName": "", "IncomingLogin": "test@email", "UseSignature": false, "Signature": "",
804: * "ServerId": 10, "Server": { "ServerId": 10, "Name": "Mail server", "IncomingServer": "mail.server",
805: * "IncomingPort": 143, "IncomingUseSsl": false, "OutgoingServer": "mail.server", "OutgoingPort": 25,
806: * "OutgoingUseSsl": false, "SmtpAuthType": "0", "Domains": "" }, "CanBeUsedToAuthorize": true }
807: * }
808: *
809: * @apiSuccessExample {json} Error response example:
810: * {
811: * Module: 'Mail',
812: * Method: 'CreateAccount',
813: * Result: false,
814: * ErrorCode: 102
815: * }
816: */
817: /**
818: * Creates mail account.
819: * @param int $UserId User identifier.
820: * @param string $FriendlyName Friendly name.
821: * @param string $Email Email.
822: * @param string $IncomingLogin Login for IMAP connection.
823: * @param string $IncomingPassword Password for IMAP connection.
824: * @param array $Server List of settings for IMAP and SMTP connections.
825: * @return \Aurora\Modules\Mail\Models\MailAccount|boolean
826: */
827: public function CreateAccount(
828: $UserId = 0,
829: $FriendlyName = '',
830: $Email = '',
831: $IncomingLogin = '',
832: $IncomingPassword = '',
833: $Server = null,
834: $XAuth = null
835: ) {
836: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
837:
838: self::checkAccess(null, $UserId);
839:
840: $oAccount = $this->GetAccountByEmail($Email, $UserId);
841: $oServer = false;
842:
843: if ($oAccount instanceof \Aurora\Modules\Mail\Models\MailAccount) {
844: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::AccountExists);
845: } else {
846: if ($Email) {
847: $sDomain = \MailSo\Base\Utils::GetDomainFromEmail($Email);
848: $bCustomServerCreated = false;
849: $iServerId = $Server['ServerId'];
850: if ($Server !== null && $iServerId === 0) {
851: $oNewServer = new \Aurora\Modules\Mail\Models\Server();
852: $oNewServer->Name = $Server['IncomingServer'];
853: $oNewServer->IncomingServer = $Server['IncomingServer'];
854: $oNewServer->IncomingPort = $Server['IncomingPort'];
855: $oNewServer->IncomingUseSsl = $Server['IncomingUseSsl'];
856: $oNewServer->OutgoingServer = $Server['OutgoingServer'];
857: $oNewServer->OutgoingPort = $Server['OutgoingPort'];
858: $oNewServer->OutgoingUseSsl = $Server['OutgoingUseSsl'];
859: $oNewServer->SmtpAuthType = $Server['SmtpAuthType'];
860: $oNewServer->Domains = $sDomain;
861: $oNewServer->EnableThreading = $Server['EnableThreading'];
862: $iServerId = $this->getServersManager()->createServer($oNewServer);
863: $bCustomServerCreated = true;
864: }
865:
866: if ($Server === null) {
867: $aServerResult = self::Decorator()->GetMailServerByDomain($sDomain, /*AllowWildcardDomain*/true);
868: if (isset($aServerResult['Server'])) {
869: $oServer = $aServerResult['Server'];
870: $iServerId = $oServer->Id;
871: }
872: }
873:
874: $oAccount = new \Aurora\Modules\Mail\Models\MailAccount();
875:
876: $oAccount->IdUser = $UserId;
877: $oAccount->FriendlyName = $FriendlyName;
878: $oAccount->Email = $Email;
879: $oAccount->IncomingLogin = $IncomingLogin;
880: $oAccount->setPassword($IncomingPassword);
881: if ($iServerId > 0) {
882: $oServer = $this->getServersManager()->getServer($iServerId);
883: }
884:
885: if ($oServer) {
886: $oAccount->Server()->associate($oServer);
887: $oAccount->UseThreading = $oServer->EnableThreading;
888: }
889:
890: $oAccount->XOAuth = $XAuth;
891:
892: $bAccoutResult = false;
893: $oResException = null;
894: $bDoImapLoginOnAccountCreate = $this->getConfig('DoImapLoginOnAccountCreate', true) && is_null($XAuth);
895: if ($bDoImapLoginOnAccountCreate) {
896: $oResException = $this->getMailManager()->validateAccountConnection($oAccount, false);
897: }
898:
899: $oUser = \Aurora\Modules\Core\Module::Decorator()->GetUserUnchecked($UserId);
900: $aQuota = [];
901: $iQuota = 0;
902:
903: if ($oResException === null && $oUser instanceof \Aurora\Modules\Core\Models\User && $oUser->PublicId === $oAccount->Email) {
904: $aTenantQuota = self::Decorator()->GetEntitySpaceLimits('Tenant', $UserId, $oUser->IdTenant);
905: if (is_array($aTenantQuota) && isset($aTenantQuota['AllocatedSpaceMb']) && isset($aTenantQuota['TenantSpaceLimitMb'])) {
906: if ($bDoImapLoginOnAccountCreate) {
907: $aQuota = $this->getMailManager()->getQuota($oAccount);
908: } else {
909: $aQuota[1] = 0;
910: }
911: $iQuota = (is_array($aQuota) && isset($aQuota[1])) ? $aQuota[1] / 1024 : 0;
912: $iNewAllocatedSpaceMb = $aTenantQuota['AllocatedSpaceMb'] + $iQuota;
913: if ($aTenantQuota['TenantSpaceLimitMb'] > 0 && $aTenantQuota['TenantSpaceLimitMb'] < $iNewAllocatedSpaceMb) {
914: $oResException = new \Aurora\Modules\Mail\Exceptions\Exception(Enums\ErrorCodes::TenantQuotaExceeded, null, $this->i18N('ERROR_TENANT_QUOTA_EXCEEDED'));
915: }
916: }
917: }
918:
919: if ($oResException === null) {
920: if ($oUser instanceof \Aurora\Modules\Core\Models\User && $oUser->PublicId === $Email &&
921: !$this->getAccountsManager()->useToAuthorizeAccountExists($Email)) {
922: $oAccount->UseToAuthorize = true;
923: }
924: $bAccoutResult = $this->getAccountsManager()->createAccount($oAccount);
925: }
926:
927: if ($bAccoutResult) {
928: if ($oAccount->Email === $oUser->PublicId && $bDoImapLoginOnAccountCreate) {
929: if (empty($aQuota)) {
930: $aQuota = $this->getMailManager()->getQuota($oAccount);
931: $iQuota = (is_array($aQuota) && isset($aQuota[1])) ? $aQuota[1] / 1024 : 0;
932: }
933: $this->updateAllocatedTenantSpace($oUser->IdTenant, $iQuota, 0);
934: $oUser->setExtendedProp(self::GetName() . '::UserSpaceLimitMb', $iQuota);
935: $oUser->save();
936: }
937: if ($oServer && $oServer->EnableSieve && $this->getConfig('EnableAllowBlockLists', false)) {
938: try {
939: $this->getSieveManager()->setAllowBlockLists($oAccount, [], []);
940: } catch (\Exception $oEx) {
941: Api::LogException($oEx);
942: }
943: }
944: return $oAccount;
945: } elseif ($bCustomServerCreated) {
946: $this->getServersManager()->deleteServer($iServerId);
947: }
948:
949: if ($oResException !== null) {
950: throw $oResException;
951: }
952: }
953: }
954: return false;
955: }
956:
957: /**
958: * @api {post} ?/Api/ UpdateAccount
959: * @apiName UpdateAccount
960: * @apiGroup Mail
961: * @apiDescription Updates mail account.
962: *
963: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
964: * @apiHeaderExample {json} Header-Example:
965: * {
966: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
967: * }
968: *
969: * @apiParam {string=Mail} Module Module name
970: * @apiParam {string=UpdateAccount} Method Method name
971: * @apiParam {string} Parameters JSON.stringified object<br>
972: * {<br>
973: * &emsp; **AccountID** *int* Identifier of account to update.<br>
974: * &emsp; **FriendlyName** *string* New friendly name.<br>
975: * &emsp; **Email** *string* New email.<br>
976: * &emsp; **IncomingLogin** *string* New loging for IMAP connection.<br>
977: * &emsp; **IncomingPassword** *string* New password for IMAP connection.<br>
978: * &emsp; **Server** *object* List of settings for IMAP and SMTP connections.<br>
979: * &emsp; **UseThreading** *boolean* Indicates if account uses mail threading.<br>
980: * &emsp; **SaveRepliesToCurrFolder** *boolean* Indicates if replies should be saved to current folder (not Sent Items).<br>
981: * }
982: *
983: * @apiParamExample {json} Request-Example:
984: * {
985: * Module: 'Mail',
986: * Method: 'UpdateAccount',
987: * Parameters: '{ "Email": "test@email", "IncomingLogin": "test@email",
988: * "IncomingPassword": "pass_value", "Server": { "ServerId": 10 }, "UseThreading": true,
989: * "SaveRepliesToCurrFolder": false }'
990: * }
991: *
992: * @apiSuccess {object[]} Result Array of response objects.
993: * @apiSuccess {string} Result.Module Module name.
994: * @apiSuccess {string} Result.Method Method name.
995: * @apiSuccess {boolean} Result.Result Indicates if account was updated successfully.
996: * @apiSuccess {int} [Result.ErrorCode] Error code
997: *
998: * @apiSuccessExample {json} Success response example:
999: * {
1000: * Module: 'Mail',
1001: * Method: 'UpdateAccount',
1002: * Result: true
1003: * }
1004: *
1005: * @apiSuccessExample {json} Error response example:
1006: * {
1007: * Module: 'Mail',
1008: * Method: 'UpdateAccount',
1009: * Result: false,
1010: * ErrorCode: 102
1011: * }
1012: */
1013: /**
1014: * Updates mail account.
1015: * @param int $AccountID Identifier of account to update.
1016: * @param boolean $UseToAuthorize Indicates if account can be used to authorize user.
1017: * @param string $Email New email.
1018: * @param string $FriendlyName New friendly name.
1019: * @param string $IncomingLogin New login for IMAP connection.
1020: * @param string $IncomingPassword New password for IMAP connection.
1021: * @param array $Server List of settings for IMAP and SMTP connections.
1022: * @param boolean $UseThreading Indicates if account uses mail threading.
1023: * @param boolean $SaveRepliesToCurrFolder Indicates if replies should be saved to current folder (not Sent Items)
1024: * @return boolean
1025: * @throws \Aurora\System\Exceptions\ApiException
1026: */
1027: public function UpdateAccount(
1028: $AccountID,
1029: $UseToAuthorize = null,
1030: $Email = null,
1031: $FriendlyName = null,
1032: $IncomingLogin = null,
1033: $IncomingPassword = null,
1034: $Server = null,
1035: $UseThreading = null,
1036: $SaveRepliesToCurrFolder = null
1037: ) {
1038: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1039:
1040: if ($AccountID > 0) {
1041: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
1042:
1043: self::checkAccess($oAccount);
1044:
1045: if ($oAccount) {
1046: if (!empty($Email)) {
1047: $oAccount->Email = $Email;
1048: }
1049: if ($UseToAuthorize === false || $UseToAuthorize === true && !$this->getAccountsManager()->useToAuthorizeAccountExists($oAccount->Email, $oAccount->Id)) {
1050: $oAccount->UseToAuthorize = $UseToAuthorize;
1051: }
1052: if ($FriendlyName !== null) {
1053: $oAccount->FriendlyName = $FriendlyName;
1054: }
1055: if (!empty($IncomingLogin)) {
1056: $oAccount->IncomingLogin = $IncomingLogin;
1057: }
1058: if (!empty($IncomingPassword)) {
1059: $oAccount->setPassword($IncomingPassword);
1060: }
1061: if ($Server !== null) {
1062: if ($Server['ServerId'] === 0) {
1063: $sDomains = explode('@', $oAccount->Email)[1];
1064: $oNewServer = new \Aurora\Modules\Mail\Models\Server();
1065: $oNewServer->Name = $Server['IncomingServer'];
1066: $oNewServer->IncomingServer = $Server['IncomingServer'];
1067: $oNewServer->IncomingPort = $Server['IncomingPort'];
1068: $oNewServer->IncomingUseSsl = $Server['IncomingUseSsl'];
1069: $oNewServer->OutgoingServer = $Server['OutgoingServer'];
1070: $oNewServer->OutgoingPort = $Server['OutgoingPort'];
1071: $oNewServer->OutgoingUseSsl = $Server['OutgoingUseSsl'];
1072: $oNewServer->SmtpAuthType = $Server['SmtpAuthType'];
1073: $oNewServer->Domains = $sDomains;
1074: $oNewServer->EnableThreading = $Server['EnableThreading'];
1075: $iNewServerId = $this->getServersManager()->createServer($oNewServer);
1076: $oAccount->Server = $iNewServerId;
1077: } elseif ($oAccount->ServerId === $Server['ServerId']) {
1078: $oAccServer = $oAccount->getServer();
1079: if ($oAccServer && $oAccServer->OwnerType === \Aurora\Modules\Mail\Enums\ServerOwnerType::Account) {
1080: $oAccServer->Name = $Server['IncomingServer'];
1081: $oAccServer->IncomingServer = $Server['IncomingServer'];
1082: $oAccServer->IncomingPort = $Server['IncomingPort'];
1083: $oAccServer->IncomingUseSsl = $Server['IncomingUseSsl'];
1084: $oAccServer->OutgoingServer = $Server['OutgoingServer'];
1085: $oAccServer->OutgoingPort = $Server['OutgoingPort'];
1086: $oAccServer->OutgoingUseSsl = $Server['OutgoingUseSsl'];
1087: $oAccServer->SmtpAuthType = $Server['SmtpAuthType'];
1088:
1089: $this->getServersManager()->updateServer($oAccServer);
1090: }
1091: } else {
1092: $oAccServer = $oAccount->getServer();
1093: if ($oAccServer && $oAccServer->OwnerType === \Aurora\Modules\Mail\Enums\ServerOwnerType::Account) {
1094: $this->getServersManager()->deleteServer($oAccServer->Id);
1095: }
1096: $oAccount->Server = $Server['ServerId'];
1097: }
1098: }
1099:
1100: if ($UseThreading !== null) {
1101: $oAccount->UseThreading = $UseThreading;
1102: }
1103:
1104: if ($SaveRepliesToCurrFolder !== null) {
1105: $oAccount->SaveRepliesToCurrFolder = $SaveRepliesToCurrFolder;
1106: }
1107:
1108: if ($this->getAccountsManager()->updateAccount($oAccount)) {
1109: return $oAccount;
1110: }
1111: }
1112: } else {
1113: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
1114: }
1115:
1116: return false;
1117: }
1118:
1119: public function UpdateAccountUnifiedMailbox(
1120: $AccountID,
1121: $IncludeInUnifiedMailbox,
1122: $ShowUnifiedMailboxLabel,
1123: $UnifiedMailboxLabelText,
1124: $UnifiedMailboxLabelColor
1125: ) {
1126: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1127: if (!$this->getConfig('AllowUnifiedInbox', false)) {
1128: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::AccessDenied);
1129: }
1130: if (!is_int($AccountID) || $AccountID <= 0 || !is_bool($IncludeInUnifiedMailbox) || !is_bool($ShowUnifiedMailboxLabel) ||
1131: !is_string($UnifiedMailboxLabelText) || !is_string($UnifiedMailboxLabelColor)) {
1132: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
1133: }
1134:
1135: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
1136:
1137: self::checkAccess($oAccount);
1138:
1139: if ($oAccount instanceof Models\MailAccount) {
1140: $oAccount->IncludeInUnifiedMailbox = $IncludeInUnifiedMailbox;
1141: $oAccount->ShowUnifiedMailboxLabel = $ShowUnifiedMailboxLabel;
1142: $oAccount->UnifiedMailboxLabelText = $UnifiedMailboxLabelText;
1143: $oAccount->UnifiedMailboxLabelColor = $UnifiedMailboxLabelColor;
1144:
1145: if ($this->getAccountsManager()->updateAccount($oAccount)) {
1146: return $oAccount;
1147: }
1148: }
1149:
1150: return false;
1151: }
1152:
1153: /**
1154: * @api {post} ?/Api/ DeleteAccount
1155: * @apiName DeleteAccount
1156: * @apiGroup Mail
1157: * @apiDescription Deletes mail account.
1158: *
1159: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1160: * @apiHeaderExample {json} Header-Example:
1161: * {
1162: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1163: * }
1164: *
1165: * @apiParam {string=Mail} Module Module name
1166: * @apiParam {string=DeleteAccount} Method Method name
1167: * @apiParam {string} Parameters JSON.stringified object<br>
1168: * {<br>
1169: * &emsp; **AccountID** *int* Identifier of account to delete.<br>
1170: * }
1171: *
1172: * @apiParamExample {json} Request-Example:
1173: * {
1174: * Module: 'Mail',
1175: * Method: 'DeleteAccount',
1176: * Parameters: '{ "AccountID": 12 }'
1177: * }
1178: *
1179: * @apiSuccess {object[]} Result Array of response objects.
1180: * @apiSuccess {string} Result.Module Module name.
1181: * @apiSuccess {string} Result.Method Method name.
1182: * @apiSuccess {boolean} Result.Result Indicates if account was deleted successfully.
1183: * @apiSuccess {int} [Result.ErrorCode] Error code
1184: *
1185: * @apiSuccessExample {json} Success response example:
1186: * {
1187: * Module: 'Mail',
1188: * Method: 'DeleteAccount',
1189: * Result: true
1190: * }
1191: *
1192: * @apiSuccessExample {json} Error response example:
1193: * {
1194: * Module: 'Mail',
1195: * Method: 'DeleteAccount',
1196: * Result: false,
1197: * ErrorCode: 102
1198: * }
1199: */
1200: /**
1201: * Deletes mail account.
1202: * @param int $AccountID Account identifier.
1203: * @return boolean
1204: * @throws \Aurora\System\Exceptions\ApiException
1205: */
1206: public function DeleteAccount($AccountID)
1207: {
1208: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1209:
1210: $bResult = false;
1211:
1212: if ($AccountID > 0) {
1213: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
1214:
1215: self::checkAccess($oAccount);
1216:
1217: if ($oAccount) {
1218: $this->getIdentitiesManager()->deleteAccountIdentities($oAccount->Id);
1219: $this->getMailManager()->deleteSystemFolderNames($oAccount->Id);
1220:
1221: $oServer = $oAccount->getServer();
1222:
1223: $oUser = \Aurora\Modules\Core\Module::Decorator()->GetUserUnchecked($oAccount->IdUser);
1224: if ($oUser instanceof \Aurora\Modules\Core\Models\User && $oAccount->Email === $oUser->PublicId) {
1225: $iQuota = $oUser->{self::GetName() . '::UserSpaceLimitMb'};
1226: $this->updateAllocatedTenantSpace($oUser->IdTenant, 0, $iQuota);
1227: }
1228:
1229: $aArgs = [
1230: 'Account' => $oAccount,
1231: 'User' => $oUser
1232: ];
1233: $this->broadcastEvent(
1234: 'BeforeDeleteAccount',
1235: $aArgs
1236: );
1237: $bResult = $this->getAccountsManager()->deleteAccount($oAccount);
1238:
1239: if ($bResult && $oServer && $oServer->OwnerType === \Aurora\Modules\Mail\Enums\ServerOwnerType::Account) {
1240: $this->getServersManager()->deleteServer($oServer->Id);
1241: }
1242: }
1243:
1244: return $bResult;
1245: } else {
1246: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
1247: }
1248: }
1249:
1250: /**
1251: * @api {post} ?/Api/ GetServers
1252: * @apiName GetServers
1253: * @apiGroup Mail
1254: * @apiDescription Obtains list of servers which contains settings for IMAP and SMTP connections.
1255: *
1256: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1257: * @apiHeaderExample {json} Header-Example:
1258: * {
1259: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1260: * }
1261: *
1262: * @apiParam {string=Mail} Module Module name
1263: * @apiParam {string=GetServers} Method Method name
1264: * @apiParam {string} [Parameters] JSON.stringified object<br>
1265: * {<br>
1266: * &emsp; **TenantId** *int* (optional) Identifier of tenant which contains servers to return. If TenantId is 0 returns server which are belonged to SuperAdmin, not Tenant.<br>
1267: * &emsp; **Offset** *int* (optional) Says to skip that many servers before beginning to return them.<br>
1268: * &emsp; **Limit** *int* (optional) Limit says to return that many servers in the list.<br>
1269: * &emsp; **Search** *string* (optional) Search string.<br>
1270: * }
1271: *
1272: * @apiParamExample {json} Request-Example:
1273: * {
1274: * Module: 'Mail',
1275: * Method: 'GetServers'
1276: * }
1277: *
1278: * @apiSuccess {object[]} Result Array of response objects.
1279: * @apiSuccess {string} Result.Module Module name.
1280: * @apiSuccess {string} Result.Method Method name.
1281: * @apiSuccess {mixed} Result.Result List of mail servers in case of success, otherwise **false**. Description of server properties are placed in GetServer method description.
1282: * @apiSuccess {int} [Result.ErrorCode] Error code
1283: *
1284: * @apiSuccessExample {json} Success response example:
1285: * {
1286: * Module: 'Mail',
1287: * Method: 'GetServers',
1288: * Result: [ { "Id": 10, "UUID": "uuid_value", "TenantId": 0, "Name": "Mail server",
1289: * "IncomingServer": "mail.email", "IncomingPort": 143, "IncomingUseSsl": false, "OutgoingServer": "mail.email",
1290: * "OutgoingPort": 25, "OutgoingUseSsl": false, "SmtpAuthType": "0", "OwnerType": "superadmin",
1291: * "Domains": "", "ServerId": 10 } ]
1292: * }
1293: *
1294: * @apiSuccessExample {json} Error response example:
1295: * {
1296: * Module: 'Mail',
1297: * Method: 'GetServers',
1298: * Result: false,
1299: * ErrorCode: 102
1300: * }
1301: */
1302: /**
1303: * Obtains list of servers which contains settings for IMAP and SMTP connections.
1304: * @param int $TenantId Identifier of tenant which contains servers to return. If $TenantId is 0 returns server which are belonged to SuperAdmin, not Tenant.
1305: * @param int $Offset Says to skip that many servers before beginning to return them.
1306: * @param int $Limit Limit says to return that many servers in the list.
1307: * @param string $Search Search string.
1308: * @return array
1309: */
1310: public function GetServers($TenantId = 0, $Offset = 0, $Limit = 0, $Search = '')
1311: {
1312: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
1313: if ($oAuthenticatedUser instanceof \Aurora\Modules\Core\Models\User && $oAuthenticatedUser->isNormalOrTenant()) {
1314: if ($TenantId === 0) {
1315: $TenantId = $oAuthenticatedUser->IdTenant;
1316: } elseif ($TenantId !== $oAuthenticatedUser->IdTenant) {
1317: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::AccessDenied);
1318: }
1319: } else {
1320: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
1321: }
1322:
1323: return [
1324: 'Items' => $this->getServersManager()->getServerList($TenantId, $Offset, $Limit, $Search)->toArray(),
1325: 'Count' => $this->getServersManager()->getServersCount($TenantId, $Search),
1326: ];
1327: }
1328:
1329: /**
1330: * @api {post} ?/Api/ GetServer
1331: * @apiName GetServer
1332: * @apiGroup Mail
1333: * @apiDescription Obtains server with specified server identifier.
1334: *
1335: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1336: * @apiHeaderExample {json} Header-Example:
1337: * {
1338: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1339: * }
1340: *
1341: * @apiParam {string=Mail} Module Module name
1342: * @apiParam {string=GetServer} Method Method name
1343: * @apiParam {string} Parameters JSON.stringified object<br>
1344: * {<br>
1345: * &emsp; **ServerId** *int* Server identifier.<br>
1346: * }
1347: *
1348: * @apiParamExample {json} Request-Example:
1349: * {
1350: * Module: 'Mail',
1351: * Method: 'GetServer',
1352: * Parameters: '{ "ServerId": 10 }'
1353: * }
1354: *
1355: * @apiSuccess {object[]} Result Array of response objects.
1356: * @apiSuccess {string} Result.Module Module name.
1357: * @apiSuccess {string} Result.Method Method name.
1358: * @apiSuccess {mixed} Result.Result Mail server properties in case of success, otherwise **false**.
1359: * @apiSuccess {int} Result.Result.ServerId Server identifier.
1360: * @apiSuccess {string} Result.Result.UUID Server UUID.
1361: * @apiSuccess {int} Result.Result.TenantId Tenant identifier.
1362: * @apiSuccess {string} Result.Result.Name Server name.
1363: * @apiSuccess {string} Result.Result.IncomingServer IMAP server.
1364: * @apiSuccess {int} Result.Result.IncomingPort IMAP port.
1365: * @apiSuccess {boolean} Result.Result.IncomingUseSsl Indicates if SSL should be used for IMAP connection.
1366: * @apiSuccess {string} Result.Result.OutgoingServer SMTP server.
1367: * @apiSuccess {int} Result.Result.OutgoingPort SMTP port.
1368: * @apiSuccess {boolean} Result.Result.OutgoingUseSsl Indicates if SSL should be used for SMTP connection.
1369: * @apiSuccess {string} Result.Result.SmtpAuthType SMTP authentication type: '0' - no authentication, '1' - specified credentials, '2' - user credentials
1370: * @apiSuccess {string} Result.Result.SmtpLogin
1371: * @apiSuccess {string} Result.Result.SmtpPassword
1372: * @apiSuccess {string} Result.Result.OwnerType Owner type: 'superadmin' - server was created by SuperAdmin user, 'tenant' - server was created by TenantAdmin user, 'account' - server was created when account was created and any existent server was chosen.
1373: * @apiSuccess {string} Result.Result.Domains List of server domain separated by comma.
1374: * @apiSuccess {int} [Result.ErrorCode] Error code
1375: *
1376: * @apiSuccessExample {json} Success response example:
1377: * {
1378: * Module: 'Mail',
1379: * Method: 'GetServer',
1380: * Result: { "ServerId": 10, "UUID": "uuid_value", "TenantId": 0, "Name": "Mail server",
1381: * "IncomingServer": "mail.email", "IncomingPort": 143, "IncomingUseSsl": false, "OutgoingServer": "mail.email",
1382: * "OutgoingPort": 25, "OutgoingUseSsl": false, "SmtpAuthType": "0", "OwnerType": "superadmin",
1383: * "Domains": "" }
1384: * }
1385: *
1386: * @apiSuccessExample {json} Error response example:
1387: * {
1388: * Module: 'Mail',
1389: * Method: 'GetServer',
1390: * Result: false,
1391: * ErrorCode: 102
1392: * }
1393: */
1394: /**
1395: * Obtains server with specified server identifier.
1396: * @param int $ServerId Server identifier.
1397: * @return \Aurora\Modules\Mail\Models\Server|boolean
1398: */
1399: public function GetServer($ServerId)
1400: {
1401: $oServer = $this->getServersManager()->getServer($ServerId);
1402: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
1403: if ($oAuthenticatedUser instanceof \Aurora\Modules\Core\Models\User && $oAuthenticatedUser->isNormalOrTenant()) {
1404: if ($oServer->TenantId !== $oAuthenticatedUser->IdTenant) {
1405: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::AccessDenied);
1406: }
1407: } else {
1408: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
1409: }
1410:
1411: return $oServer;
1412: }
1413:
1414: /**
1415: * @api {post} ?/Api/ CreateServer
1416: * @apiName CreateServer
1417: * @apiGroup Mail
1418: * @apiDescription Creates mail server.
1419: *
1420: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1421: * @apiHeaderExample {json} Header-Example:
1422: * {
1423: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1424: * }
1425: *
1426: * @apiParam {string=Mail} Module Module name
1427: * @apiParam {string=CreateServer} Method Method name
1428: * @apiParam {string} Parameters JSON.stringified object<br>
1429: * {<br>
1430: * &emsp; **Name** *string* Server name.<br>
1431: * &emsp; **IncomingServer** *string* IMAP server.<br>
1432: * &emsp; **IncomingPort** *int* Port for connection to IMAP server.<br>
1433: * &emsp; **IncomingUseSsl** *boolean* Indicates if it is necessary to use SSL while connecting to IMAP server.<br>
1434: * &emsp; **OutgoingServer** *string* SMTP server.<br>
1435: * &emsp; **OutgoingPort** *int* Port for connection to SMTP server.<br>
1436: * &emsp; **OutgoingUseSsl** *boolean* Indicates if it is necessary to use SSL while connecting to SMTP server.<br>
1437: * &emsp; **SmtpAuthType** *string* SMTP authentication type: '0' - no authentication, '1' - specified credentials, '2' - user credentials.<br>
1438: * &emsp; **SmtpLogin** *string* (optional)<br>
1439: * &emsp; **SmtpPassword** *string* (optional)<br>
1440: * &emsp; **Domains** *string* List of domains separated by comma.<br>
1441: * &emsp; **TenantId** *int* (optional) If tenant identifier is specified creates mail server belonged to specified tenant.<br>
1442: * }
1443: *
1444: * @apiParamExample {json} Request-Example:
1445: * {
1446: * Module: 'Mail',
1447: * Method: 'CreateServer',
1448: * Parameters: '{ "Name": "Server name", "IncomingServer": "mail.server", "IncomingPort": 143,
1449: * "IncomingUseSsl": false, "OutgoingServer": "mail.server", "OutgoingPort": 25,
1450: * "OutgoingUseSsl": false, "SmtpAuthType": "0", "Domains": "" }'
1451: * }
1452: *
1453: * @apiSuccess {object[]} Result Array of response objects.
1454: * @apiSuccess {string} Result.Module Module name.
1455: * @apiSuccess {string} Result.Method Method name.
1456: * @apiSuccess {mixed} Result.Result Identifier of created server in case of success, otherwise **false**.
1457: * @apiSuccess {int} [Result.ErrorCode] Error code
1458: *
1459: * @apiSuccessExample {json} Success response example:
1460: * {
1461: * Module: 'Mail',
1462: * Method: 'CreateServer',
1463: * Result: 10
1464: * }
1465: *
1466: * @apiSuccessExample {json} Error response example:
1467: * {
1468: * Module: 'Mail',
1469: * Method: 'CreateServer',
1470: * Result: false,
1471: * ErrorCode: 102
1472: * }
1473: */
1474: /**
1475: * Creates mail server.
1476: * @param string $Name Server name.
1477: * @param string $IncomingServer IMAP server.
1478: * @param int $IncomingPort Port for connection to IMAP server.
1479: * @param boolean $IncomingUseSsl Indicates if it is necessary to use SSL while connecting to IMAP server.
1480: * @param string $OutgoingServer SMTP server.
1481: * @param int $OutgoingPort Port for connection to SMTP server.
1482: * @param boolean $OutgoingUseSsl Indicates if it is necessary to use SSL while connecting to SMTP server.
1483: * @param string $SmtpAuthType SMTP authentication type: '0' - no authentication, '1' - specified credentials, '2' - user credentials.
1484: * @param string $Domains List of domains separated by comma.
1485: * @param boolean $EnableThreading
1486: * @param boolean $EnableSieve
1487: * @param int $SievePort
1488: * @param string $SmtpLogin (optional)
1489: * @param string $SmtpPassword (optional)
1490: * @param boolean $UseFullEmailAddressAsLogin (optional)
1491: * @param int $TenantId (optional) If tenant identifier is specified creates mail server belonged to specified tenant.
1492: * @param boolean $SetExternalAccessServers
1493: * @param string $ExternalAccessImapServer
1494: * @param int $ExternalAccessImapPort
1495: * @param int $ExternalAccessImapAlterPort
1496: * @param boolean $ExternalAccessImapUseSsl
1497: * @param string $ExternalAccessPop3Server
1498: * @param int $ExternalAccessPop3Port
1499: * @param int $ExternalAccessPop3AlterPort
1500: * @param boolean $ExternalAccessPop3UseSsl
1501: * @param string $ExternalAccessSmtpServer
1502: * @param int $ExternalAccessSmtpPort
1503: * @param int $ExternalAccessSmtpAlterPort
1504: * @param boolean $ExternalAccessSmtpUseSsl
1505: * @param boolean $OAuthEnable
1506: * @param string $OAuthName
1507: * @param string $OAuthType
1508: * @param string $OAuthIconUrl
1509: * @return int|boolean
1510: */
1511: public function CreateServer(
1512: $Name,
1513: $IncomingServer,
1514: $IncomingPort,
1515: $IncomingUseSsl,
1516: $OutgoingServer,
1517: $OutgoingPort,
1518: $OutgoingUseSsl,
1519: $SmtpAuthType,
1520: $Domains,
1521: $EnableThreading = true,
1522: $EnableSieve = false,
1523: $SievePort = 4190,
1524: $SmtpLogin = '',
1525: $SmtpPassword = '',
1526: $UseFullEmailAddressAsLogin = true,
1527: $TenantId = 0,
1528: $SetExternalAccessServers = false,
1529: $ExternalAccessImapServer = '',
1530: $ExternalAccessImapPort = 143,
1531: $ExternalAccessImapAlterPort = 0,
1532: $ExternalAccessImapUseSsl = false,
1533: $ExternalAccessPop3Server = '',
1534: $ExternalAccessPop3Port = 143,
1535: $ExternalAccessPop3AlterPort = 0,
1536: $ExternalAccessPop3UseSsl = false,
1537: $ExternalAccessSmtpServer = '',
1538: $ExternalAccessSmtpPort = 25,
1539: $ExternalAccessSmtpAlterPort = 0,
1540: $ExternalAccessImapSmtpUseSsl = false,
1541: $OAuthEnable = false,
1542: $OAuthName = '',
1543: $OAuthType = '',
1544: $OAuthIconUrl = ''
1545: ) {
1546: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
1547: if ($oAuthenticatedUser instanceof \Aurora\Modules\Core\Models\User && $oAuthenticatedUser->Role === \Aurora\Modules\Mail\Enums\ServerOwnerType::Tenant) {
1548: if ($TenantId !== $oAuthenticatedUser->IdTenant) {
1549: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::AccessDenied);
1550: }
1551: } else {
1552: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
1553: }
1554:
1555: $sOwnerType = ($TenantId === 0) ? \Aurora\Modules\Mail\Enums\ServerOwnerType::SuperAdmin : \Aurora\Modules\Mail\Enums\ServerOwnerType::Tenant;
1556:
1557: $oServer = new \Aurora\Modules\Mail\Models\Server();
1558: $oServer->OwnerType = $sOwnerType;
1559: $oServer->TenantId = $TenantId;
1560: $oServer->Name = $Name;
1561: $oServer->IncomingServer = $IncomingServer;
1562: $oServer->IncomingPort = $IncomingPort;
1563: $oServer->IncomingUseSsl = $IncomingUseSsl;
1564: $oServer->OutgoingServer = $OutgoingServer;
1565: $oServer->OutgoingPort = $OutgoingPort;
1566: $oServer->OutgoingUseSsl = $OutgoingUseSsl;
1567: $oServer->SmtpAuthType = $SmtpAuthType;
1568: $oServer->SmtpLogin = $SmtpLogin;
1569: $oServer->SmtpPassword = $SmtpPassword;
1570: $oServer->Domains = $this->getServersManager()->trimDomains($Domains);
1571: $oServer->EnableThreading = $EnableThreading;
1572: $oServer->EnableSieve = $EnableSieve;
1573: $oServer->SievePort = $SievePort;
1574: $oServer->UseFullEmailAddressAsLogin = $UseFullEmailAddressAsLogin;
1575: $oServer->SetExternalAccessServers = $SetExternalAccessServers;
1576: if ($oServer->SetExternalAccessServers) {
1577: $oServer->ExternalAccessImapServer = $ExternalAccessImapServer;
1578: $oServer->ExternalAccessImapPort = $ExternalAccessImapPort;
1579: $oServer->ExternalAccessImapAlterPort = $ExternalAccessImapAlterPort;
1580: $oServer->ExternalAccessImapUseSsl = $ExternalAccessImapUseSsl;
1581:
1582: $oServer->ExternalAccessPop3Server = $ExternalAccessPop3Server;
1583: $oServer->ExternalAccessPop3Port = $ExternalAccessPop3Port;
1584: $oServer->ExternalAccessPop3AlterPort = $ExternalAccessPop3AlterPort;
1585: $oServer->ExternalAccessPop3UseSsl = $ExternalAccessPop3UseSsl;
1586:
1587: $oServer->ExternalAccessSmtpServer = $ExternalAccessSmtpServer;
1588: $oServer->ExternalAccessSmtpPort = $ExternalAccessSmtpPort;
1589: $oServer->ExternalAccessSmtpAlterPort = $ExternalAccessSmtpAlterPort;
1590: $oServer->ExternalAccessSmtpUseSsl = $ExternalAccessImapSmtpUseSsl;
1591: }
1592: $oServer->OAuthEnable = $OAuthEnable;
1593: if ($oServer->OAuthEnable) {
1594: $oServer->OAuthName = $OAuthName;
1595: $oServer->OAuthType = $OAuthType;
1596: $oServer->OAuthIconUrl = $OAuthIconUrl;
1597: }
1598:
1599: return $this->getServersManager()->createServer($oServer);
1600: }
1601:
1602: /**
1603: * @api {post} ?/Api/ UpdateServer
1604: * @apiName UpdateServer
1605: * @apiGroup Mail
1606: * @apiDescription Updates mail server with specified identifier.
1607: *
1608: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1609: * @apiHeaderExample {json} Header-Example:
1610: * {
1611: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1612: * }
1613: *
1614: * @apiParam {string=Mail} Module Module name
1615: * @apiParam {string=UpdateServer} Method Method name
1616: * @apiParam {string} Parameters JSON.stringified object<br>
1617: * {<br>
1618: * &emsp; **ServerId** *int* Server identifier.<br>
1619: * &emsp; **Name** *string* New server name.<br>
1620: * &emsp; **IncomingServer** *string* New IMAP server.<br>
1621: * &emsp; **IncomingPort** *int* New port for connection to IMAP server.<br>
1622: * &emsp; **IncomingUseSsl** *boolean* Indicates if it is necessary to use SSL while connecting to IMAP server.<br>
1623: * &emsp; **OutgoingServer** *string* New SMTP server.<br>
1624: * &emsp; **OutgoingPort** *int* New port for connection to SMTP server.<br>
1625: * &emsp; **OutgoingUseSsl** *boolean* Indicates if it is necessary to use SSL while connecting to SMTP server.<br>
1626: * &emsp; **SmtpAuthType** *string* SMTP authentication type: '0' - no authentication, '1' - specified credentials, '2' - user credentials.<br>
1627: * &emsp; **SmtpLogin** *string* (optional)<br>
1628: * &emsp; **SmtpPassword** *string* (optional)<br>
1629: * &emsp; **Domains** *string* New list of domains separated by comma.<br>
1630: * &emsp; **TenantId** *int* If tenant identifier is specified creates mail server belonged to specified tenant.<br>
1631: * }
1632: *
1633: * @apiParamExample {json} Request-Example:
1634: * {
1635: * Module: 'Mail',
1636: * Method: 'UpdateServer',
1637: * Parameters: '{ "Name": "Server name", "IncomingServer": "mail.server", "IncomingPort": 143,
1638: * "IncomingUseSsl": false, "OutgoingServer": "mail.server", "OutgoingPort": 25, "OutgoingUseSsl": false,
1639: * "SmtpAuthType": "0", "Domains": "" }'
1640: * }
1641: *
1642: * @apiSuccess {object[]} Result Array of response objects.
1643: * @apiSuccess {string} Result.Module Module name.
1644: * @apiSuccess {string} Result.Method Method name.
1645: * @apiSuccess {boolean} Result.Result Indicates if server was updated successfully.
1646: * @apiSuccess {int} [Result.ErrorCode] Error code
1647: *
1648: * @apiSuccessExample {json} Success response example:
1649: * {
1650: * Module: 'Mail',
1651: * Method: 'UpdateServer',
1652: * Result: true
1653: * }
1654: *
1655: * @apiSuccessExample {json} Error response example:
1656: * {
1657: * Module: 'Mail',
1658: * Method: 'UpdateServer',
1659: * Result: false,
1660: * ErrorCode: 102
1661: * }
1662: */
1663: /**
1664: * Updates mail server with specified identifier.
1665: * @param int $ServerId Server identifier.
1666: * @param string $Name New server name.
1667: * @param string $IncomingServer New IMAP server.
1668: * @param int $IncomingPort New port for connection to IMAP server.
1669: * @param boolean $IncomingUseSsl Indicates if it is necessary to use SSL while connecting to IMAP server.
1670: * @param string $OutgoingServer New SMTP server.
1671: * @param int $OutgoingPort New port for connection to SMTP server.
1672: * @param boolean $OutgoingUseSsl Indicates if it is necessary to use SSL while connecting to SMTP server.
1673: * @param boolean $SmtpAuthType SMTP authentication type: '0' - no authentication, '1' - specified credentials, '2' - user credentials.
1674: * @param string $Domains New list of domains separated by comma.
1675: * @param boolean $EnableThreading
1676: * @param boolean $EnableSieve
1677: * @param int $SievePort
1678: * @param string $SmtpLogin
1679: * @param string $SmtpPassword
1680: * @param boolean $UseFullEmailAddressAsLogin
1681: * @param int $TenantId If tenant identifier is specified updates mail server belonged to specified tenant.
1682: * @param boolean $SetExternalAccessServers
1683: * @param string $ExternalAccessImapServer
1684: * @param int $ExternalAccessImapPort
1685: * @param int $ExternalAccessImapAlterPort
1686: * @param boolean $ExternalAccessImapUseSsl
1687: * @param string $ExternalAccessPop3Server
1688: * @param int $ExternalAccessPop3Port
1689: * @param int $ExternalAccessPop3AlterPort
1690: * @param boolean $ExternalAccessPop3UseSsl
1691: * @param string $ExternalAccessSmtpServer
1692: * @param int $ExternalAccessSmtpPort
1693: * @param int $ExternalAccessSmtpAlterPort
1694: * @param boolean $ExternalAccessSmtpUseSsl
1695: * @param boolean $OAuthEnable
1696: * @param string $OAuthName
1697: * @param string $OAuthType
1698: * @param string $OAuthIconUrl
1699: * @return boolean
1700: */
1701: public function UpdateServer(
1702: $ServerId,
1703: $Name,
1704: $IncomingServer,
1705: $IncomingPort,
1706: $IncomingUseSsl,
1707: $OutgoingServer,
1708: $OutgoingPort,
1709: $OutgoingUseSsl,
1710: $SmtpAuthType,
1711: $Domains,
1712: $EnableThreading,
1713: $EnableSieve,
1714: $SievePort,
1715: $SmtpLogin = '',
1716: $SmtpPassword = '',
1717: $UseFullEmailAddressAsLogin = true,
1718: $TenantId = 0,
1719: $SetExternalAccessServers = false,
1720: $ExternalAccessImapServer = '',
1721: $ExternalAccessImapPort = 143,
1722: $ExternalAccessImapAlterPort = 0,
1723: $ExternalAccessImapUseSsl = false,
1724: $ExternalAccessPop3Server = '',
1725: $ExternalAccessPop3Port = 143,
1726: $ExternalAccessPop3AlterPort = 0,
1727: $ExternalAccessPop3UseSsl = false,
1728: $ExternalAccessSmtpServer = '',
1729: $ExternalAccessSmtpPort = 25,
1730: $ExternalAccessSmtpAlterPort = 0,
1731: $ExternalAccessSmtpUseSsl = false,
1732: $OAuthEnable = false,
1733: $OAuthName = '',
1734: $OAuthType = '',
1735: $OAuthIconUrl = ''
1736: ) {
1737: $bResult = false;
1738:
1739: $oServer = $this->getServersManager()->getServer($ServerId);
1740:
1741: if ($oServer->OwnerType === \Aurora\Modules\Mail\Enums\ServerOwnerType::SuperAdmin) {
1742: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
1743: } else {
1744: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
1745: }
1746:
1747: if ($oServer && ($oServer->OwnerType === \Aurora\Modules\Mail\Enums\ServerOwnerType::SuperAdmin ||
1748: $oServer->OwnerType === \Aurora\Modules\Mail\Enums\ServerOwnerType::Tenant && $oServer->TenantId === $TenantId)) {
1749: $oServer->Name = $Name;
1750: $oServer->IncomingServer = $IncomingServer;
1751: $oServer->IncomingPort = $IncomingPort;
1752: $oServer->IncomingUseSsl = $IncomingUseSsl;
1753: $oServer->OutgoingServer = $OutgoingServer;
1754: $oServer->OutgoingPort = $OutgoingPort;
1755: $oServer->OutgoingUseSsl = $OutgoingUseSsl;
1756: $oServer->SmtpAuthType = $SmtpAuthType;
1757: $oServer->SmtpLogin = $SmtpLogin;
1758: // Dummy password could be passed to client side by toResponseArray method.
1759: // Password will not be updated it if this value were received from client.
1760: if ($SmtpPassword !== '*****') {
1761: $oServer->SmtpPassword = $SmtpPassword;
1762: }
1763: $oServer->Domains = $this->getServersManager()->trimDomains($Domains);
1764: $oServer->EnableThreading = $EnableThreading;
1765: $oServer->EnableSieve = $EnableSieve;
1766: $oServer->SievePort = $SievePort;
1767: $oServer->UseFullEmailAddressAsLogin = $UseFullEmailAddressAsLogin;
1768: $oServer->SetExternalAccessServers = $SetExternalAccessServers;
1769: if ($oServer->SetExternalAccessServers) {
1770: $oServer->ExternalAccessImapServer = $ExternalAccessImapServer;
1771: $oServer->ExternalAccessImapPort = $ExternalAccessImapPort;
1772: $oServer->ExternalAccessImapAlterPort = $ExternalAccessImapAlterPort;
1773: $oServer->ExternalAccessImapUseSsl = $ExternalAccessImapUseSsl;
1774:
1775: $oServer->ExternalAccessPop3Server = $ExternalAccessPop3Server;
1776: $oServer->ExternalAccessPop3Port = $ExternalAccessPop3Port;
1777: $oServer->ExternalAccessPop3AlterPort = $ExternalAccessPop3AlterPort;
1778: $oServer->ExternalAccessPop3UseSsl = $ExternalAccessPop3UseSsl;
1779:
1780: $oServer->ExternalAccessSmtpServer = $ExternalAccessSmtpServer;
1781: $oServer->ExternalAccessSmtpPort = $ExternalAccessSmtpPort;
1782: $oServer->ExternalAccessSmtpAlterPort = $ExternalAccessSmtpAlterPort;
1783: $oServer->ExternalAccessImapUseSsl = $ExternalAccessImapUseSsl;
1784: $oServer->ExternalAccessSmtpUseSsl = $ExternalAccessSmtpUseSsl;
1785: }
1786: $oServer->OAuthEnable = $OAuthEnable;
1787: if ($oServer->OAuthEnable) {
1788: $oServer->OAuthName = $OAuthName;
1789: $oServer->OAuthType = $OAuthType;
1790: $oServer->OAuthIconUrl = $OAuthIconUrl;
1791: }
1792:
1793: $bResult = $this->getServersManager()->updateServer($oServer);
1794: } else {
1795: $bResult = false;
1796: }
1797:
1798: return $bResult;
1799: }
1800:
1801: /**
1802: * @api {post} ?/Api/ DeleteServer
1803: * @apiName DeleteServer
1804: * @apiGroup Mail
1805: * @apiDescription Deletes mail server.
1806: *
1807: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1808: * @apiHeaderExample {json} Header-Example:
1809: * {
1810: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1811: * }
1812: *
1813: * @apiParam {string=Mail} Module Module name
1814: * @apiParam {string=DeleteServer} Method Method name
1815: * @apiParam {string} Parameters JSON.stringified object<br>
1816: * {<br>
1817: * &emsp; **ServerId** *int* Identifier of server to delete.<br>
1818: * &emsp; **TenantId** *int* (optional) Identifier of tenant that contains mail server.<br>
1819: * }
1820: *
1821: * @apiParamExample {json} Request-Example:
1822: * {
1823: * Module: 'Mail',
1824: * Method: 'DeleteServer',
1825: * Parameters: '{ "ServerId": 10 }'
1826: * }
1827: *
1828: * @apiSuccess {object[]} Result Array of response objects.
1829: * @apiSuccess {string} Result.Module Module name.
1830: * @apiSuccess {string} Result.Method Method name.
1831: * @apiSuccess {boolean} Result.Result Indicates if server was deleted successfully.
1832: * @apiSuccess {int} [Result.ErrorCode] Error code
1833: *
1834: * @apiSuccessExample {json} Success response example:
1835: * {
1836: * Module: 'Mail',
1837: * Method: 'DeleteServer',
1838: * Result: true
1839: * }
1840: *
1841: * @apiSuccessExample {json} Error response example:
1842: * {
1843: * Module: 'Mail',
1844: * Method: 'DeleteServer',
1845: * Result: false,
1846: * ErrorCode: 102
1847: * }
1848: */
1849: /**
1850: * Deletes mail server.
1851: * @param int $ServerId Identifier of server to delete.
1852: * @param int $TenantId Identifier of tenant that contains mail server.
1853: * @return boolean
1854: */
1855: public function DeleteServer($ServerId, $TenantId = 0)
1856: {
1857: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
1858: if ($oAuthenticatedUser instanceof \Aurora\Modules\Core\Models\User && $oAuthenticatedUser->Role === \Aurora\Modules\Mail\Enums\ServerOwnerType::Tenant) {
1859: if ($TenantId !== $oAuthenticatedUser->IdTenant) {
1860: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::AccessDenied);
1861: }
1862: } else {
1863: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
1864: }
1865:
1866: $mPrimaryAccounts = $this->getAccountsManager()->getAccounts(['ServerId' => $ServerId, 'UseToAuthorize' => true]);
1867: if ($mPrimaryAccounts) {
1868: foreach ($mPrimaryAccounts as $oAccount) {
1869: \Aurora\Modules\Core\Module::Decorator()->DeleteUser($oAccount->IdUser);
1870: }
1871: }
1872:
1873: $mSecondaryAccounts = $this->getAccountsManager()->getAccounts(['ServerId' => $ServerId, 'UseToAuthorize' => false]);
1874: if ($mSecondaryAccounts) {
1875: foreach ($mSecondaryAccounts as $oAccount) {
1876: self::Decorator()->DeleteAccount($oAccount->Id);
1877: }
1878: }
1879:
1880: return $this->getServersManager()->deleteServer($ServerId, $TenantId);
1881: }
1882:
1883: /**
1884: * @api {post} ?/Api/ GetFolders
1885: * @apiName GetFolders
1886: * @apiGroup Mail
1887: * @apiDescription Obtains list of folders for specified account.
1888: *
1889: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1890: * @apiHeaderExample {json} Header-Example:
1891: * {
1892: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1893: * }
1894: *
1895: * @apiParam {string=Mail} Module Module name
1896: * @apiParam {string=GetFolders} Method Method name
1897: * @apiParam {string} Parameters JSON.stringified object<br>
1898: * {<br>
1899: * &emsp; **AccountId** *int* Identifier of mail account that contains folders to obtain.<br>
1900: * }
1901: *
1902: * @apiParamExample {json} Request-Example:
1903: * {
1904: * Module: 'Mail',
1905: * Method: 'GetFolders',
1906: * Parameters: '{ "AccountId": 12 }'
1907: * }
1908: *
1909: * @apiSuccess {object[]} Result Array of response objects.
1910: * @apiSuccess {string} Result.Module Module name.
1911: * @apiSuccess {string} Result.Method Method name.
1912: * @apiSuccess {mixed} Result.Result Folder list data in case of success, otherwise **false**.
1913: * @apiSuccess {object[]} Result.Result.Folders List of folders.
1914: * @apiSuccess {int} Result.Result.Folders.Count Count of folders.
1915: * @apiSuccess {object[]} Result.Result.Folders.Collection Collection of folders.
1916: * @apiSuccess {int} Result.Result.Folders.Collection.Type Type of folder: 1 - Inbox; 2 - Sent; 3 - Drafts; 4 - Spam; 5 - Trash; 10 - other folders.
1917: * @apiSuccess {string} Result.Result.Folders.Collection.Name Name of folder.
1918: * @apiSuccess {string} Result.Result.Folders.Collection.FullName Folder full name.
1919: * @apiSuccess {string} Result.Result.Folders.Collection.FullNameRaw Folder full name.
1920: * @apiSuccess {string} Result.Result.Folders.Collection.FullNameHash Hash of folder full name.
1921: * @apiSuccess {string} Result.Result.Folders.Collection.Delimiter Delimiter that is used in folder full name.
1922: * @apiSuccess {boolean} Result.Result.Folders.Collection.IsSubscribed Indicates if folder is subscribed.
1923: * @apiSuccess {boolean} Result.Result.Folders.Collection.IsSelectable Indicates if folder can be selected.
1924: * @apiSuccess {boolean} Result.Result.Folders.Collection.Exists Indicates if folder exists.
1925: * @apiSuccess {boolean} Result.Result.Folders.Collection.Extended Indicates if folder is extended.
1926: * @apiSuccess {object[]} Result.Result.Folders.Collection.SubFolders List of sub folders.
1927: * @apiSuccess {string} Result.Result.Namespace
1928: * @apiSuccess {int} [Result.ErrorCode] Error code
1929: *
1930: * @apiSuccessExample {json} Success response example:
1931: * {
1932: * Module: 'Mail',
1933: * Method: 'GetFolders',
1934: * Result: { "Folders": {
1935: * "@Count": 5,
1936: * "@Collection": [
1937: * { "Type": 1, "Name": "INBOX", "FullName": "INBOX", "FullNameRaw": "INBOX",
1938: * "FullNameHash": "hash_value", "Delimiter": "/", "IsSubscribed": true,
1939: * "IsSelectable": true, "Exists": true, "Extended": null, "SubFolders": null },
1940: * { "Type": 2, "Name": "Sent", "FullName": "Sent", "FullNameRaw": "Sent",
1941: * "FullNameHash": "hash_value", "Delimiter": "/", "IsSubscribed": true,
1942: * "IsSelectable": true, "Exists": true, "Extended": null, "SubFolders": null },
1943: * ...
1944: * ]}, "Namespace": "" } }
1945: * }
1946: *
1947: * @apiSuccessExample {json} Error response example:
1948: * {
1949: * Module: 'Mail',
1950: * Method: 'GetFolders',
1951: * Result: false,
1952: * ErrorCode: 102
1953: * }
1954: */
1955: /**
1956: * Obtains list of folders for specified account.
1957: * @param int $AccountID Account identifier.
1958: * @return array
1959: */
1960: public function GetFolders($AccountID)
1961: {
1962: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1963:
1964: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
1965:
1966: self::checkAccess($oAccount);
1967:
1968: $oFolderCollection = $this->getMailManager()->getFolders($oAccount);
1969: return array(
1970: 'Folders' => $oFolderCollection,
1971: 'Namespace' => $oFolderCollection->GetNamespace()
1972: );
1973: }
1974:
1975: public function getSortInfo($SortBy, $SortOrder)
1976: {
1977: $aMessagesSortBy = $this->getConfig('MessagesSortBy', false);
1978:
1979: if ($SortOrder === null && $aMessagesSortBy !== false && isset($aMessagesSortBy['Allow']) && (bool) $aMessagesSortBy['Allow'] === true) {
1980: $oSortOrder = new \Aurora\System\Enums\SortOrder();
1981: $aSortOrderMap = $oSortOrder->getMap();
1982: $SortOrder = isset($aMessagesSortBy['SortOrder']) ? $aSortOrderMap[\strtoupper($aMessagesSortBy['SortOrder'])] : '';
1983: }
1984:
1985: if ($SortBy === null) {
1986: if ($aMessagesSortBy !== false && isset($aMessagesSortBy['Allow']) && (bool) $aMessagesSortBy['Allow'] === true) {
1987: $SortBy = isset($aMessagesSortBy['DefaultSortBy']) ? $aMessagesSortBy['DefaultSortBy'] : '';
1988: }
1989: } else {
1990: if ($aMessagesSortBy === false || isset($aMessagesSortBy['Allow']) && (bool) $aMessagesSortBy['Allow'] === false) {
1991: $SortBy = '';
1992: }
1993: }
1994:
1995: if (empty($SortBy)) {
1996: $SortOrder = \Aurora\System\Enums\SortOrder::ASC;
1997: }
1998:
1999: return [$SortBy, $SortOrder];
2000: }
2001:
2002: /**
2003: * @api {post} ?/Api/ GetMessages
2004: * @apiName GetMessages
2005: * @apiGroup Mail
2006: * @apiDescription Obtains message list for specified account and folder.
2007: *
2008: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
2009: * @apiHeaderExample {json} Header-Example:
2010: * {
2011: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
2012: * }
2013: *
2014: * @apiParam {string=Mail} Module Module name
2015: * @apiParam {string=GetMessages} Method Method name
2016: * @apiParam {string} Parameters JSON.stringified object<br>
2017: * {<br>
2018: * &emsp; **AccountID** *int* Account identifier.<br>
2019: * &emsp; **Folder** *string* Folder full name.<br>
2020: * &emsp; **Offset** *int* Says to skip that many messages before beginning to return them.<br>
2021: * &emsp; **Limit** *int* Limit says to return that many messages in the list.<br>
2022: * &emsp; **Search** *string* Search string.<br>
2023: * &emsp; **Filters** *string* List of conditions to obtain messages.<br>
2024: * &emsp; **UseThreading** *int* Indicates if it is necessary to return messages in threads.<br>
2025: * &emsp; **InboxUidnext** *string* (optional) UIDNEXT Inbox last value that is known on client side.<br>
2026: * }
2027: *
2028: * @apiParamExample {json} Request-Example:
2029: * {
2030: * Module: 'Mail',
2031: * Method: 'GetMessages',
2032: * Parameters: '{ "AccountID": 12, "Folder": "Inbox", "Offset": 0, "Limit": 20, "Search": "",
2033: * "Filters": "", "UseThreading": true }'
2034: * }
2035: *
2036: * @apiSuccess {object[]} Result Array of response objects.
2037: * @apiSuccess {string} Result.Module Module name.
2038: * @apiSuccess {string} Result.Method Method name.
2039: * @apiSuccess {mixed} Result.Result Messages data in case of success, otherwise **false**.
2040: * @apiSuccess {int} Result.Result.Count Count of messages.
2041: * @apiSuccess {object[]} Result.Result.Collection List of messages
2042: * @apiSuccess {string} Result.Result.Collection.Folder Full name of folder that contains the message.
2043: * @apiSuccess {int} Result.Result.Collection.Uid Message uid.
2044: * @apiSuccess {string} Result.Result.Collection.Subject Message subject.
2045: * @apiSuccess {string} Result.Result.Collection.MessageId Message string identifier that is retrieved from message headers.
2046: * @apiSuccess {int} Result.Result.Collection.Size Message size.
2047: * @apiSuccess {int} Result.Result.Collection.TextSize Message text size.
2048: * @apiSuccess {int} Result.Result.Collection.InternalTimeStampInUTC Timestamp of message receiving date.
2049: * @apiSuccess {int} Result.Result.Collection.ReceivedOrDateTimeStampInUTC Timestamp of date that is retrieved from message.
2050: * @apiSuccess {int} Result.Result.Collection.TimeStampInUTC InternalTimeStampInUTC or ReceivedOrDateTimeStampInUTC depending on UseDateFromHeaders setting.
2051: * @apiSuccess {object} Result.Result.Collection.From Collection of sender addresses. Usually contains one address.
2052: * @apiSuccess {object} Result.Result.Collection.To Collection of recipient addresses.
2053: * @apiSuccess {object} Result.Result.Collection.Cc Collection of recipient addresses which receive copies of message.
2054: * @apiSuccess {object} Result.Result.Collection.Bcc Collection of recipient addresses which receive hidden copies of message.
2055: * @apiSuccess {object} Result.Result.Collection.ReplyTo Collection of address which is used for message reply.
2056: * @apiSuccess {boolean} Result.Result.Collection.IsSeen Indicates if message is seen.
2057: * @apiSuccess {boolean} Result.Result.Collection.IsFlagged Indicates if message is flagged.
2058: * @apiSuccess {boolean} Result.Result.Collection.IsAnswered Indicates if message is answered.
2059: * @apiSuccess {boolean} Result.Result.Collection.IsForwarded Indicates if message is forwarded.
2060: * @apiSuccess {boolean} Result.Result.Collection.HasAttachments Indicates if message has attachments.
2061: * @apiSuccess {boolean} Result.Result.Collection.HasVcardAttachment Indicates if message has attachment with VCARD.
2062: * @apiSuccess {boolean} Result.Result.Collection.HasIcalAttachment Indicates if message has attachment with ICAL.
2063: * @apiSuccess {int} Result.Result.Collection.Importance Importance value of the message, from 1 (highest) to 5 (lowest).
2064: * @apiSuccess {array} Result.Result.Collection.DraftInfo Contains information about the original message which is replied or forwarded: message type (reply/forward), UID and folder.
2065: * @apiSuccess {int} Result.Result.Collection.Sensitivity If Sensitivity header was set for the message, its value will be returned: 1 for "Confidential", 2 for "Private", 3 for "Personal".
2066: * @apiSuccess {string} Result.Result.Collection.DownloadAsEmlUrl Url for download message as .eml file.
2067: * @apiSuccess {string} Result.Result.Collection.Hash Message hash.
2068: * @apiSuccess {array} Result.Result.Collection.Threads List of uids of messages that are belonged to one thread.
2069: * @apiSuccess {array} Result.Result.Uids List determines order of messages.
2070: * @apiSuccess {string} Result.Result.UidNext Last value of folder UIDNEXT.
2071: * @apiSuccess {string} Result.Result.FolderHash Folder hash is used to determine if there were changes in folder.
2072: * @apiSuccess {int} Result.Result.MessageCount Total count of messages in folder.
2073: * @apiSuccess {int} Result.Result.MessageUnseenCount Count of unread messages in folder.
2074: * @apiSuccess {int} Result.Result.MessageResultCount Count of messages in obtained list.
2075: * @apiSuccess {string} Result.Result.FolderName Full name of folder.
2076: * @apiSuccess {int} Result.Result.Offset Says to skip that many messages before beginning to return them.
2077: * @apiSuccess {int} Result.Result.Limit Limit says to return that many messages in the list.
2078: * @apiSuccess {string} Result.Result.Search Search string.
2079: * @apiSuccess {string} Result.Result.Filters List of conditions to obtain messages.
2080: * @apiSuccess {array} Result.Result.New List of short information about new messages.
2081: * @apiSuccess {int} [Result.ErrorCode] Error code
2082: *
2083: * @apiSuccessExample {json} Success response example:
2084: * {
2085: * Module: 'Mail',
2086: * Method: 'GetMessages',
2087: * Result: { "@Count": 30, "@Collection": [
2088: * { "Folder": "INBOX", "Uid": 1690, "Subject": "subject_value", "MessageId": "id_value",
2089: * "Size": 17381, "TextSize": 117, "InternalTimeStampInUTC": 1493370309,
2090: * "ReceivedOrDateTimeStampInUTC": 1493370308, "TimeStampInUTC": 1493370309,
2091: * "From": { "@Count": 1, "@Collection": [ { "DisplayName": "", "Email": "test@email" } ] },
2092: * "To": { "@Count":1, "@Collection": [ { "DisplayName": "", "Email": "test2@email" } ] },
2093: * "Cc": null, "Bcc": null, "ReplyTo": null, "IsSeen": true, "IsFlagged": false,
2094: * "IsAnswered": false, "IsForwarded": false, "HasAttachments": true,
2095: * "HasVcardAttachment": false, "HasIcalAttachment": false, "Importance": 3,
2096: * "DraftInfo": null, "Sensitivity": 0,
2097: * "DownloadAsEmlUrl": "url_value", "Hash": "hash_value", "Threads": [] },
2098: * ...
2099: * ],
2100: * "Uids": [1690,1689,1667,1666,1651,1649,1648,1647,1646,1639], "UidNext": "1691",
2101: * "FolderHash": "hash_value", "MessageCount": 639, "MessageUnseenCount": 0,
2102: * "MessageResultCount": 602, "FolderName": "INBOX", "Offset": 0, "Limit": 30, "Search": "",
2103: * "Filters": "", "New": [] }
2104: * }
2105: *
2106: * @apiSuccessExample {json} Error response example:
2107: * {
2108: * Module: 'Mail',
2109: * Method: 'GetMessages',
2110: * Result: false,
2111: * ErrorCode: 102
2112: * }
2113: */
2114: /**
2115: * Obtains message list for specified account and folder.
2116: * @param int $AccountID Account identifier.
2117: * @param string $Folder Folder full name.
2118: * @param int $Offset Says to skip that many messages before beginning to return them.
2119: * @param int $Limit Limit says to return that many messages in the list.
2120: * @param string $Search Search string.
2121: * @param string $Filters List of conditions to obtain messages.
2122: * @param int $UseThreading Indicates if it is necessary to return messages in threads.
2123: * @param string $InboxUidnext UIDNEXT Inbox last value that is known on client side.
2124: * @return array
2125: * @throws \Aurora\System\Exceptions\ApiException
2126: */
2127: public function GetMessages($AccountID, $Folder, $Offset = 0, $Limit = 20, $Search = '', $Filters = '', $UseThreading = false, $InboxUidnext = '', $SortBy = null, $SortOrder = null)
2128: {
2129: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2130:
2131: $sSearch = \trim((string) $Search);
2132:
2133: $aFilters = array();
2134: $sFilters = \strtolower(\trim((string) $Filters));
2135: if (0 < \strlen($sFilters)) {
2136: $aFilters = \array_filter(\explode(',', $sFilters), function ($sValue) {
2137: return '' !== trim($sValue);
2138: });
2139: }
2140:
2141: $iOffset = (int) $Offset;
2142: $iLimit = (int) $Limit;
2143:
2144: if (0 === \strlen(trim($Folder)) || 0 > $iOffset || 0 >= $iLimit || 200 < $iLimit) {
2145: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
2146: }
2147:
2148: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
2149:
2150: self::checkAccess($oAccount);
2151:
2152: $aSortInfo = $this->getSortInfo($SortBy, $SortOrder);
2153:
2154: $sSortBy = \strtoupper($aSortInfo[0]);
2155: $sSortOrder = $aSortInfo[1] === \Aurora\System\Enums\SortOrder::DESC ? 'REVERSE' : '';
2156:
2157: return $this->getMailManager()->getMessageList(
2158: $oAccount,
2159: $Folder,
2160: $iOffset,
2161: $iLimit,
2162: $sSearch,
2163: $UseThreading,
2164: $aFilters,
2165: $InboxUidnext,
2166: $sSortBy,
2167: $sSortOrder
2168: );
2169: }
2170:
2171: protected function getFoldersForSearch($oAccount, $Folder, $Search, &$sSearch)
2172: {
2173: $iSearchInFoldersType = SearchInFoldersType::Cur;
2174: if (!empty(trim($Search))) {
2175: $aSearch = explode(' ', $Search);
2176: if (is_array($aSearch) && count($aSearch) > 0) {
2177: $iKey = array_search('folders:sub', $aSearch);
2178: if ($iKey !== false) {
2179: $iSearchInFoldersType = SearchInFoldersType::Sub;
2180: unset($aSearch[$iKey]);
2181: } else {
2182: $iKey = array_search('folders:all', $aSearch);
2183: if ($iKey !== false) {
2184: $iSearchInFoldersType = SearchInFoldersType::All;
2185: unset($aSearch[$iKey]);
2186: }
2187: }
2188: $sSearch = implode(' ', $aSearch);
2189: }
2190: }
2191:
2192: $aFolders = [];
2193: $bCreateUnExistenSystemFolders = $Folder === '';
2194: if ($iSearchInFoldersType === SearchInFoldersType::Cur) {
2195: $oFoldersColl = $this->getMailManager()->getFolders($oAccount, $bCreateUnExistenSystemFolders);
2196: $oFolder = $oFoldersColl->getFolder($Folder);
2197: $aFolders = [$oFolder];
2198: } else {
2199: if ($iSearchInFoldersType === SearchInFoldersType::All) {
2200: $Folder = '';
2201: }
2202: $oFoldersColl = $this->getMailManager()->getFolders($oAccount, $bCreateUnExistenSystemFolders, $Folder);
2203:
2204: $oFoldersColl->foreachWithSubFolders(function ($oFolder) use (&$aFolders) {
2205: if ($oFolder->isSubscribed() && $oFolder->isSelectable()) {
2206: if ($oFolder->getFolderXListType() !== \Aurora\Modules\Mail\Enums\FolderType::All) {
2207: $aFolders[] = $oFolder;
2208: }
2209: }
2210: });
2211: }
2212:
2213: return $aFolders;
2214: }
2215:
2216: public function GetMessagesByFolders($AccountID, $Folder = '', $Offset = 0, $Limit = 20, $Search = '', $Filters = '', $UseThreading = false, $InboxUidnext = '', $SortBy = null, $SortOrder = null)
2217: {
2218: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2219:
2220: $sSearch = \trim((string) $Search);
2221:
2222: $aFilters = [];
2223: $sFilters = \strtolower(\trim((string) $Filters));
2224: if (0 < \strlen($sFilters)) {
2225: $aFilters = \array_filter(\explode(',', $sFilters), function ($sValue) {
2226: return '' !== trim($sValue);
2227: });
2228: }
2229:
2230: $iOffset = (int) $Offset;
2231: $iLimit = (int) $Limit;
2232:
2233: if (0 > $iOffset || 0 >= $iLimit || 200 < $iLimit) {
2234: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
2235: }
2236:
2237: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
2238:
2239: self::checkAccess($oAccount);
2240:
2241: $aSortInfo = $this->getSortInfo($SortBy, $SortOrder);
2242:
2243: $sSortBy = \strtoupper($aSortInfo[0]);
2244: $sSortOrder = $aSortInfo[1] === \Aurora\System\Enums\SortOrder::DESC ? 'REVERSE' : '';
2245:
2246: $oMessageCollectionResult = \Aurora\Modules\Mail\Classes\MessageCollection::createInstance();
2247: $oMessageCollectionResult->FolderName = $Folder;
2248: $oMessageCollectionResult->Limit = $iLimit;
2249: $oMessageCollectionResult->Offset = $iOffset;
2250: $oMessageCollectionResult->Search = $Search;
2251: $oMessageCollectionResult->Filters = implode(',', $aFilters);
2252:
2253: $aFolderUids = [];
2254: $aUids = [];
2255: $iMessagesCount = 0;
2256: $iMessagesResultCount = 0;
2257: $iMessagesUnseenCount = 0;
2258: $aFoldersHash = [];
2259:
2260: $sSortBy = 'ARRIVAL';
2261: $sSortOrder = $SortOrder === \Aurora\System\Enums\SortOrder::DESC ? 'REVERSE' : '';
2262:
2263: $aFolders = $this->getFoldersForSearch($oAccount, $Folder, $Search, $sSearch);
2264: foreach ($aFolders as $oFolder) {
2265: $sFolder = $oFolder->getRawFullName();
2266: $aUnifiedInfo = $this->getMailManager()->getUnifiedMailboxMessagesInfo($oAccount, $sFolder, $sSearch, $aFilters, $UseThreading, $iOffset + $iLimit, $sSortBy, $sSortOrder);
2267: if (is_array($aUnifiedInfo['Uids']) && count($aUnifiedInfo['Uids']) > 0) {
2268: foreach ($aUnifiedInfo['Uids'] as $iKey => $aUid) {
2269: $aUnifiedInfo['Uids'][$iKey]['folder'] = $sFolder;
2270: }
2271: $aUids = array_merge(
2272: $aUids,
2273: $aUnifiedInfo['Uids']
2274: );
2275: }
2276: $iMessagesCount += $aUnifiedInfo['Count'];
2277: $iMessagesResultCount += $aUnifiedInfo['ResultCount'];
2278: $iMessagesUnseenCount += $aUnifiedInfo['UnreadCount'];
2279: $aFoldersHash[] = $sFolder . ':' . $aUnifiedInfo['FolderHash'];
2280: }
2281:
2282: // sort by time
2283: usort($aUids, function ($a, $b) use ($SortOrder) {
2284: if ($SortOrder === \Aurora\System\Enums\SortOrder::DESC) {
2285: return (strtotime($a['internaldate']) < strtotime($b['internaldate'])) ? 1 : -1;
2286: } else {
2287: return (strtotime($a['internaldate']) > strtotime($b['internaldate'])) ? 1 : -1;
2288: }
2289: });
2290: if (count($aUids) >= 0) {
2291: $aUids = array_slice($aUids, $iOffset, $iLimit);
2292: }
2293:
2294: $aAllMessages = [];
2295: $aNextUids = [];
2296: $aFoldersHash = [];
2297:
2298: $aInboxUidsNext = [];
2299: if (!empty($InboxUidnext)) {
2300: $aInboxUids = \explode('.', $InboxUidnext);
2301: foreach ($aInboxUids as $aUid) {
2302: $aUidsNext = \explode(':', $aUid);
2303: if (count($aUidsNext) === 2) {
2304: $aInboxUidsNext[$aUidsNext[0]] = $aUidsNext[1];
2305: }
2306: }
2307: }
2308:
2309: foreach ($aUids as $aUid) {
2310: $aFolderUids[$aUid['folder']][] = $aUid['uid'];
2311: }
2312: foreach ($aFolderUids as $sFolder => $aFldUids) {
2313: $sFolder = (string) $sFolder;
2314: $sInboxUidnext = isset($aInboxUidsNext[$sFolder]) ? $aInboxUidsNext[$sFolder] : '';
2315:
2316: $oMessageCollection = $this->getMailManager()->getMessageListByUids(
2317: $oAccount,
2318: $sFolder,
2319: $aFldUids,
2320: $sInboxUidnext
2321: );
2322:
2323: if ($UseThreading) {
2324: $oMessageCollection->ForeachList(function (/* @var $oMessage \Aurora\Modules\Mail\Classes\Message */ $oMessage) use ($aUids, $sFolder) {
2325: $iUid = $oMessage->getUid();
2326: $aUidInfo = current(array_filter($aUids, function ($aUid) use ($sFolder, $iUid) {
2327: return $aUid['folder'] === $sFolder && $aUid['uid'] == $iUid;
2328: }));
2329: if (isset($aUidInfo['threads']) && is_array($aUidInfo['threads'])) {
2330: $oMessage->setThreads($aUidInfo['threads']);
2331: }
2332: });
2333: }
2334:
2335: foreach ($oMessageCollection->New as $aNew) {
2336: $aNew['Folder'] = $sFolder;
2337: $oMessageCollectionResult->New[] = $aNew;
2338: }
2339:
2340: $aNextUids[] = $sFolder . ':' . $oMessageCollection->UidNext;
2341: $aMessages = $oMessageCollection->GetAsArray();
2342: foreach ($aMessages as $oMessage) {
2343: //TODO Remove because it must be set when Message instance is created
2344: // $oMessage->setAccountId($oAccount->Id);
2345: $oMessage->setUnifiedUid($oAccount->Id . ':' . $sFolder . ':' . $oMessage->getUid());
2346: }
2347: $aAllMessages = array_merge($aAllMessages, $aMessages);
2348: }
2349:
2350: // sort by time
2351: usort($aAllMessages, function ($a, $b) use ($SortOrder) {
2352: if ($SortOrder === \Aurora\System\Enums\SortOrder::DESC) {
2353: return ($a->getReceivedOrDateTimeStamp() < $b->getReceivedOrDateTimeStamp()) ? 1 : -1;
2354: } else {
2355: return ($a->getReceivedOrDateTimeStamp() > $b->getReceivedOrDateTimeStamp()) ? 1 : -1;
2356: }
2357: });
2358:
2359: $oMessageCollectionResult->Uids = array_map(function ($oMessage) {
2360: return $oMessage->getUnifiedUid();
2361: }, $aAllMessages);
2362:
2363: $oMessageCollectionResult->MessageCount = $iMessagesCount;
2364: $oMessageCollectionResult->MessageResultCount = $iMessagesResultCount;
2365: $oMessageCollectionResult->MessageUnseenCount = $iMessagesUnseenCount;
2366: $oMessageCollectionResult->UidNext = implode('.', $aNextUids);
2367: $oMessageCollectionResult->FolderHash = implode('.', $aFoldersHash);
2368: $oMessageCollectionResult->AddArray($aAllMessages);
2369:
2370: return $oMessageCollectionResult;
2371: }
2372:
2373: public function GetUnifiedMailboxMessages($UserId, $Folder = 'INBOX', $Offset = 0, $Limit = 20, $Search = '', $Filters = '', $UseThreading = false, $InboxUidnext = '', $SortOrder = \Aurora\System\Enums\SortOrder::DESC)
2374: {
2375: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2376: self::checkAccess(null, $UserId);
2377: if (!$this->getConfig('AllowUnifiedInbox', false)) {
2378: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::AccessDenied);
2379: }
2380:
2381: $aFilters = array();
2382: $sFilters = \strtolower(\trim((string) $Filters));
2383: if (0 < \strlen($sFilters)) {
2384: $aFilters = \array_filter(\explode(',', $sFilters), function ($sValue) {
2385: return '' !== trim($sValue);
2386: });
2387: }
2388:
2389: $oMessageCollectionResult = \Aurora\Modules\Mail\Classes\MessageCollection::createInstance();
2390: $oMessageCollectionResult->FolderName = $Folder;
2391: $oMessageCollectionResult->Limit = $Limit;
2392: $oMessageCollectionResult->Offset = $Offset;
2393: $oMessageCollectionResult->Search = $Search;
2394: $oMessageCollectionResult->Filters = implode(',', $aFilters);
2395:
2396: $aAccounts = $this->getAccountsManager()->getUserAccounts($UserId);
2397: $aAccountsCache = [];
2398: $aUids = [];
2399: $aAccountUids = [];
2400: $iMessagesCount = 0;
2401: $iMessagesResultCount = 0;
2402: $iMessagesUnseenCount = 0;
2403: $aFoldersHash = [];
2404:
2405: $sSortBy = 'ARRIVAL';
2406: $sSortOrder = $SortOrder === \Aurora\System\Enums\SortOrder::DESC ? 'REVERSE' : '';
2407:
2408: foreach ($aAccounts as $oAccount) {
2409: if ($oAccount->IncludeInUnifiedMailbox) {
2410: $aAccountsCache[$oAccount->Id]['Account'] = $oAccount;
2411: $aAccountUids[$oAccount->Id] = [];
2412: $sSearch = $Search;
2413:
2414: $aFolders = $this->getFoldersForSearch($oAccount, $Folder, $Search, $sSearch);
2415:
2416: $aFolderFullNamesRaw = array_map(function ($oFolder) {
2417: return $oFolder->getRawFullName();
2418: }, $aFolders);
2419:
2420: $aFoldersInfo = $this->getMailManager()->getFolderListInformation($oAccount, $aFolderFullNamesRaw, true);
2421: foreach ($aFolderFullNamesRaw as $sFolder) {
2422: $aUnifiedInfo = $this->getMailManager()->getUnifiedMailboxMessagesInfo(
2423: $oAccount,
2424: $sFolder,
2425: $sSearch,
2426: $aFilters,
2427: $UseThreading,
2428: $Offset + $Limit,
2429: $sSortBy,
2430: $sSortOrder
2431: );
2432: if (is_array($aUnifiedInfo['Uids']) && count($aUnifiedInfo['Uids']) > 0) {
2433: foreach ($aUnifiedInfo['Uids'] as $iKey => $aUid) {
2434: $aUnifiedInfo['Uids'][$iKey]['folder'] = $sFolder;
2435: }
2436: $aUids = array_merge(
2437: $aUids,
2438: $aUnifiedInfo['Uids']
2439: );
2440: }
2441:
2442: $iMessagesCount += (int) $aFoldersInfo[$sFolder][0];
2443: $iMessagesResultCount += $aUnifiedInfo['ResultCount'];
2444: $iMessagesUnseenCount += $aFoldersInfo[$sFolder][1];
2445: $aFoldersHash[] = $aFoldersInfo[$sFolder][3];
2446: }
2447: }
2448: }
2449:
2450: // sort by time
2451: usort($aUids, function ($a, $b) use ($SortOrder) {
2452: if ($SortOrder === \Aurora\System\Enums\SortOrder::DESC) {
2453: return (strtotime($a['internaldate']) < strtotime($b['internaldate'])) ? 1 : -1;
2454: } else {
2455: return (strtotime($a['internaldate']) > strtotime($b['internaldate'])) ? 1 : -1;
2456: }
2457: });
2458: if (count($aUids) >= 0) {
2459: $aUids = array_slice($aUids, $Offset, $Limit);
2460: }
2461:
2462: $aAllMessages = [];
2463: $aNextUids = [];
2464:
2465: $aInboxUidsNext = [];
2466: if (!empty($InboxUidnext)) {
2467: $aInboxUids = \explode('.', $InboxUidnext);
2468: foreach ($aInboxUids as $aUid) {
2469: $aUidsNext = \explode(':', $aUid);
2470: if (count($aUidsNext) === 3) {
2471: $aInboxUidsNext[$aUidsNext[0]][$aUidsNext[1]] = $aUidsNext[2];
2472: }
2473: }
2474: }
2475:
2476: foreach ($aUids as $aUid) {
2477: $aAccountUids[$aUid['accountid']][$aUid['folder']][] = $aUid['uid'];
2478: }
2479: foreach ($aAccountUids as $iAccountId => $aFolders) {
2480: $oAccount = $aAccountsCache[$iAccountId]['Account'];
2481: foreach ($aFolders as $sFolder => $aFolderUids) {
2482: $sInboxUidnext = isset($aInboxUidsNext[$iAccountId][$sFolder]) ? $aInboxUidsNext[$iAccountId][$sFolder] : '';
2483: $oMessageCollection = $this->getMailManager()->getMessageListByUids(
2484: $oAccount,
2485: $sFolder,
2486: $aFolderUids,
2487: $sInboxUidnext
2488: );
2489:
2490: if ($UseThreading) {
2491: $oMessageCollection->ForeachList(function (/* @var $oMessage \Aurora\Modules\Mail\Classes\Message */ $oMessage) use ($aUids, $iAccountId, $sFolder) {
2492: $iUid = $oMessage->getUid();
2493: $aUidInfo = current(array_filter($aUids, function ($aUid) use ($iAccountId, $iUid, $sFolder) {
2494: return $aUid['folder'] === $sFolder && $aUid['accountid'] === $iAccountId && $aUid['uid'] == $iUid;
2495: }));
2496: if (isset($aUidInfo['threads']) && is_array($aUidInfo['threads'])) {
2497: $oMessage->setThreads($aUidInfo['threads']);
2498: }
2499: });
2500: }
2501: $sPrefix = $oAccount->Id . ':' . $sFolder . ':';
2502:
2503: foreach ($oMessageCollection->New as $aNew) {
2504: $aNew['AccountId'] = $oAccount->Id;
2505: $aNew['Folder'] = $sFolder;
2506:
2507: $oMessageCollectionResult->New[] = $aNew;
2508: }
2509:
2510: $aNextUids[] = $sPrefix . $oMessageCollection->UidNext;
2511: $aMessages = $oMessageCollection->GetAsArray();
2512: foreach ($aMessages as $oMessage) {
2513: //TODO Remove because it must be set when Message instance is created
2514: // $oMessage->setAccountId($oAccount->Id);
2515: $oMessage->setUnifiedUid($sPrefix . $oMessage->getUid());
2516: }
2517: $aAllMessages = array_merge($aAllMessages, $aMessages);
2518: }
2519: }
2520:
2521: // sort by time
2522: usort($aAllMessages, function ($a, $b) use ($SortOrder) {
2523: if ($SortOrder === \Aurora\System\Enums\SortOrder::DESC) {
2524: return ($a->getReceivedOrDateTimeStamp() < $b->getReceivedOrDateTimeStamp()) ? 1 : -1;
2525: } else {
2526: return ($a->getReceivedOrDateTimeStamp() > $b->getReceivedOrDateTimeStamp()) ? 1 : -1;
2527: }
2528: });
2529:
2530: $oMessageCollectionResult->Uids = array_map(function ($oMessage) {
2531: return $oMessage->getUnifiedUid();
2532: }, $aAllMessages);
2533:
2534: $oMessageCollectionResult->MessageCount = $iMessagesCount;
2535: $oMessageCollectionResult->MessageResultCount = $iMessagesResultCount;
2536: $oMessageCollectionResult->MessageUnseenCount = $iMessagesUnseenCount;
2537: $oMessageCollectionResult->UidNext = implode('.', $aNextUids);
2538: $oMessageCollectionResult->FolderHash = implode('.', $aFoldersHash);
2539: $oMessageCollectionResult->AddArray($aAllMessages);
2540:
2541: return $oMessageCollectionResult;
2542: }
2543:
2544: public function GetMessagesInfo($AccountID, $Folder, $Search = null, $UseThreading = false, $SortBy = null, $SortOrder = null)
2545: {
2546: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2547:
2548: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
2549:
2550: self::checkAccess($oAccount);
2551:
2552: $aSortInfo = $this->getSortInfo($SortBy, $SortOrder);
2553:
2554: $sSortBy = \strtoupper($aSortInfo[0]);
2555: $sSortOrder = $aSortInfo[1] === \Aurora\System\Enums\SortOrder::DESC ? 'REVERSE' : '';
2556:
2557: return $this->getMailManager()->GetMessagesInfo(
2558: $oAccount,
2559: $Folder,
2560: $Search,
2561: $UseThreading,
2562: $sSortBy,
2563: $sSortOrder
2564: );
2565: }
2566:
2567: public function GetUnifiedRelevantFoldersInformation($AccountsData)
2568: {
2569: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2570: if (!$this->getConfig('AllowUnifiedInbox', false)) {
2571: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::AccessDenied);
2572: }
2573:
2574: if (!\is_array($AccountsData) || 0 === \count($AccountsData)) {
2575: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
2576: }
2577:
2578: $aResult = [];
2579: $iUnifiedCount = 0;
2580: $iUnifiedUnseenCount = 0;
2581: $aUnifiedUidNext = [];
2582: $aUnifiedFolderHash = [];
2583: foreach ($AccountsData as $aAccountData) {
2584: $iAccountId = $aAccountData['AccountID'];
2585: $oAccount = $this->getAccountsManager()->getAccountById($iAccountId);
2586: if ($oAccount instanceof Models\MailAccount) {
2587: self::checkAccess($oAccount);
2588: $aCounts = self::Decorator()->GetRelevantFoldersInformation($iAccountId, $aAccountData['Folders'], $aAccountData['UseListStatusIfPossible']);
2589: $aCounts['AccountId'] = $iAccountId;
2590: $aResult[] = $aCounts;
2591: if (isset($aCounts['Counts']['INBOX']) && $oAccount->IncludeInUnifiedMailbox) {
2592: $iUnifiedCount += $aCounts['Counts']['INBOX'][0];
2593: $iUnifiedUnseenCount += $aCounts['Counts']['INBOX'][1];
2594: $aUnifiedUidNext[] = $iAccountId . ':' . $aCounts['Counts']['INBOX'][2];
2595: $aUnifiedFolderHash[] = $iAccountId . ':' . $aCounts['Counts']['INBOX'][3];
2596: }
2597: }
2598: }
2599:
2600: return [
2601: 'Accounts' => $aResult,
2602: 'Unified' => [$iUnifiedCount, $iUnifiedUnseenCount, implode('.', $aUnifiedUidNext), implode('.', $aUnifiedFolderHash)]
2603: ];
2604: }
2605:
2606: /**
2607: * @api {post} ?/Api/ GetRelevantFoldersInformation
2608: * @apiName GetRelevantFoldersInformation
2609: * @apiGroup Mail
2610: * @apiDescription Obtains relevant information about total and unseen messages count in specified folders.
2611: *
2612: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
2613: * @apiHeaderExample {json} Header-Example:
2614: * {
2615: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
2616: * }
2617: *
2618: * @apiParam {string=Mail} Module Module name
2619: * @apiParam {string=GetRelevantFoldersInformation} Method Method name
2620: * @apiParam {string} Parameters JSON.stringified object<br>
2621: * {<br>
2622: * &emsp; **AccountID** *int* Account identifier.<br>
2623: * &emsp; **Folders** *array* List of folders full names.<br>
2624: * &emsp; **UseListStatusIfPossible** *boolean* Indicates if LIST-STATUS command should be used if it's supported by IMAP server. If LIST-STATUS is used information about all folders will be obtained, and not only about the requested ones.
2625: * }
2626: *
2627: * @apiParamExample {json} Request-Example:
2628: * {
2629: * Module: 'Mail',
2630: * Method: 'GetRelevantFoldersInformation',
2631: * Parameters: '{ "AccountID": 12, "Folders": [ "INBOX", "Spam" ] }'
2632: * }
2633: *
2634: * @apiSuccess {object[]} Result Array of response objects.
2635: * @apiSuccess {string} Result.Module Module name.
2636: * @apiSuccess {string} Result.Method Method name.
2637: * @apiSuccess {mixed} Result.Result Mail account properties in case of success, otherwise **false**.
2638: * @apiSuccess {object[]} Result.Result.Counts List of folders data where key is folder full name and value is array like [message_count, unread_message_count, "next_message_uid", "hash_to_indicate_changes"]
2639: * @apiSuccess {int} [Result.ErrorCode] Error code
2640: *
2641: * @apiSuccessExample {json} Success response example:
2642: * {
2643: * Module: 'Mail',
2644: * Method: 'GetRelevantFoldersInformation',
2645: * Result: { "Counts": { "INBOX": [638, 0, "1690", "97b2a280e7b9f2cbf86857e5cacf63b7"],
2646: * "Spam": [71, 69, "92", "3c9fe98367857e9930c725010e947d88" ] } }
2647: * }
2648: *
2649: * @apiSuccessExample {json} Error response example:
2650: * {
2651: * Module: 'Mail',
2652: * Method: 'GetRelevantFoldersInformation',
2653: * Result: false,
2654: * ErrorCode: 102
2655: * }
2656: */
2657: /**
2658: * Obtains relevant information about total and unseen messages count in specified folders.
2659: * @param int $AccountID Account identifier.
2660: * @param array $Folders List of folders full names.
2661: * @param boolean $UseListStatusIfPossible Indicates if LIST-STATUS command should be used if it's supported by IMAP server.
2662: * @return array
2663: * @throws \Aurora\System\Exceptions\ApiException
2664: * @throws \MailSo\Net\Exceptions\ConnectionException
2665: */
2666: public function GetRelevantFoldersInformation($AccountID, $Folders, $UseListStatusIfPossible)
2667: {
2668: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2669:
2670: if (!\is_array($Folders) || 0 === \count($Folders)) {
2671: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
2672: }
2673:
2674: $aResult = array();
2675:
2676: try {
2677: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
2678:
2679: self::checkAccess($oAccount);
2680:
2681: $aResult = $this->getMailManager()->getFolderListInformation($oAccount, $Folders, $UseListStatusIfPossible);
2682: } catch (\MailSo\Net\Exceptions\ConnectionException $oException) {
2683: throw $oException;
2684: } catch (\MailSo\Imap\Exceptions\LoginException $oException) {
2685: throw $oException;
2686: } catch (\Aurora\Modules\Mail\Exceptions\Exception $oException) {
2687: throw $oException;
2688: } catch (\Exception $oException) {
2689: \Aurora\System\Api::Log((string) $oException);
2690: }
2691:
2692: return array(
2693: 'Counts' => $aResult,
2694: );
2695: }
2696:
2697: /**
2698: * @api {post} ?/Api/ GetQuota
2699: * @apiName GetQuota
2700: * @apiGroup Mail
2701: * @apiDescription Obtains mail account quota.
2702: *
2703: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
2704: * @apiHeaderExample {json} Header-Example:
2705: * {
2706: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
2707: * }
2708: *
2709: * @apiParam {string=Mail} Module Module name
2710: * @apiParam {string=GetQuota} Method Method name
2711: * @apiParam {string} Parameters JSON.stringified object<br>
2712: * {<br>
2713: * &emsp; **AccountID** *int* Account identifier.<br>
2714: * }
2715: *
2716: * @apiParamExample {json} Request-Example:
2717: * {
2718: * Module: 'Mail',
2719: * Method: 'GetQuota',
2720: * Parameters: '{ "AccountID": 12 }'
2721: * }
2722: *
2723: * @apiSuccess {object[]} Result Array of response objects.
2724: * @apiSuccess {string} Result.Module Module name.
2725: * @apiSuccess {string} Result.Method Method name.
2726: * @apiSuccess {mixed} Result.Result Array like [quota_limit, used_space] in case of success, otherwise **false**.
2727: * @apiSuccess {int} [Result.ErrorCode] Error code
2728: *
2729: * @apiSuccessExample {json} Success response example:
2730: * {
2731: * Module: 'Mail',
2732: * Method: 'GetQuota',
2733: * Result: [8976, 10240]
2734: * }
2735: *
2736: * @apiSuccessExample {json} Error response example:
2737: * {
2738: * Module: 'Mail',
2739: * Method: 'GetQuota',
2740: * Result: false,
2741: * ErrorCode: 102
2742: * }
2743: */
2744: /**
2745: * Obtains mail account quota.
2746: * @param int $AccountID Account identifier.
2747: * @return array|boolean
2748: */
2749: public function GetQuota($AccountID)
2750: {
2751: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2752:
2753: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
2754:
2755: self::checkAccess($oAccount);
2756:
2757: $aQuota = $this->getMailManager()->getQuota($oAccount);
2758: $iQuota = (is_array($aQuota) && isset($aQuota[1])) ? $aQuota[1] / 1024 : 0;
2759: $oUser = \Aurora\Modules\Core\Module::Decorator()->GetUserUnchecked($oAccount->IdUser);
2760: $iUserSpaceLimitMb = ($oUser instanceof \Aurora\Modules\Core\Models\User) ? $oUser->{self::GetName() . '::UserSpaceLimitMb'} : 0;
2761: if ($iQuota !== $iUserSpaceLimitMb) {
2762: $this->updateAllocatedTenantSpace($oUser->IdTenant, $iQuota, $iUserSpaceLimitMb);
2763: $oUser->setExtendedProp(self::GetName() . '::UserSpaceLimitMb', $iQuota);
2764: $oUser->save();
2765: }
2766:
2767: return $aQuota; // Can be changed by subscribers
2768: }
2769:
2770: /**
2771: * @api {post} ?/Api/ GetMessagesBodies
2772: * @apiName GetMessagesBodies
2773: * @apiGroup Mail
2774: * @apiDescription Obtains full data of specified messages including plain text, HTML text and attachments.
2775: *
2776: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
2777: * @apiHeaderExample {json} Header-Example:
2778: * {
2779: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
2780: * }
2781: *
2782: * @apiParam {string=Mail} Module Module name
2783: * @apiParam {string=GetMessagesBodies} Method Method name
2784: * @apiParam {string} Parameters JSON.stringified object<br>
2785: * {<br>
2786: * &emsp; **AccountID** *int* Account identifier.<br>
2787: * &emsp; **Folder** *string* Folder full name.<br>
2788: * &emsp; **Uids** *array* List of messages' uids.<br>
2789: * }
2790: *
2791: * @apiParamExample {json} Request-Example:
2792: * {
2793: * Module: 'Mail',
2794: * Method: 'GetMessagesBodies',
2795: * Parameters: '{ "AccountID": 12, "Folder": "INBOX", "Uids": [ "1591", "1589", "1588", "1587", "1586" ] }'
2796: * }
2797: *
2798: * @apiSuccess {object[]} Result Array of response objects.
2799: * @apiSuccess {string} Result.Module Module name.
2800: * @apiSuccess {string} Result.Method Method name.
2801: * @apiSuccess {mixed} Result.Result Array of messages in case of success, otherwise **false**.
2802: * @apiSuccess {string} Result.Result.Folder Full name of folder that contains the message.
2803: * @apiSuccess {int} Result.Result.Uid Message uid.
2804: * @apiSuccess {string} Result.Result.Subject Message subject.
2805: * @apiSuccess {string} Result.Result.MessageId Message string identifier that is retrieved from message headers.
2806: * @apiSuccess {int} Result.Result.Size Message size.
2807: * @apiSuccess {int} Result.Result.TextSize Message text size.
2808: * @apiSuccess {int} Result.Result.InternalTimeStampInUTC Timestamp of message receiving date.
2809: * @apiSuccess {int} Result.Result.ReceivedOrDateTimeStampInUTC Timestamp of date that is retrieved from message.
2810: * @apiSuccess {int} Result.Result.TimeStampInUTC InternalTimeStampInUTC or ReceivedOrDateTimeStampInUTC depending on UseDateFromHeaders setting.
2811: * @apiSuccess {object} Result.Result.From Collection of sender addresses. Usually contains one address.
2812: * @apiSuccess {object} Result.Result.To Collection of recipient addresses.
2813: * @apiSuccess {object} Result.Result.Cc Collection of recipient addresses which receive copies of message.
2814: * @apiSuccess {object} Result.Result.Bcc Collection of recipient addresses which receive hidden copies of message.
2815: * @apiSuccess {object} Result.Result.ReplyTo Collection of address which is used for message reply.
2816: * @apiSuccess {boolean} Result.Result.IsSeen Indicates if message is seen.
2817: * @apiSuccess {boolean} Result.Result.IsFlagged Indicates if message is flagged.
2818: * @apiSuccess {boolean} Result.Result.IsAnswered Indicates if message is answered.
2819: * @apiSuccess {boolean} Result.Result.IsForwarded Indicates if message is forwarded.
2820: * @apiSuccess {boolean} Result.Result.HasAttachments Indicates if message has attachments.
2821: * @apiSuccess {boolean} Result.Result.HasVcardAttachment Indicates if message has attachment with VCARD.
2822: * @apiSuccess {boolean} Result.Result.HasIcalAttachment Indicates if message has attachment with ICAL.
2823: * @apiSuccess {int} Result.Result.Importance Importance value of the message, from 1 (highest) to 5 (lowest).
2824: * @apiSuccess {array} Result.Result.DraftInfo Contains information about the original message which is replied or forwarded: message type (reply/forward), UID and folder.
2825: * @apiSuccess {int} Result.Result.Sensitivity If Sensitivity header was set for the message, its value will be returned: 1 for "Confidential", 2 for "Private", 3 for "Personal".
2826: * @apiSuccess {string} Result.Result.DownloadAsEmlUrl Url for download message as .eml file.
2827: * @apiSuccess {string} Result.Result.Hash Message hash.
2828: * @apiSuccess {string} Result.Result.Headers Block of headers of the message.
2829: * @apiSuccess {string} Result.Result.InReplyTo Value of **In-Reply-To** header which is supplied in replies/forwards and contains Message-ID of the original message. This approach allows for organizing threads.
2830: * @apiSuccess {string} Result.Result.References Content of References header block of the message.
2831: * @apiSuccess {string} Result.Result.ReadingConfirmationAddressee Email address reading confirmation is to be sent to.
2832: * @apiSuccess {string} Result.Result.Html HTML body of the message.
2833: * @apiSuccess {boolean} Result.Result.Truncated Indicates if message body is truncated.
2834: * @apiSuccess {string} Result.Result.Plain Message plaintext body prepared for display.
2835: * @apiSuccess {string} Result.Result.PlainRaw Message plaintext body as is.
2836: * @apiSuccess {boolean} Result.Result.Rtl Indicates if message body contains symbols from one of rtl languages.
2837: * @apiSuccess {array} Result.Result.Extend List of custom content, implemented for use of ICAL/VCARD content.
2838: * @apiSuccess {boolean} Result.Result.Safety Indication of whether the sender is trustworthy so it's safe to display external images.
2839: * @apiSuccess {boolean} Result.Result.HasExternals Indicates if HTML message body contains images with external URLs.
2840: * @apiSuccess {array} Result.Result.FoundedCIDs List of content-IDs used for inline attachments.
2841: * @apiSuccess {array} Result.Result.FoundedContentLocationUrls
2842: * @apiSuccess {array} Result.Result.Attachments Information about attachments of the message.
2843: * @apiSuccess {int} [Result.ErrorCode] Error code
2844: *
2845: * @apiSuccessExample {json} Success response example:
2846: * {
2847: * Module: 'Mail',
2848: * Method: 'GetMessagesBodies',
2849: * Result: [
2850: * { "Folder": "INBOX", "Uid": 1591, "Subject": "test", "MessageId": "string_id", "Size": 2578,
2851: * "TextSize": 243, "InternalTimeStampInUTC": 1490615414, "ReceivedOrDateTimeStampInUTC": 1490615414,
2852: * "TimeStampInUTC": 1490615414, "From": {"@Count": 1, "@Collection": [ { "DisplayName": "",
2853: * "Email": "test@afterlogic.com" } ] }, "To": { "@Count": 1, "@Collection": [ { "DisplayName": "test",
2854: * "Email":"test@afterlogic.com" } ] }, "Cc": null, "Bcc": null, "ReplyTo": null, "IsSeen": true,
2855: * "IsFlagged": false, "IsAnswered": false, "IsForwarded": false, "HasAttachments": false,
2856: * "HasVcardAttachment": false, "HasIcalAttachment": false, "Importance": 3, "DraftInfo": null,
2857: * "Sensitivity": 0, "DownloadAsEmlUrl": "url_value", "Hash": "hash_value",
2858: * "Headers": "headers_value", "InReplyTo": "", "References": "", "ReadingConfirmationAddressee": "",
2859: * "Html": "html_text_of_message", "Truncated": false, "Plain": "", "PlainRaw": "", "Rtl": false,
2860: * "Extend": [], "Safety": false, "HasExternals": false, "FoundedCIDs": [],
2861: * "FoundedContentLocationUrls": [], "Attachments": null },
2862: * ...
2863: * ]
2864: * }
2865: *
2866: * @apiSuccessExample {json} Error response example:
2867: * {
2868: * Module: 'Mail',
2869: * Method: 'GetMessagesBodies',
2870: * Result: false,
2871: * ErrorCode: 102
2872: * }
2873: */
2874: /**
2875: * Obtains full data of specified messages including plain text, HTML text and attachments.
2876: * @param int $AccountID Account identifier.
2877: * @param string $Folder Folder full name.
2878: * @param array $Uids List of messages' uids.
2879: * @return array
2880: * @throws \Aurora\System\Exceptions\ApiException
2881: */
2882: public function GetMessagesBodies($AccountID, $Folder, $Uids, $MessageBodyTruncationThreshold = null)
2883: {
2884: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2885:
2886: if (0 === \strlen(\trim($Folder)) || !\is_array($Uids) || 0 === \count($Uids)) {
2887: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
2888: }
2889:
2890: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
2891: $oImapClient =& $this->getMailManager()->_getImapClient($oAccount);
2892: $oImapClient->FolderExamine($Folder);
2893:
2894: $aBodystructuresFetchResponse = $oImapClient->Fetch(array(
2895: \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE), \implode(',', $Uids), true);
2896: $aBodystructures = [];
2897: foreach ($aBodystructuresFetchResponse as $oBodystructureFetchResponse) {
2898: $aBodystructures[(int) $oBodystructureFetchResponse->GetFetchValue('UID')] = $oBodystructureFetchResponse;
2899: }
2900: unset($aBodystructuresFetchResponse);
2901:
2902: // access will be checked in GetMessage method
2903:
2904: $aList = array();
2905: foreach ($Uids as $iUid) {
2906: if (\is_numeric($iUid)) {
2907: $oBody = isset($aBodystructures[$iUid]) ? $aBodystructures[$iUid] : null;
2908: $oMessage = $this->Decorator()->GetMessage($AccountID, $Folder, (string) $iUid, '', $MessageBodyTruncationThreshold, $oBody);
2909: if ($oMessage instanceof \Aurora\Modules\Mail\Classes\Message) {
2910: $aList[] = $oMessage;
2911: }
2912:
2913: unset($oMessage);
2914: }
2915: }
2916:
2917: return $aList;
2918: }
2919:
2920: /**
2921: * @api {post} ?/Api/ GetMessage
2922: * @apiName GetMessage
2923: * @apiGroup Mail
2924: * @apiDescription Obtains full data of specified message including plain text, HTML text and attachments.
2925: *
2926: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
2927: * @apiHeaderExample {json} Header-Example:
2928: * {
2929: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
2930: * }
2931: *
2932: * @apiParam {string=Mail} Module Module name
2933: * @apiParam {string=GetMessage} Method Method name
2934: * @apiParam {string} Parameters JSON.stringified object<br>
2935: * {<br>
2936: * &emsp; **AccountId** *int* Account identifier.<br>
2937: * &emsp; **Folder** *string* Folder full name.<br>
2938: * &emsp; **Uid** *string* Message uid.<br>
2939: * &emsp; **Rfc822MimeIndex** *string* (optional) If specified obtains message from attachment of another message.<br>
2940: * }
2941: *
2942: * @apiParamExample {json} Request-Example:
2943: * {
2944: * Module: 'Mail',
2945: * Method: 'GetMessage',
2946: * Parameters: '{ "AccountId": 12, "Folder": "Inbox", "Uid": 1232 }'
2947: * }
2948: *
2949: * @apiSuccess {object[]} Result Array of response objects.
2950: * @apiSuccess {string} Result.Module Module name.
2951: * @apiSuccess {string} Result.Method Method name.
2952: * @apiSuccess {mixed} Result.Result Message properties in case of success, otherwise **false**.
2953: * @apiSuccess {string} Result.Result.Folder Full name of folder that contains the message.
2954: * @apiSuccess {int} Result.Result.Uid Message uid.
2955: * @apiSuccess {string} Result.Result.Subject Message subject.
2956: * @apiSuccess {string} Result.Result.MessageId Message string identifier that is retrieved from message headers.
2957: * @apiSuccess {int} Result.Result.Size Message size.
2958: * @apiSuccess {int} Result.Result.TextSize Message text size.
2959: * @apiSuccess {int} Result.Result.InternalTimeStampInUTC Timestamp of message receiving date.
2960: * @apiSuccess {int} Result.Result.ReceivedOrDateTimeStampInUTC Timestamp of date that is retrieved from message.
2961: * @apiSuccess {int} Result.Result.TimeStampInUTC InternalTimeStampInUTC or ReceivedOrDateTimeStampInUTC depending on UseDateFromHeaders setting.
2962: * @apiSuccess {object} Result.Result.From Collection of sender addresses. Usually contains one address.
2963: * @apiSuccess {object} Result.Result.To Collection of recipient addresses.
2964: * @apiSuccess {object} Result.Result.Cc Collection of recipient addresses which receive copies of message.
2965: * @apiSuccess {object} Result.Result.Bcc Collection of recipient addresses which receive hidden copies of message.
2966: * @apiSuccess {object} Result.Result.ReplyTo Collection of address which is used for message reply.
2967: * @apiSuccess {boolean} Result.Result.IsSeen Indicates if message is seen.
2968: * @apiSuccess {boolean} Result.Result.IsFlagged Indicates if message is flagged.
2969: * @apiSuccess {boolean} Result.Result.IsAnswered Indicates if message is answered.
2970: * @apiSuccess {boolean} Result.Result.IsForwarded Indicates if message is forwarded.
2971: * @apiSuccess {boolean} Result.Result.HasAttachments Indicates if message has attachments.
2972: * @apiSuccess {boolean} Result.Result.HasVcardAttachment Indicates if message has attachment with VCARD.
2973: * @apiSuccess {boolean} Result.Result.HasIcalAttachment Indicates if message has attachment with ICAL.
2974: * @apiSuccess {int} Result.Result.Importance Importance value of the message, from 1 (highest) to 5 (lowest).
2975: * @apiSuccess {array} Result.Result.DraftInfo Contains information about the original message which is replied or forwarded: message type (reply/forward), UID and folder.
2976: * @apiSuccess {int} Result.Result.Sensitivity If Sensitivity header was set for the message, its value will be returned: 1 for "Confidential", 2 for "Private", 3 for "Personal".
2977: * @apiSuccess {string} Result.Result.DownloadAsEmlUrl Url for download message as .eml file.
2978: * @apiSuccess {string} Result.Result.Hash Message hash.
2979: * @apiSuccess {string} Result.Result.Headers Block of headers of the message.
2980: * @apiSuccess {string} Result.Result.InReplyTo Value of **In-Reply-To** header which is supplied in replies/forwards and contains Message-ID of the original message. This approach allows for organizing threads.
2981: * @apiSuccess {string} Result.Result.References Content of References header block of the message.
2982: * @apiSuccess {string} Result.Result.ReadingConfirmationAddressee Email address reading confirmation is to be sent to.
2983: * @apiSuccess {string} Result.Result.Html HTML body of the message.
2984: * @apiSuccess {boolean} Result.Result.Truncated Indicates if message body is truncated.
2985: * @apiSuccess {string} Result.Result.Plain Message plaintext body prepared for display.
2986: * @apiSuccess {string} Result.Result.PlainRaw Message plaintext body as is.
2987: * @apiSuccess {boolean} Result.Result.Rtl Indicates if message body contains symbols from one of rtl languages.
2988: * @apiSuccess {array} Result.Result.Extend List of custom content, implemented for use of ICAL/VCARD content.
2989: * @apiSuccess {boolean} Result.Result.Safety Indication of whether the sender is trustworthy so it's safe to display external images.
2990: * @apiSuccess {boolean} Result.Result.HasExternals Indicates if HTML message body contains images with external URLs.
2991: * @apiSuccess {array} Result.Result.FoundedCIDs List of content-IDs used for inline attachments.
2992: * @apiSuccess {array} Result.Result.FoundedContentLocationUrls
2993: * @apiSuccess {array} Result.Result.Attachments Information about attachments of the message.
2994: * @apiSuccess {int} [Result.ErrorCode] Error code
2995: *
2996: * @apiSuccessExample {json} Success response example:
2997: * {
2998: * Module: 'Mail',
2999: * Method: 'GetMessage',
3000: * Result: { "Folder": "INBOX", "Uid": 1591, "Subject": "test", "MessageId": "string_id", "Size": 2578,
3001: * "TextSize": 243, "InternalTimeStampInUTC": 1490615414, "ReceivedOrDateTimeStampInUTC": 1490615414,
3002: * "TimeStampInUTC": 1490615414, "From": {"@Count": 1, "@Collection": [ { "DisplayName": "",
3003: * "Email": "test@afterlogic.com" } ] }, "To": { "@Count": 1, "@Collection": [ { "DisplayName": "test",
3004: * "Email":"test@afterlogic.com" } ] }, "Cc": null, "Bcc": null, "ReplyTo": null, "IsSeen": true,
3005: * "IsFlagged": false, "IsAnswered": false, "IsForwarded": false, "HasAttachments": false,
3006: * "HasVcardAttachment": false, "HasIcalAttachment": false, "Importance": 3, "DraftInfo": null,
3007: * "Sensitivity": 0, "DownloadAsEmlUrl": "url_value", "Hash": "hash_value",
3008: * "Headers": "headers_value", "InReplyTo": "", "References": "", "ReadingConfirmationAddressee": "",
3009: * "Html": "html_text_of_message", "Truncated": false, "Plain": "", "PlainRaw": "", "Rtl": false, "Extend": [],
3010: * "Safety": false, "HasExternals": false, "FoundedCIDs": [], "FoundedContentLocationUrls": [], "Attachments": null }
3011: * }
3012: *
3013: * @apiSuccessExample {json} Error response example:
3014: * {
3015: * Module: 'Mail',
3016: * Method: 'GetMessage',
3017: * Result: false,
3018: * ErrorCode: 102
3019: * }
3020: */
3021: /**
3022: * Obtains full data of specified message including plain text, HTML text and attachments.
3023: * @param int $AccountID Account identifier.
3024: * @param string $Folder Folder full name.
3025: * @param string $Uid Message uid.
3026: * @param string $Rfc822MimeIndex If specified obtains message from attachment of another message.
3027: * @return \Aurora\Modules\Mail\Classes\Message
3028: * @throws \Aurora\System\Exceptions\ApiException
3029: * @throws CApiInvalidArgumentException
3030: */
3031: public function GetMessage($AccountID, $Folder, $Uid, $Rfc822MimeIndex = '', $MessageBodyTruncationThreshold = null, $oBody = null)
3032: {
3033: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
3034:
3035: $iUid = 0 < \strlen($Uid) && \is_numeric($Uid) ? (int) $Uid : 0;
3036:
3037: if (0 === \strlen(\trim($Folder)) || 0 >= $iUid) {
3038: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
3039: }
3040:
3041: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
3042:
3043: self::checkAccess($oAccount);
3044:
3045: if (0 === \strlen($Folder) || !\is_numeric($iUid) || 0 >= (int) $iUid) {
3046: throw new InvalidArgumentException();
3047: }
3048:
3049: $oImapClient =& $this->getMailManager()->_getImapClient($oAccount);
3050:
3051: $oImapClient->FolderExamine($Folder);
3052:
3053: $oMessage = false;
3054:
3055: $aTextMimeIndexes = array();
3056:
3057: if (!isset($oBody)) {
3058: $aFetchResponse = $oImapClient->Fetch(array(
3059: \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE), $iUid, true);
3060: $oBodyStructure = (0 < \count($aFetchResponse)) ? $aFetchResponse[0]->GetFetchBodyStructure($Rfc822MimeIndex) : null;
3061: } else {
3062: $oBodyStructure = $oBody->GetFetchBodyStructure($Rfc822MimeIndex);
3063: }
3064:
3065: $aCustomParts = array();
3066: if ($oBodyStructure) {
3067: $aTextParts = $oBodyStructure->SearchHtmlOrPlainParts();
3068: if (\is_array($aTextParts) && 0 < \count($aTextParts)) {
3069: foreach ($aTextParts as $oPart) {
3070: $aTextMimeIndexes[] = array($oPart->PartID(), $oPart->Size());
3071: }
3072: }
3073:
3074: $aParts = $oBodyStructure->GetAllParts();
3075:
3076: $this->broadcastEvent(
3077: 'GetBodyStructureParts',
3078: $aParts,
3079: $aCustomParts
3080: );
3081: }
3082:
3083: $bTruncated = false;
3084: $aFetchItems = array(
3085: \MailSo\Imap\Enumerations\FetchType::INDEX,
3086: \MailSo\Imap\Enumerations\FetchType::UID,
3087: \MailSo\Imap\Enumerations\FetchType::RFC822_SIZE,
3088: \MailSo\Imap\Enumerations\FetchType::INTERNALDATE,
3089: \MailSo\Imap\Enumerations\FetchType::FLAGS,
3090: 0 < strlen($Rfc822MimeIndex)
3091: ? \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$Rfc822MimeIndex.'.HEADER]'
3092: : \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK
3093: );
3094:
3095: if (0 < \count($aTextMimeIndexes)) {
3096: if (0 < \strlen($Rfc822MimeIndex) && \is_numeric($Rfc822MimeIndex)) {
3097: $sLine = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$aTextMimeIndexes[0][0].'.1]';
3098: if (\is_numeric($MessageBodyTruncationThreshold) && 0 < $MessageBodyTruncationThreshold && $MessageBodyTruncationThreshold < $aTextMimeIndexes[0][1]) {
3099: $sLine .= '<0.'.((int) $MessageBodyTruncationThreshold).'>';
3100: $bTruncated = true;
3101: }
3102:
3103: $aFetchItems[] = $sLine;
3104: } else {
3105: foreach ($aTextMimeIndexes as $aTextMimeIndex) {
3106: $sLine = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$aTextMimeIndex[0].']';
3107: if (\is_numeric($MessageBodyTruncationThreshold) && 0 < $MessageBodyTruncationThreshold && $MessageBodyTruncationThreshold < $aTextMimeIndex[1]) {
3108: $sLine .= '<0.'.((int) $MessageBodyTruncationThreshold).'>';
3109: $bTruncated = true;
3110: }
3111:
3112: $aFetchItems[] = $sLine;
3113: }
3114: }
3115: }
3116:
3117: foreach ($aCustomParts as $oCustomPart) {
3118: $aFetchItems[] = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$oCustomPart->PartID().']';
3119: }
3120:
3121: if (!$oBodyStructure) {
3122: $aFetchItems[] = \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE;
3123: }
3124:
3125: $aFetchResponse = $oImapClient->Fetch($aFetchItems, $iUid, true);
3126: if (0 < \count($aFetchResponse)) {
3127: $oMessage = \Aurora\Modules\Mail\Classes\Message::createInstance($Folder, $aFetchResponse[0], $oBodyStructure, $Rfc822MimeIndex, $bTruncated);
3128: }
3129:
3130: if ($oMessage) {
3131: $oMessage->setAccountId($oAccount->Id);
3132: $sFromEmail = '';
3133: $oFromCollection = $oMessage->getFrom();
3134: if ($oFromCollection && 0 < $oFromCollection->Count()) {
3135: $oFrom =& $oFromCollection->GetByIndex(0);
3136: if ($oFrom) {
3137: $sFromEmail = trim($oFrom->GetEmail());
3138: }
3139: }
3140:
3141: if (0 < \strlen($sFromEmail)) {
3142: $bAlwaysShowImagesInMessage = !!$this->getConfig('AlwaysShowImagesInMessage', false);
3143: $oMessage->setSafety($bAlwaysShowImagesInMessage ? true :
3144: $this->getMailManager()->isSafetySender($oAccount->IdUser, $sFromEmail));
3145: }
3146:
3147: $aData = array();
3148: foreach ($aCustomParts as $oCustomPart) {
3149: $sData = $aFetchResponse[0]->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::BODY.'['.$oCustomPart->PartID().']');
3150: if (!empty($sData)) {
3151: $sData = \MailSo\Base\Utils::DecodeEncodingValue($sData, $oCustomPart->MailEncodingName());
3152: $sData = \MailSo\Base\Utils::ConvertEncoding(
3153: $sData,
3154: \MailSo\Base\Utils::NormalizeCharset($oCustomPart->Charset(), true),
3155: \MailSo\Base\Enumerations\Charset::UTF_8
3156: );
3157: }
3158: $aData[] = array(
3159: 'Data' => $sData,
3160: 'Part' => $oCustomPart
3161: );
3162: }
3163:
3164: $this->broadcastEvent('ExtendMessageData', $aData, $oMessage);
3165: }
3166:
3167: if (!($oMessage instanceof \Aurora\Modules\Mail\Classes\Message)) {
3168: throw new \Aurora\Modules\Mail\Exceptions\Exception(Enums\ErrorCodes::CannotGetMessage);
3169: }
3170:
3171: return $oMessage;
3172: }
3173:
3174: /**
3175: * Unsubscribe the account from the mailing list.
3176: *
3177: * @param $AccountID
3178: * @param $Folder
3179: * @param $Uid
3180: * @return bool
3181: */
3182: public function Unsubscribe($AccountID, $Folder, $Uid)
3183: {
3184: $mResult = false;
3185:
3186: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
3187:
3188: self::checkAccess($oAccount);
3189:
3190: $validate = false;
3191: $this->getMailManager()->directMessageToStream(
3192: $oAccount,
3193: function ($rResource) use (&$validate) {
3194: if (\is_resource($rResource)) {
3195: $rawMessage = stream_get_contents($rResource);
3196:
3197: try {
3198: $dkimValidator = new DKIMValidator($rawMessage);
3199: $validateResult = @$dkimValidator->validate();
3200:
3201: $validateCount = count($validateResult);
3202: $validateSuccessCount = 0;
3203: if ($validateCount > 0) {
3204: foreach ($validateResult as $val) {
3205: if ($val[0]['status'] === 'SUCCESS') {
3206: $validateSuccessCount++;
3207: }
3208: }
3209: }
3210:
3211: $validate = $validateCount === $validateSuccessCount;
3212: } catch (DKIMException $e) {
3213: $validate = false;
3214: }
3215: }
3216: },
3217: $Folder,
3218: $Uid
3219: );
3220:
3221: if ($validate) {
3222: $oMessage = self::Decorator()->GetMessage($AccountID, $Folder, $Uid);
3223: if ($oMessage instanceof Message) {
3224: $aParsedHeaders = $oMessage->parseUnsubscribeHeaders();
3225:
3226: if ($aParsedHeaders['OneClick']) {
3227: if (!empty($aParsedHeaders['Url'])) {
3228: $iCode = 0;
3229: $this->oHttp->SendPostRequest(
3230: $aParsedHeaders['Url'],
3231: ['List-Unsubscribe' => 'One-Click'],
3232: '',
3233: $iCode,
3234: \Aurora\Api::SystemLogger()
3235: );
3236: $mResult = ($iCode == 200);
3237: } elseif (!empty($aParsedHeaders['Email'])) {
3238: $sEmailCheck = str_ireplace('mailto:', '', $aParsedHeaders['Email']);
3239: $aEmailData = explode('?', $sEmailCheck);
3240: $mResult = self::Decorator()->SendMessage(
3241: $AccountID,
3242: null,
3243: null,
3244: 0,
3245: [],
3246: "",
3247: $aEmailData[0],
3248: "",
3249: "",
3250: [],
3251: 'Unsubscribe'
3252: );
3253: }
3254: }
3255: }
3256: }
3257:
3258: return $mResult;
3259: }
3260:
3261: public function GetMessageByMessageID($AccountID, $Folder, $UidFrom, $MessageID)
3262: {
3263: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
3264:
3265: self::checkAccess($oAccount);
3266: $mResult = false;
3267: $iUID = $this->getMailManager()->getMessageUIDByMessageID($oAccount, $Folder, $UidFrom, $MessageID);
3268: if ($iUID !== false) {
3269: $aMessages = $this->GetMessagesBodies($AccountID, $Folder, [$iUID]);
3270: if (is_array($aMessages) && count($aMessages) > 0) {
3271: $mResult = $aMessages[0];
3272: }
3273: }
3274:
3275: return $mResult;
3276: }
3277:
3278: /**
3279: * @api {post} ?/Api/ SetMessagesSeen
3280: * @apiName SetMessagesSeen
3281: * @apiGroup Mail
3282: * @apiDescription Puts on or off seen flag of message.
3283: *
3284: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
3285: * @apiHeaderExample {json} Header-Example:
3286: * {
3287: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
3288: * }
3289: *
3290: * @apiParam {string=Mail} Module Module name
3291: * @apiParam {string=SetMessagesSeen} Method Method name
3292: * @apiParam {string} Parameters JSON.stringified object<br>
3293: * {<br>
3294: * &emsp; **AccountID** *int* Account identifier.<br>
3295: * &emsp; **Folder** *string* Folder full name.<br>
3296: * &emsp; **Uids** *string* List of messages' uids.<br>
3297: * &emsp; **SetAction** *boolean* Indicates if flag should be set or removed.<br>
3298: * }
3299: *
3300: * @apiParamExample {json} Request-Example:
3301: * {
3302: * Module: 'Mail',
3303: * Method: 'SetMessagesSeen',
3304: * Parameters: '{ "AccountID": 12, "Folder": "Inbox", "Uids": "1243,1244,1245", "SetAction": false }'
3305: * }
3306: *
3307: * @apiSuccess {object[]} Result Array of response objects.
3308: * @apiSuccess {string} Result.Module Module name.
3309: * @apiSuccess {string} Result.Method Method name.
3310: * @apiSuccess {boolean} Result.Result Indicates if seen flag was set successfully.
3311: * @apiSuccess {int} [Result.ErrorCode] Error code
3312: *
3313: * @apiSuccessExample {json} Success response example:
3314: * {
3315: * Module: 'Mail',
3316: * Method: 'SetMessagesSeen',
3317: * Result: true
3318: * }
3319: *
3320: * @apiSuccessExample {json} Error response example:
3321: * {
3322: * Module: 'Mail',
3323: * Method: 'SetMessagesSeen',
3324: * Result: false,
3325: * ErrorCode: 102
3326: * }
3327: */
3328: /**
3329: * Puts on or off seen flag of message.
3330: * @param int $AccountID Account identifier.
3331: * @param string $Folder Folder full name.
3332: * @param string $Uids List of messages' uids.
3333: * @param boolean $SetAction Indicates if flag should be set or removed.
3334: * @return boolean
3335: */
3336: public function SetMessagesSeen($AccountID, $Folder, $Uids, $SetAction)
3337: {
3338: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
3339:
3340: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
3341:
3342: self::checkAccess($oAccount);
3343:
3344: return $this->setMessageFlag($AccountID, $Folder, $Uids, $SetAction, \MailSo\Imap\Enumerations\MessageFlag::SEEN);
3345: }
3346:
3347: /**
3348: * @api {post} ?/Api/ SetMessageFlagged
3349: * @apiName SetMessageFlagged
3350: * @apiGroup Mail
3351: * @apiDescription Puts on or off flagged flag of message.
3352: *
3353: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
3354: * @apiHeaderExample {json} Header-Example:
3355: * {
3356: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
3357: * }
3358: *
3359: * @apiParam {string=Mail} Module Module name
3360: * @apiParam {string=SetMessageFlagged} Method Method name
3361: * @apiParam {string} Parameters JSON.stringified object<br>
3362: * {<br>
3363: * &emsp; **AccountID** *int* Account identifier.<br>
3364: * &emsp; **Folder** *string* Folder full name.<br>
3365: * &emsp; **Uids** *string* List of messages' uids.<br>
3366: * &emsp; **SetAction** *boolean* Indicates if flag should be set or removed.<br>
3367: * }
3368: *
3369: * @apiParamExample {json} Request-Example:
3370: * {
3371: * Module: 'Mail',
3372: * Method: 'SetMessageFlagged',
3373: * Parameters: '{ "AccountID": 12, "Folder": "Inbox", "Uids": "1243,1244,1245", "SetAction": false }'
3374: * }
3375: *
3376: * @apiSuccess {object[]} Result Array of response objects.
3377: * @apiSuccess {string} Result.Module Module name.
3378: * @apiSuccess {string} Result.Method Method name.
3379: * @apiSuccess {boolean} Result.Result Indicates if flagged flag was set successfully.
3380: * @apiSuccess {int} [Result.ErrorCode] Error code
3381: *
3382: * @apiSuccessExample {json} Success response example:
3383: * {
3384: * Module: 'Mail',
3385: * Method: 'SetMessageFlagged',
3386: * Result: true
3387: * }
3388: *
3389: * @apiSuccessExample {json} Error response example:
3390: * {
3391: * Module: 'Mail',
3392: * Method: 'SetMessageFlagged',
3393: * Result: false,
3394: * ErrorCode: 102
3395: * }
3396: */
3397: /**
3398: * Puts on or off flagged flag of message.
3399: * @param int $AccountID Account identifier.
3400: * @param string $Folder Folder full name.
3401: * @param string $Uids List of messages' uids.
3402: * @param boolean $SetAction Indicates if flag should be set or removed.
3403: * @return boolean
3404: */
3405: public function SetMessageFlagged($AccountID, $Folder, $Uids, $SetAction)
3406: {
3407: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
3408:
3409: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
3410:
3411: self::checkAccess($oAccount);
3412:
3413: return $this->setMessageFlag($AccountID, $Folder, $Uids, $SetAction, \MailSo\Imap\Enumerations\MessageFlag::FLAGGED);
3414: }
3415:
3416: /**
3417: * @api {post} ?/Api/ SetAllMessagesSeen
3418: * @apiName SetAllMessagesSeen
3419: * @apiGroup Mail
3420: * @apiDescription Puts on seen flag for all messages in folder.
3421: *
3422: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
3423: * @apiHeaderExample {json} Header-Example:
3424: * {
3425: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
3426: * }
3427: *
3428: * @apiParam {string=Mail} Module Module name
3429: * @apiParam {string=SetAllMessagesSeen} Method Method name
3430: * @apiParam {string} Parameters JSON.stringified object<br>
3431: * {<br>
3432: * &emsp; **AccountID** *int* Account identifier.<br>
3433: * &emsp; **Folder** *string* Folder full name.<br>
3434: * }
3435: *
3436: * @apiParamExample {json} Request-Example:
3437: * {
3438: * Module: 'Mail',
3439: * Method: 'SetAllMessagesSeen',
3440: * Parameters: '{ "AccountID": 12, "Folder": "Inbox" }'
3441: * }
3442: *
3443: * @apiSuccess {object[]} Result Array of response objects.
3444: * @apiSuccess {string} Result.Module Module name.
3445: * @apiSuccess {string} Result.Method Method name.
3446: * @apiSuccess {boolean} Result.Result Indicates if seen flag was set successfully.
3447: * @apiSuccess {int} [Result.ErrorCode] Error code
3448: *
3449: * @apiSuccessExample {json} Success response example:
3450: * {
3451: * Module: 'Mail',
3452: * Method: 'SetAllMessagesSeen',
3453: * Result: true
3454: * }
3455: *
3456: * @apiSuccessExample {json} Error response example:
3457: * {
3458: * Module: 'Mail',
3459: * Method: 'SetAllMessagesSeen',
3460: * Result: false,
3461: * ErrorCode: 102
3462: * }
3463: */
3464: /**
3465: * Puts on seen flag for all messages in folder.
3466: * @param int $AccountID Account identifier.
3467: * @param string $Folder Folder full name.
3468: * @return boolean
3469: * @throws \Aurora\System\Exceptions\ApiException
3470: */
3471: public function SetAllMessagesSeen($AccountID, $Folder)
3472: {
3473: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
3474:
3475: if (0 === \strlen(\trim($Folder))) {
3476: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
3477: }
3478:
3479: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
3480:
3481: self::checkAccess($oAccount);
3482:
3483: return $this->getMailManager()->setMessageFlag(
3484: $oAccount,
3485: $Folder,
3486: array(),
3487: \MailSo\Imap\Enumerations\MessageFlag::SEEN,
3488: \Aurora\Modules\Mail\Enums\MessageStoreAction::Add,
3489: true
3490: );
3491: }
3492:
3493: /**
3494: * @api {post} ?/Api/ MoveMessages
3495: * @apiName MoveMessages
3496: * @apiGroup Mail
3497: * @apiDescription Moves messages from one folder to another.
3498: *
3499: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
3500: * @apiHeaderExample {json} Header-Example:
3501: * {
3502: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
3503: * }
3504: *
3505: * @apiParam {string=Mail} Module Module name
3506: * @apiParam {string=MoveMessages} Method Method name
3507: * @apiParam {string} Parameters JSON.stringified object<br>
3508: * {<br>
3509: * &emsp; **AccountID** *int* Account identifier.<br>
3510: * &emsp; **Folder** *string* Full name of the folder messages will be moved from.<br>
3511: * &emsp; **ToFolder** *string* Full name of the folder messages will be moved to.<br>
3512: * &emsp; **Uids** *string* Uids of messages to move.<br>
3513: * }
3514: *
3515: * @apiParamExample {json} Request-Example:
3516: * {
3517: * Module: 'Mail',
3518: * Method: 'MoveMessages',
3519: * Parameters: '{ "AccountID": 12, "Folder": "Inbox", "ToFolder": "Trash", "Uids": "1212,1213,1215" }'
3520: * }
3521: *
3522: * @apiSuccess {object[]} Result Array of response objects.
3523: * @apiSuccess {string} Result.Module Module name.
3524: * @apiSuccess {string} Result.Method Method name.
3525: * @apiSuccess {boolean} Result.Result Indicates if messages were moved successfully.
3526: * @apiSuccess {int} [Result.ErrorCode] Error code
3527: *
3528: * @apiSuccessExample {json} Success response example:
3529: * {
3530: * Module: 'Mail',
3531: * Method: 'MoveMessages',
3532: * Result: true
3533: *
3534: * @apiSuccessExample {json} Error response example:
3535: * {
3536: * Module: 'Mail',
3537: * Method: 'MoveMessages',
3538: * Result: false,
3539: * ErrorCode: 102
3540: * }
3541: */
3542: /**
3543: * Moves messages from one folder to another.
3544: * @param int $AccountID Account identifier.
3545: * @param string $Folder Full name of the folder messages will be moved from.
3546: * @param string $ToFolder Full name of the folder which messages will be moved to.
3547: * @param string $Uids Uids of messages to move.
3548: * @return boolean
3549: * @throws \Aurora\System\Exceptions\ApiException
3550: */
3551: public function CopyMessages($AccountID, $Folder, $ToFolder, $Uids)
3552: {
3553: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
3554:
3555: $aUids = \Aurora\System\Utils::ExplodeIntUids((string) $Uids);
3556:
3557: if (0 === \strlen(\trim($Folder)) || 0 === \strlen(\trim($ToFolder)) || !\is_array($aUids) || 0 === \count($aUids)) {
3558: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
3559: }
3560:
3561: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
3562:
3563: self::checkAccess($oAccount);
3564:
3565: try {
3566: $this->getMailManager()->copyMessage($oAccount, $Folder, $ToFolder, $aUids);
3567: } catch (\MailSo\Imap\Exceptions\NegativeResponseException $oException) {
3568: $oResponse = /* @var $oResponse \MailSo\Imap\Response */ $oException->GetLastResponse();
3569: throw new \Aurora\Modules\Mail\Exceptions\Exception(
3570: Enums\ErrorCodes::CannotMoveMessageQuota,
3571: $oException,
3572: $oResponse instanceof \MailSo\Imap\Response ? $oResponse->Tag.' '.$oResponse->StatusOrIndex.' '.$oResponse->HumanReadable : ''
3573: );
3574: } catch (\Exception $oException) {
3575: throw new \Aurora\Modules\Mail\Exceptions\Exception(
3576: Enums\ErrorCodes::CannotMoveMessage,
3577: $oException,
3578: $oException->getMessage()
3579: );
3580: }
3581:
3582: return true;
3583: }
3584:
3585: /**
3586: * @api {post} ?/Api/ MoveMessages
3587: * @apiName MoveMessages
3588: * @apiGroup Mail
3589: * @apiDescription Moves messages from one folder to another.
3590: *
3591: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
3592: * @apiHeaderExample {json} Header-Example:
3593: * {
3594: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
3595: * }
3596: *
3597: * @apiParam {string=Mail} Module Module name
3598: * @apiParam {string=MoveMessages} Method Method name
3599: * @apiParam {string} Parameters JSON.stringified object<br>
3600: * {<br>
3601: * &emsp; **AccountID** *int* Account identifier.<br>
3602: * &emsp; **Folder** *string* Full name of the folder messages will be moved from.<br>
3603: * &emsp; **ToFolder** *string* Full name of the folder messages will be moved to.<br>
3604: * &emsp; **Uids** *string* Uids of messages to move.<br>
3605: * }
3606: *
3607: * @apiParamExample {json} Request-Example:
3608: * {
3609: * Module: 'Mail',
3610: * Method: 'MoveMessages',
3611: * Parameters: '{ "AccountID": 12, "Folder": "Inbox", "ToFolder": "Trash", "Uids": "1212,1213,1215" }'
3612: * }
3613: *
3614: * @apiSuccess {object[]} Result Array of response objects.
3615: * @apiSuccess {string} Result.Module Module name.
3616: * @apiSuccess {string} Result.Method Method name.
3617: * @apiSuccess {boolean} Result.Result Indicates if messages were moved successfully.
3618: * @apiSuccess {int} [Result.ErrorCode] Error code
3619: *
3620: * @apiSuccessExample {json} Success response example:
3621: * {
3622: * Module: 'Mail',
3623: * Method: 'MoveMessages',
3624: * Result: true
3625: *
3626: * @apiSuccessExample {json} Error response example:
3627: * {
3628: * Module: 'Mail',
3629: * Method: 'MoveMessages',
3630: * Result: false,
3631: * ErrorCode: 102
3632: * }
3633: */
3634: /**
3635: * Moves messages from one folder to another.
3636: * @param int $AccountID Account identifier.
3637: * @param string $Folder Full name of the folder messages will be moved from.
3638: * @param string $ToFolder Full name of the folder which messages will be moved to.
3639: * @param string $Uids Uids of messages to move.
3640: * @return boolean
3641: * @throws \Aurora\System\Exceptions\ApiException
3642: */
3643: public function MoveMessages($AccountID, $Folder, $ToFolder, $Uids)
3644: {
3645: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
3646:
3647: $aUids = \Aurora\System\Utils::ExplodeIntUids((string) $Uids);
3648:
3649: if (0 === \strlen(\trim($Folder)) || 0 === \strlen(\trim($ToFolder)) || !\is_array($aUids) || 0 === \count($aUids)) {
3650: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
3651: }
3652:
3653: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
3654:
3655: self::checkAccess($oAccount);
3656:
3657: try {
3658: $this->getMailManager()->moveMessage($oAccount, $Folder, $ToFolder, $aUids);
3659: } catch (\MailSo\Imap\Exceptions\NegativeResponseException $oException) {
3660: $oResponse = /* @var $oResponse \MailSo\Imap\Response */ $oException->GetLastResponse();
3661: throw new \Aurora\Modules\Mail\Exceptions\Exception(
3662: Enums\ErrorCodes::CannotMoveMessageQuota,
3663: $oException,
3664: $oResponse instanceof \MailSo\Imap\Response ? $oResponse->Tag.' '.$oResponse->StatusOrIndex.' '.$oResponse->HumanReadable : ''
3665: );
3666: } catch (\Exception $oException) {
3667: throw new \Aurora\Modules\Mail\Exceptions\Exception(
3668: Enums\ErrorCodes::CannotMoveMessage,
3669: $oException,
3670: $oException->getMessage()
3671: );
3672: }
3673:
3674: return true;
3675: }
3676:
3677: /**
3678: * @api {post} ?/Api/ DeleteMessages
3679: * @apiName DeleteMessages
3680: * @apiGroup Mail
3681: * @apiDescription Deletes messages from folder.
3682: *
3683: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
3684: * @apiHeaderExample {json} Header-Example:
3685: * {
3686: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
3687: * }
3688: *
3689: * @apiParam {string=Mail} Module Module name
3690: * @apiParam {string=DeleteMessages} Method Method name
3691: * @apiParam {string} Parameters JSON.stringified object<br>
3692: * {<br>
3693: * &emsp; **AccountID** *int* Account identifier.<br>
3694: * &emsp; **Folder** *string* Folder full name.<br>
3695: * &emsp; **Uids** *string* Uids of messages to delete.<br>
3696: * }
3697: *
3698: * @apiParamExample {json} Request-Example:
3699: * {
3700: * Module: 'Mail',
3701: * Method: 'DeleteMessages',
3702: * Parameters: '{ "AccountID": 12, "Folder": "Inbox", "Uids": "1212,1213,1215" }'
3703: * }
3704: *
3705: * @apiSuccess {object[]} Result Array of response objects.
3706: * @apiSuccess {string} Result.Module Module name.
3707: * @apiSuccess {string} Result.Method Method name.
3708: * @apiSuccess {boolean} Result.Result Indicates if messages were deleted successfully.
3709: * @apiSuccess {int} [Result.ErrorCode] Error code
3710: *
3711: * @apiSuccessExample {json} Success response example:
3712: * {
3713: * Module: 'Mail',
3714: * Method: 'DeleteMessages',
3715: * Result: true
3716: * }
3717: *
3718: * @apiSuccessExample {json} Error response example:
3719: * {
3720: * Module: 'Mail',
3721: * Method: 'DeleteMessages',
3722: * Result: false,
3723: * ErrorCode: 102
3724: * }
3725: */
3726: /**
3727: * Deletes messages from folder.
3728: * @param int $AccountID Account identifier.
3729: * @param string $Folder Folder full name.
3730: * @param string $Uids Uids of messages to delete.
3731: * @return boolean
3732: * @throws \Aurora\System\Exceptions\ApiException
3733: */
3734: public function DeleteMessages($AccountID, $Folder, $Uids)
3735: {
3736: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
3737:
3738: $aUids = \Aurora\System\Utils::ExplodeIntUids((string) $Uids);
3739:
3740: if (0 === \strlen(\trim($Folder)) || !\is_array($aUids) || 0 === \count($aUids)) {
3741: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
3742: }
3743:
3744: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
3745:
3746: self::checkAccess($oAccount);
3747:
3748: $this->getMailManager()->deleteMessage($oAccount, $Folder, $aUids);
3749:
3750: return true;
3751: }
3752:
3753: /**
3754: * @api {post} ?/Api/ CreateFolder
3755: * @apiName CreateFolder
3756: * @apiGroup Mail
3757: * @apiDescription Creates folder in mail account.
3758: *
3759: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
3760: * @apiHeaderExample {json} Header-Example:
3761: * {
3762: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
3763: * }
3764: *
3765: * @apiParam {string=Mail} Module Module name
3766: * @apiParam {string=CreateFolder} Method Method name
3767: * @apiParam {string} Parameters JSON.stringified object<br>
3768: * {<br>
3769: * &emsp; **AccountID** *int* Account identifier.<br>
3770: * &emsp; **FolderNameInUtf8** *string* Name of folder to create.<br>
3771: * &emsp; **FolderParentFullNameRaw** *string* Full name of parent folder.<br>
3772: * &emsp; **Delimiter** *string* Delimiter that is used if full folder name.<br>
3773: * }
3774: *
3775: * @apiParamExample {json} Request-Example:
3776: * {
3777: * Module: 'Mail',
3778: * Method: 'CreateFolder',
3779: * Parameters: '{ "AccountID": 12, "FolderNameInUtf8": "new_folder",
3780: * "FolderParentFullNameRaw": "parent_folder", "Delimiter": "/" }'
3781: * }
3782: *
3783: * @apiSuccess {object[]} Result Array of response objects.
3784: * @apiSuccess {string} Result.Module Module name.
3785: * @apiSuccess {string} Result.Method Method name.
3786: * @apiSuccess {boolean} Result.Result Indicates if folder was created successfully.
3787: * @apiSuccess {int} [Result.ErrorCode] Error code
3788: *
3789: * @apiSuccessExample {json} Success response example:
3790: * {
3791: * Module: 'Mail',
3792: * Method: 'CreateFolder',
3793: * Result: true
3794: * }
3795: *
3796: * @apiSuccessExample {json} Error response example:
3797: * {
3798: * Module: 'Mail',
3799: * Method: 'CreateFolder',
3800: * Result: false,
3801: * ErrorCode: 102
3802: * }
3803: */
3804: /**
3805: * Creates folder in mail account.
3806: * @param int $AccountID Account identifier.
3807: * @param string $FolderNameInUtf8 Name of folder to create.
3808: * @param string $FolderParentFullNameRaw Full name of parent folder.
3809: * @param string $Delimiter Delimiter that is used if full folder name.
3810: * @return boolean
3811: * @throws \Aurora\System\Exceptions\ApiException
3812: */
3813: public function CreateFolder($AccountID, $FolderNameInUtf8, $FolderParentFullNameRaw, $Delimiter)
3814: {
3815: $bResult = true;
3816: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
3817:
3818: if (0 === \strlen($FolderNameInUtf8) || 1 !== \strlen($Delimiter)) {
3819: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
3820: }
3821:
3822: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
3823:
3824: self::checkAccess($oAccount);
3825:
3826: try {
3827: $this->getMailManager()->createFolder($oAccount, $FolderNameInUtf8, $Delimiter, $FolderParentFullNameRaw);
3828: } catch (\MailSo\Mail\Exceptions\AlreadyExistsFolder $oException) {
3829: throw new \Aurora\Modules\Mail\Exceptions\Exception(
3830: Enums\ErrorCodes::FolderAlreadyExists,
3831: $oException,
3832: $oException->getMessage()
3833: );
3834: }
3835:
3836: $aFoldersOrderList = $this->getMailManager()->getFoldersOrder($oAccount);
3837: if (\is_array($aFoldersOrderList) && 0 < \count($aFoldersOrderList)) {
3838: $aFoldersOrderListNew = $aFoldersOrderList;
3839:
3840: $sFolderNameInUtf7Imap = \MailSo\Base\Utils::ConvertEncoding(
3841: $FolderNameInUtf8,
3842: \MailSo\Base\Enumerations\Charset::UTF_8,
3843: \MailSo\Base\Enumerations\Charset::UTF_7_IMAP
3844: );
3845:
3846: $sFolderFullNameRaw = (0 < \strlen($FolderParentFullNameRaw) ? $FolderParentFullNameRaw.$Delimiter : '').
3847: $sFolderNameInUtf7Imap;
3848:
3849: $sFolderFullNameUtf8 = \MailSo\Base\Utils::ConvertEncoding(
3850: $sFolderFullNameRaw,
3851: \MailSo\Base\Enumerations\Charset::UTF_7_IMAP,
3852: \MailSo\Base\Enumerations\Charset::UTF_8
3853: );
3854:
3855: $aFoldersOrderListNew[] = $sFolderFullNameRaw;
3856:
3857: $aFoldersOrderListUtf8 = \array_map(function ($sValue) {
3858: return \MailSo\Base\Utils::ConvertEncoding(
3859: $sValue,
3860: \MailSo\Base\Enumerations\Charset::UTF_7_IMAP,
3861: \MailSo\Base\Enumerations\Charset::UTF_8
3862: );
3863: }, $aFoldersOrderListNew);
3864:
3865: \usort($aFoldersOrderListUtf8, 'strnatcasecmp');
3866:
3867: $iKey = \array_search($sFolderFullNameUtf8, $aFoldersOrderListUtf8, true);
3868: if (\is_int($iKey) && 0 < $iKey && isset($aFoldersOrderListUtf8[$iKey - 1])) {
3869: $sUpperName = $aFoldersOrderListUtf8[$iKey - 1];
3870:
3871: $iUpperKey = \array_search(\MailSo\Base\Utils::ConvertEncoding(
3872: $sUpperName,
3873: \MailSo\Base\Enumerations\Charset::UTF_8,
3874: \MailSo\Base\Enumerations\Charset::UTF_7_IMAP
3875: ), $aFoldersOrderList, true);
3876:
3877: if (\is_int($iUpperKey) && isset($aFoldersOrderList[$iUpperKey])) {
3878: \Aurora\System\Api::Log('insert order index:'.$iUpperKey);
3879: \array_splice($aFoldersOrderList, $iUpperKey + 1, 0, $sFolderFullNameRaw);
3880: $this->getMailManager()->updateFoldersOrder($oAccount, $aFoldersOrderList);
3881: }
3882: }
3883: }
3884:
3885: return $bResult;
3886: }
3887:
3888: /**
3889: * @api {post} ?/Api/ RenameFolder
3890: * @apiName RenameFolder
3891: * @apiGroup Mail
3892: * @apiDescription Renames folder.
3893: *
3894: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
3895: * @apiHeaderExample {json} Header-Example:
3896: * {
3897: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
3898: * }
3899: *
3900: * @apiParam {string=Mail} Module Module name
3901: * @apiParam {string=RenameFolder} Method Method name
3902: * @apiParam {string} [Parameters] JSON.stringified object<br>
3903: * {<br>
3904: * &emsp; **AccountID** *int* Account identifier.<br>
3905: * &emsp; **PrevFolderFullNameRaw** *int* Full name of folder to rename.<br>
3906: * &emsp; **NewFolderNameInUtf8** *int* New folder name.<br>
3907: * }
3908: *
3909: * @apiParamExample {json} Request-Example:
3910: * {
3911: * Module: 'Mail',
3912: * Method: 'RenameFolder',
3913: * Parameters: '{ "AccountID": 12, "PrevFolderFullNameRaw": "old_folder_name",
3914: * "NewFolderNameInUtf8": "new_folder_name" }'
3915: * }
3916: *
3917: * @apiSuccess {object[]} Result Array of response objects.
3918: * @apiSuccess {string} Result.Module Module name.
3919: * @apiSuccess {string} Result.Method Method name.
3920: * @apiSuccess {mixed} Result.Result New folder name information in case of success, otherwise **false**.
3921: * @apiSuccess {string} Result.Result.FullName New full name of folder.
3922: * @apiSuccess {string} Result.Result.FullNameHash Hash of new full name of folder.
3923: * @apiSuccess {int} [Result.ErrorCode] Error code
3924: *
3925: * @apiSuccessExample {json} Success response example:
3926: * {
3927: * Module: 'Mail',
3928: * Method: 'RenameFolder',
3929: * Result: { "FullName": "new_folder_name", "FullNameHash": "hash_value" }
3930: * }
3931: *
3932: * @apiSuccessExample {json} Error response example:
3933: * {
3934: * Module: 'Mail',
3935: * Method: 'RenameFolder',
3936: * Result: false,
3937: * ErrorCode: 102
3938: * }
3939: */
3940: /**
3941: * Renames folder.
3942: * @param int $AccountID Account identifier.
3943: * @param string $PrevFolderFullNameRaw Full name of folder to rename.
3944: * @param string $NewFolderNameInUtf8 New folder name.
3945: * @return array | boolean
3946: * @throws \Aurora\System\Exceptions\ApiException
3947: */
3948: public function RenameFolder($AccountID, $PrevFolderFullNameRaw, $NewFolderNameInUtf8, $ChangeParent, $NewParentFolder)
3949: {
3950: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
3951:
3952: if (0 === \strlen($PrevFolderFullNameRaw) || 0 === \strlen($NewFolderNameInUtf8)) {
3953: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
3954: }
3955:
3956: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
3957:
3958: self::checkAccess($oAccount);
3959:
3960: $mResult = $this->getMailManager()->renameFolder($oAccount, $PrevFolderFullNameRaw, $NewFolderNameInUtf8, $ChangeParent, $NewParentFolder);
3961:
3962: return (0 < \strlen($mResult) ? array(
3963: 'FullName' => $mResult,
3964: 'FullNameHash' => \md5($mResult)
3965: ) : false);
3966: }
3967:
3968: /**
3969: * @api {post} ?/Api/ DeleteFolder
3970: * @apiName DeleteFolder
3971: * @apiGroup Mail
3972: * @apiDescription Deletes folder.
3973: *
3974: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
3975: * @apiHeaderExample {json} Header-Example:
3976: * {
3977: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
3978: * }
3979: *
3980: * @apiParam {string=Mail} Module Module name
3981: * @apiParam {string=DeleteFolder} Method Method name
3982: * @apiParam {string} Parameters JSON.stringified object<br>
3983: * {<br>
3984: * &emsp; **AccountID** *int* Account identifier.<br>
3985: * &emsp; **Folder** *string* Full name of folder to delete.<br>
3986: * }
3987: *
3988: * @apiParamExample {json} Request-Example:
3989: * {
3990: * Module: 'Mail',
3991: * Method: 'DeleteFolder',
3992: * Parameters: '{ "AccountID": 12, "Folder": "folder2" }'
3993: * }
3994: *
3995: * @apiSuccess {object[]} Result Array of response objects.
3996: * @apiSuccess {string} Result.Module Module name.
3997: * @apiSuccess {string} Result.Method Method name.
3998: * @apiSuccess {boolean} Result.Result Indicates if folder was deleted successfully.
3999: * @apiSuccess {int} [Result.ErrorCode] Error code
4000: *
4001: * @apiSuccessExample {json} Success response example:
4002: * {
4003: * Module: 'Mail',
4004: * Method: 'DeleteFolder',
4005: * Result: true
4006: * }
4007: *
4008: * @apiSuccessExample {json} Error response example:
4009: * {
4010: * Module: 'Mail',
4011: * Method: 'DeleteFolder',
4012: * Result: false,
4013: * ErrorCode: 102
4014: * }
4015: */
4016: /**
4017: * Deletes folder.
4018: * @param int $AccountID Account identifier.
4019: * @param string $Folder Full name of folder to delete.
4020: * @return boolean
4021: * @throws \Aurora\System\Exceptions\ApiException
4022: */
4023: public function DeleteFolder($AccountID, $Folder)
4024: {
4025: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
4026:
4027: if (0 === \strlen(\trim($Folder))) {
4028: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
4029: }
4030:
4031: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
4032:
4033: self::checkAccess($oAccount);
4034:
4035: $this->getMailManager()->deleteFolder($oAccount, $Folder);
4036:
4037: return true;
4038: }
4039:
4040: /**
4041: * @api {post} ?/Api/ SubscribeFolder
4042: * @apiName SubscribeFolder
4043: * @apiGroup Mail
4044: * @apiDescription Subscribes/unsubscribes folder.
4045: *
4046: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
4047: * @apiHeaderExample {json} Header-Example:
4048: * {
4049: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
4050: * }
4051: *
4052: * @apiParam {string=Mail} Module Module name
4053: * @apiParam {string=SubscribeFolder} Method Method name
4054: * @apiParam {string} Parameters JSON.stringified object<br>
4055: * {<br>
4056: * &emsp; **AccountID** *int* Account identifier.<br>
4057: * &emsp; **Folder** *string* Full name of folder to subscribe/unsubscribe.<br>
4058: * &emsp; **SetAction** *boolean* Indicates if folder should be subscribed or unsubscribed.<br>
4059: * }
4060: *
4061: * @apiParamExample {json} Request-Example:
4062: * {
4063: * Module: 'Mail',
4064: * Method: 'SubscribeFolder',
4065: * Parameters: '{ "AccountID": 12, "Folder": "folder2", "SetAction": true }'
4066: * }
4067: *
4068: * @apiSuccess {object[]} Result Array of response objects.
4069: * @apiSuccess {string} Result.Module Module name.
4070: * @apiSuccess {string} Result.Method Method name.
4071: * @apiSuccess {boolean} Result.Result Indicates if folder was subscribed/unsubscribed successfully.
4072: * @apiSuccess {int} [Result.ErrorCode] Error code
4073: *
4074: * @apiSuccessExample {json} Success response example:
4075: * {
4076: * Module: 'Mail',
4077: * Method: 'SubscribeFolder',
4078: * Result: true
4079: * }
4080: *
4081: * @apiSuccessExample {json} Error response example:
4082: * {
4083: * Module: 'Mail',
4084: * Method: 'SubscribeFolder',
4085: * Result: false,
4086: * ErrorCode: 102
4087: * }
4088: */
4089: /**
4090: * Subscribes/unsubscribes folder.
4091: * @param int $AccountID Account identifier.
4092: * @param string $Folder Full name of folder to subscribe/unsubscribe.
4093: * @param boolean $SetAction Indicates if folder should be subscribed or unsubscribed.
4094: * @return boolean
4095: * @throws \Aurora\System\Exceptions\ApiException
4096: */
4097: public function SubscribeFolder($AccountID, $Folder, $SetAction)
4098: {
4099: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
4100:
4101: if ($this->getConfig('IgnoreImapSubscription', false)) {
4102: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::AccessDenied);
4103: }
4104:
4105: if (0 === \strlen(\trim($Folder))) {
4106: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
4107: }
4108:
4109: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
4110:
4111: self::checkAccess($oAccount);
4112:
4113: $this->getMailManager()->subscribeFolder($oAccount, $Folder, $SetAction);
4114:
4115: return true;
4116: }
4117:
4118: /**
4119: * @api {post} ?/Api/ UpdateFoldersOrder
4120: * @apiName UpdateFoldersOrder
4121: * @apiGroup Mail
4122: * @apiDescription Updates order of folders.
4123: *
4124: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
4125: * @apiHeaderExample {json} Header-Example:
4126: * {
4127: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
4128: * }
4129: *
4130: * @apiParam {string=Mail} Module Module name
4131: * @apiParam {string=UpdateFoldersOrder} Method Method name
4132: * @apiParam {string} Parameters JSON.stringified object<br>
4133: * {<br>
4134: * &emsp; **AccountID** *int* Account identifier.<br>
4135: * &emsp; **FolderList** *array* List of folders with new order.<br>
4136: * }
4137: *
4138: * @apiParamExample {json} Request-Example:
4139: * {
4140: * Module: 'Mail',
4141: * Method: 'UpdateFoldersOrder',
4142: * Parameters: '{ "AccountID": 12, "FolderList": [ "INBOX", "Sent", "Drafts", "Trash", "Spam", "folder1" ] }'
4143: * }
4144: *
4145: * @apiSuccess {object[]} Result Array of response objects.
4146: * @apiSuccess {string} Result.Module Module name.
4147: * @apiSuccess {string} Result.Method Method name.
4148: * @apiSuccess {boolean} Result.Result Indicates if folders' order was changed successfully.
4149: * @apiSuccess {int} [Result.ErrorCode] Error code
4150: *
4151: * @apiSuccessExample {json} Success response example:
4152: * {
4153: * Module: 'Mail',
4154: * Method: 'UpdateFoldersOrder',
4155: * Result: true
4156: * }
4157: *
4158: * @apiSuccessExample {json} Error response example:
4159: * {
4160: * Module: 'Mail',
4161: * Method: 'UpdateFoldersOrder',
4162: * Result: false,
4163: * ErrorCode: 102
4164: * }
4165: */
4166: /**
4167: * Updates order of folders.
4168: * @param int $AccountID Account identifier.
4169: * @param array $FolderList List of folders with new order.
4170: * @return boolean
4171: * @throws \Aurora\System\Exceptions\ApiException
4172: */
4173: public function UpdateFoldersOrder($AccountID, $FolderList)
4174: {
4175: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
4176:
4177: if (!\is_array($FolderList)) {
4178: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
4179: }
4180:
4181: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
4182:
4183: self::checkAccess($oAccount);
4184:
4185: return $this->getMailManager()->updateFoldersOrder($oAccount, $FolderList);
4186: }
4187:
4188: /**
4189: * @api {post} ?/Api/ ClearFolder
4190: * @apiName ClearFolder
4191: * @apiGroup Mail
4192: * @apiDescription Removes all messages from folder. Method is used for Trash and Spam folders.
4193: *
4194: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
4195: * @apiHeaderExample {json} Header-Example:
4196: * {
4197: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
4198: * }
4199: *
4200: * @apiParam {string=Mail} Module Module name
4201: * @apiParam {string=ClearFolder} Method Method name
4202: * @apiParam {string} Parameters JSON.stringified object<br>
4203: * {<br>
4204: * &emsp; **AccountID** *int* Account identifier.<br>
4205: * &emsp; **Folder** *string* Folder full name.<br>
4206: * }
4207: *
4208: * @apiParamExample {json} Request-Example:
4209: * {
4210: * Module: 'Mail',
4211: * Method: 'ClearFolder',
4212: * Parameters: '{ "AccountID": 12, "Folder": "Trash" }'
4213: * }
4214: *
4215: * @apiSuccess {object[]} Result Array of response objects.
4216: * @apiSuccess {string} Result.Module Module name.
4217: * @apiSuccess {string} Result.Method Method name.
4218: * @apiSuccess {boolean} Result.Result Indicates if folder was cleared successfully.
4219: * @apiSuccess {int} [Result.ErrorCode] Error code
4220: *
4221: * @apiSuccessExample {json} Success response example:
4222: * {
4223: * Module: 'Mail',
4224: * Method: 'ClearFolder',
4225: * Result: true
4226: *
4227: * @apiSuccessExample {json} Error response example:
4228: * {
4229: * Module: 'Mail',
4230: * Method: 'ClearFolder',
4231: * Result: false,
4232: * ErrorCode: 102
4233: * }
4234: */
4235: /**
4236: * Removes all messages from folder. Method is used for Trash and Spam folders.
4237: * @param int $AccountID Account identifier.
4238: * @param string $Folder Folder full name.
4239: * @return boolean
4240: * @throws \Aurora\System\Exceptions\ApiException
4241: */
4242: public function ClearFolder($AccountID, $Folder)
4243: {
4244: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
4245:
4246: if (0 === \strlen(\trim($Folder))) {
4247: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
4248: }
4249:
4250: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
4251:
4252: self::checkAccess($oAccount);
4253:
4254: $this->getMailManager()->clearFolder($oAccount, $Folder);
4255:
4256: return true;
4257: }
4258:
4259: /**
4260: * @api {post} ?/Api/ GetMessagesByUids
4261: * @apiName GetMessagesByUids
4262: * @apiGroup Mail
4263: * @apiDescription Obtains message list for specified messages' uids.
4264: *
4265: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
4266: * @apiHeaderExample {json} Header-Example:
4267: * {
4268: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
4269: * }
4270: *
4271: * @apiParam {string=Mail} Module Module name
4272: * @apiParam {string=GetMessagesByUids} Method Method name
4273: * @apiParam {string} Parameters JSON.stringified object<br>
4274: * {<br>
4275: * &emsp; **AccountID** *int* Account identifier.<br>
4276: * &emsp; **Folder** *string* Folder full name.<br>
4277: * &emsp; **Uids** *array* Uids of messages to obtain.<br>
4278: * }
4279: *
4280: * @apiParamExample {json} Request-Example:
4281: * {
4282: * Module: 'Mail',
4283: * Method: 'GetMessagesByUids',
4284: * Parameters: '{ "AccountID": 12, "Folder": "Inbox", "Uids": [ "1221", "1222", "1226" ] }'
4285: * }
4286: *
4287: * @apiSuccess {object[]} Result Array of response objects.
4288: * @apiSuccess {string} Result.Module Module name.
4289: * @apiSuccess {string} Result.Method Method name.
4290: * @apiSuccess {mixed} Result.Result Messages data in case of success, otherwise **false**.
4291: * @apiSuccess {int} Result.Result.Count Count of messages.
4292: * @apiSuccess {object[]} Result.Result.Collection List of messages
4293: * @apiSuccess {string} Result.Result.Collection.Folder Full name of folder that contains the message.
4294: * @apiSuccess {int} Result.Result.Collection.Uid Message uid.
4295: * @apiSuccess {string} Result.Result.Collection.Subject Message subject.
4296: * @apiSuccess {string} Result.Result.Collection.MessageId Message string identifier that is retrieved from message headers.
4297: * @apiSuccess {int} Result.Result.Collection.Size Message size.
4298: * @apiSuccess {int} Result.Result.Collection.TextSize Message text size.
4299: * @apiSuccess {int} Result.Result.Collection.InternalTimeStampInUTC Timestamp of message receiving date.
4300: * @apiSuccess {int} Result.Result.Collection.ReceivedOrDateTimeStampInUTC Timestamp of date that is retrieved from message.
4301: * @apiSuccess {int} Result.Result.Collection.TimeStampInUTC InternalTimeStampInUTC or ReceivedOrDateTimeStampInUTC depending on UseDateFromHeaders setting.
4302: * @apiSuccess {object} Result.Result.Collection.From Collection of sender addresses. Usually contains one address.
4303: * @apiSuccess {object} Result.Result.Collection.To Collection of recipient addresses.
4304: * @apiSuccess {object} Result.Result.Collection.Cc Collection of recipient addresses which receive copies of message.
4305: * @apiSuccess {object} Result.Result.Collection.Bcc Collection of recipient addresses which receive hidden copies of message.
4306: * @apiSuccess {object} Result.Result.Collection.ReplyTo Collection of address which is used for message reply.
4307: * @apiSuccess {boolean} Result.Result.Collection.IsSeen Indicates if message is seen.
4308: * @apiSuccess {boolean} Result.Result.Collection.IsFlagged Indicates if message is flagged.
4309: * @apiSuccess {boolean} Result.Result.Collection.IsAnswered Indicates if message is answered.
4310: * @apiSuccess {boolean} Result.Result.Collection.IsForwarded Indicates if message is forwarded.
4311: * @apiSuccess {boolean} Result.Result.Collection.HasAttachments Indicates if message has attachments.
4312: * @apiSuccess {boolean} Result.Result.Collection.HasVcardAttachment Indicates if message has attachment with VCARD.
4313: * @apiSuccess {boolean} Result.Result.Collection.HasIcalAttachment Indicates if message has attachment with ICAL.
4314: * @apiSuccess {int} Result.Result.Collection.Importance Importance value of the message, from 1 (highest) to 5 (lowest).
4315: * @apiSuccess {array} Result.Result.Collection.DraftInfo Contains information about the original message which is replied or forwarded: message type (reply/forward), UID and folder.
4316: * @apiSuccess {int} Result.Result.Collection.Sensitivity If Sensitivity header was set for the message, its value will be returned: 1 for "Confidential", 2 for "Private", 3 for "Personal".
4317: * @apiSuccess {string} Result.Result.Collection.DownloadAsEmlUrl Url for download message as .eml file.
4318: * @apiSuccess {string} Result.Result.Collection.Hash Message hash.
4319: * @apiSuccess {array} Result.Result.Collection.Threads List of uids of messages that are belonged to one thread.
4320: * @apiSuccess {array} Result.Result.Uids List determines order of messages.
4321: * @apiSuccess {string} Result.Result.UidNext Last value of folder UIDNEXT.
4322: * @apiSuccess {string} Result.Result.FolderHash Folder hash is used to determine if there were changes in folder.
4323: * @apiSuccess {int} Result.Result.MessageCount Total count of messages in folder.
4324: * @apiSuccess {int} Result.Result.MessageUnseenCount Count of unread messages in folder.
4325: * @apiSuccess {int} Result.Result.MessageResultCount Count of messages in obtained list.
4326: * @apiSuccess {string} Result.Result.FolderName Full name of folder.
4327: * @apiSuccess {int} Result.Result.Offset Says to skip that many messages before beginning to return them.
4328: * @apiSuccess {int} Result.Result.Limit Limit says to return that many messages in the list.
4329: * @apiSuccess {string} Result.Result.Search Search string.
4330: * @apiSuccess {string} Result.Result.Filters List of conditions to obtain messages.
4331: * @apiSuccess {array} Result.Result.New List of short information about new messages.
4332: * @apiSuccess {int} [Result.ErrorCode] Error code
4333: *
4334: * @apiSuccessExample {json} Success response example:
4335: * {
4336: * Module: 'Mail',
4337: * Method: 'GetMessagesByUids',
4338: * Result: {
4339: * "@Count": 30,"@Collection": [
4340: * { "Folder": "INBOX", "Uid": 1689, "Subject": "subject_value", "MessageId": "string_id",
4341: * "Size": 2947, "TextSize": 321, "InternalTimeStampInUTC": 1493290584,
4342: * "ReceivedOrDateTimeStampInUTC": 1493290584, "TimeStampInUTC": 1493290584,
4343: * "From": {"@Count": 1, "@Collection": [ { "DisplayName": "","Email": "test@email" } ] },
4344: * "To": {"@Count": 1, "@Collection": [ { "DisplayName": "", "Email": "test2@email" } ] },
4345: * "Cc": null, "Bcc": null,
4346: * "ReplyTo": { "@Count": 1, "@Collection": [ { "DisplayName": "Afterlogic", "Email":"test@email" } ] },
4347: * "IsSeen": true, "IsFlagged": false, "IsAnswered": false, "IsForwarded": false,
4348: * "HasAttachments": false, "HasVcardAttachment": false, "HasIcalAttachment": false, "Importance": 3,
4349: * "DraftInfo": null, "Sensitivity": 0, "DownloadAsEmlUrl": "url_value",
4350: * "Hash": "hash_value", "Threads": [] },
4351: * ... ],
4352: * "Uids": [1689,1667,1666,1651,1649,1648,1647,1646,1639,1638],
4353: * "UidNext": "1690", "FolderHash": "97b2a280e7b9f2cbf86857e5cacf63b7", "MessageCount": 638,
4354: * "MessageUnseenCount": 0, "MessageResultCount": 601, "FolderName": "INBOX", "Offset": 0,
4355: * "Limit": 30, "Search": "", "Filters": "", "New": []
4356: * }
4357: *
4358: * @apiSuccessExample {json} Error response example:
4359: * {
4360: * Module: 'Mail',
4361: * Method: 'GetMessagesByUids',
4362: * Result: false,
4363: * ErrorCode: 102
4364: * }
4365: */
4366: /**
4367: * Obtains message list for specified messages' uids.
4368: * @param int $AccountID Account identifier.
4369: * @param string $Folder Folder full name.
4370: * @param array $Uids Uids of messages to obtain.
4371: * @return array
4372: * @throws \Aurora\System\Exceptions\ApiException
4373: */
4374: public function GetMessagesByUids($AccountID, $Folder, $Uids)
4375: {
4376: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
4377:
4378: if (0 === \strlen(trim($Folder)) || !\is_array($Uids)) {
4379: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
4380: }
4381:
4382: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
4383:
4384: self::checkAccess($oAccount);
4385:
4386: return $this->getMailManager()->getMessageListByUids($oAccount, $Folder, $Uids);
4387: }
4388:
4389: /**
4390: * @api {post} ?/Api/ GetMessagesFlags
4391: * @apiName GetMessagesFlags
4392: * @apiGroup Mail
4393: * @apiDescription Obtains infomation about flagged flags for specified messages.
4394: *
4395: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
4396: * @apiHeaderExample {json} Header-Example:
4397: * {
4398: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
4399: * }
4400: *
4401: * @apiParam {string=Mail} Module Module name
4402: * @apiParam {string=GetMessagesFlags} Method Method name
4403: * @apiParam {string} [Parameters] JSON.stringified object<br>
4404: * {<br>
4405: * &emsp; **AccountID** *int* Account identifier.<br>
4406: * &emsp; **Folder** *string* Folder full name.<br>
4407: * &emsp; **Uids** *array* Uids of messages.<br>
4408: * }
4409: *
4410: * @apiParamExample {json} Request-Example:
4411: * {
4412: * Module: 'Mail',
4413: * Method: 'GetMessagesFlags'
4414: * }
4415: *
4416: * @apiSuccess {object[]} Result Array of response objects.
4417: * @apiSuccess {string} Result.Module Module name.
4418: * @apiSuccess {string} Result.Method Method name.
4419: * @apiSuccess {mixed} Result.Result List of flags for every message uid in case of success, otherwise **false**.
4420: * @apiSuccess {int} [Result.ErrorCode] Error code
4421: *
4422: * @apiSuccessExample {json} Success response example:
4423: * {
4424: * Module: 'Mail',
4425: * Method: 'GetMessagesFlags',
4426: * Result: { "1649": ["\flagged", "\seen"], "1666": ["\flagged", "\seen"] }
4427: * }
4428: *
4429: * @apiSuccessExample {json} Error response example:
4430: * {
4431: * Module: 'Mail',
4432: * Method: 'GetMessagesFlags',
4433: * Result: false,
4434: * ErrorCode: 102
4435: * }
4436: */
4437: /**
4438: * Obtains infomation about flagged flags for specified messages.
4439: * @param int $AccountID Account identifier.
4440: * @param string $Folder Folder full name.
4441: * @param array $Uids Uids of messages.
4442: * @return array
4443: * @throws \Aurora\System\Exceptions\ApiException
4444: */
4445: public function GetMessagesFlags($AccountID, $Folder, $Uids)
4446: {
4447: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
4448:
4449: if (0 === \strlen(\trim($Folder)) || !\is_array($Uids)) {
4450: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
4451: }
4452:
4453: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
4454:
4455: self::checkAccess($oAccount);
4456:
4457: return $this->getMailManager()->getMessagesFlags($oAccount, $Folder, $Uids);
4458: }
4459:
4460: /**
4461: * @api {post} ?/Api/ SaveMessage
4462: * @apiName SaveMessage
4463: * @apiGroup Mail
4464: * @apiDescription Saves message to Drafts folder.
4465: *
4466: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
4467: * @apiHeaderExample {json} Header-Example:
4468: * {
4469: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
4470: * }
4471: *
4472: * @apiParam {string=Mail} Module Module name
4473: * @apiParam {string=SaveMessage} Method Method name
4474: * @apiParam {string} Parameters JSON.stringified object<br>
4475: * {<br>
4476: * &emsp; **AccountID** *int* Account identifier.<br>
4477: * &emsp; **FetcherID** *int* Fetcher identifier.<br>
4478: * &emsp; **AliasID** *int* Alias identifier.<br>
4479: * &emsp; **IdentityID** *int* Identity identifier.<br>
4480: * &emsp; **DraftInfo** *array* Contains information about the original message which is replied or forwarded: message type (reply/forward), UID and folder.<br>
4481: * &emsp; **DraftUid** *string* Uid of message to save in Drafts folder.<br>
4482: * &emsp; **To** *string* Message recipients.<br>
4483: * &emsp; **Cc** *string* Recipients which will get a copy of the message.<br>
4484: * &emsp; **Bcc** *string* Recipients which will get a hidden copy of the message.<br>
4485: * &emsp; **Subject** *string* Subject of the message.<br>
4486: * &emsp; **Text** *string* Text of the message.<br>
4487: * &emsp; **IsHtml** *boolean* Indicates if text of the message is HTML or plain.<br>
4488: * &emsp; **Importance** *int* Importance of the message - LOW = 5, NORMAL = 3, HIGH = 1.<br>
4489: * &emsp; **SendReadingConfirmation** *boolean* Indicates if it is necessary to include header that says.<br>
4490: * &emsp; **Attachments** *array* List of attachments.<br>
4491: * &emsp; **InReplyTo** *string* Value of **In-Reply-To** header which is supplied in replies/forwards and contains Message-ID of the original message. This approach allows for organizing threads.<br>
4492: * &emsp; **References** *string* Content of References header block of the message.<br>
4493: * &emsp; **Sensitivity** *int* Sensitivity header for the message, its value will be returned: 1 for "Confidential", 2 for "Private", 3 for "Personal".<br>
4494: * &emsp; **DraftFolder** *string* Full name of Drafts folder.<br>
4495: * }
4496: *
4497: * @apiParamExample {json} Request-Example:
4498: * {
4499: * Module: 'Mail',
4500: * Method: 'SaveMessage',
4501: * Parameters: '{ "AccountID": 12, "FetcherID": 0, "AliasID": 0, "IdentityID": 14, "DraftInfo": [], "DraftUid": "",
4502: * "To": "test@email", "Cc": "", "Bcc": "", "Subject": "", "Text": "text_value", "IsHtml": true,
4503: * "Importance": 3, "SendReadingConfirmation": false, "Attachments": [], "InReplyTo": "", "References": "",
4504: * "Sensitivity": 0, "DraftFolder": "Drafts" }'
4505: * }
4506: *
4507: * @apiSuccess {object[]} Result Array of response objects.
4508: * @apiSuccess {string} Result.Module Module name.
4509: * @apiSuccess {string} Result.Method Method name.
4510: * @apiSuccess {boolean} Result.Result Indicates if message was saved successfully.
4511: * @apiSuccess {int} [Result.ErrorCode] Error code
4512: *
4513: * @apiSuccessExample {json} Success response example:
4514: * {
4515: * Module: 'Mail',
4516: * Method: 'SaveMessage',
4517: * Result: true
4518: * }
4519: *
4520: * @apiSuccessExample {json} Error response example:
4521: * {
4522: * Module: 'Mail',
4523: * Method: 'SaveMessage',
4524: * Result: false,
4525: * ErrorCode: 102
4526: * }
4527: */
4528: /**
4529: * Saves message to Drafts folder.
4530: * @param int $AccountID Account identifier.
4531: * @param int $Fetcher Fetcher object is filled in by subscription. Webclient sends FetcherID parameter.
4532: * @param int $Alias Alias object is filled in by subscription. Webclient sends AliasID parameter.
4533: * @param int $IdentityID Identity identifier.
4534: * @param array $DraftInfo Contains information about the original message which is replied or forwarded: message type (reply/forward), UID and folder.
4535: * @param string $DraftUid Uid of message to save in Drafts folder.
4536: * @param string $To Message recipients.
4537: * @param string $Cc Recipients which will get a copy of the message.
4538: * @param string $Bcc Recipients which will get a hidden copy of the message.
4539: * @param string $Subject Subject of the message.
4540: * @param string $Text Text of the message.
4541: * @param boolean $IsHtml Indicates if text of the message is HTML or plain.
4542: * @param int $Importance Importance of the message - LOW = 5, NORMAL = 3, HIGH = 1.
4543: * @param boolean $SendReadingConfirmation Indicates if it is necessary to include header that says
4544: * @param array $Attachments List of attachments.
4545: * @param string $InReplyTo Value of **In-Reply-To** header which is supplied in replies/forwards and contains Message-ID of the original message. This approach allows for organizing threads.
4546: * @param string $References Content of References header block of the message.
4547: * @param int $Sensitivity Sensitivity header for the message, its value will be returned: 1 for "Confidential", 2 for "Private", 3 for "Personal".
4548: * @param string $DraftFolder Full name of Drafts folder.
4549: * @return boolean
4550: * @throws \System\Exceptions\AuroraApiException
4551: */
4552: public function SaveMessage(
4553: $AccountID,
4554: $Fetcher = null,
4555: $Alias = null,
4556: $IdentityID = 0,
4557: $DraftInfo = [],
4558: $DraftUid = "",
4559: $To = "",
4560: $Cc = "",
4561: $Bcc = "",
4562: $Subject = "",
4563: $Text = "",
4564: $IsHtml = false,
4565: $Importance = \MailSo\Mime\Enumerations\MessagePriority::NORMAL,
4566: $SendReadingConfirmation = false,
4567: $Attachments = array(),
4568: $InReplyTo = "",
4569: $References = "",
4570: $Sensitivity = \MailSo\Mime\Enumerations\Sensitivity::NOTHING,
4571: $DraftFolder = ""
4572: ) {
4573: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
4574:
4575: $mResult = false;
4576:
4577: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
4578:
4579: self::checkAccess($oAccount);
4580:
4581: if (0 === \strlen($DraftFolder)) {
4582: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
4583: }
4584:
4585: $oIdentity = $IdentityID !== 0 ? $this->getIdentitiesManager()->getIdentity($IdentityID) : null;
4586:
4587: $oMessage = self::Decorator()->BuildMessage(
4588: $oAccount,
4589: $To,
4590: $Cc,
4591: $Bcc,
4592: $Subject,
4593: $IsHtml,
4594: $Text,
4595: $Attachments,
4596: $DraftInfo,
4597: $InReplyTo,
4598: $References,
4599: $Importance,
4600: $Sensitivity,
4601: $SendReadingConfirmation,
4602: $Fetcher,
4603: $Alias,
4604: true,
4605: $oIdentity
4606: );
4607: if ($oMessage) {
4608: try {
4609: $mResult = $this->getMailManager()->saveMessage($oAccount, $oMessage, $DraftFolder, $DraftUid);
4610: } catch (\Aurora\System\Exceptions\ManagerException $oException) {
4611: throw new \Aurora\Modules\Mail\Exceptions\Exception(Enums\ErrorCodes::CannotSaveMessage, $oException, $oException->getMessage());
4612: }
4613: }
4614:
4615: return $mResult;
4616: }
4617:
4618: /**
4619: * @api {post} ?/Api/ SendMessage
4620: * @apiName SendMessage
4621: * @apiGroup Mail
4622: * @apiDescription Sends message.
4623: *
4624: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
4625: * @apiHeaderExample {json} Header-Example:
4626: * {
4627: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
4628: * }
4629: *
4630: * @apiParam {string=Mail} Module Module name
4631: * @apiParam {string=SendMessage} Method Method name
4632: * @apiParam {string} Parameters JSON.stringified object<br>
4633: * {<br>
4634: * &emsp; **AccountID** *int* Account identifier.<br>
4635: * &emsp; **FetcherID** *int* Fetcher identifier.<br>
4636: * &emsp; **AliasID** *int* Alias identifier.<br>
4637: * &emsp; **IdentityID** *int* Identity identifier.<br>
4638: * &emsp; **DraftInfo** *array* Contains information about the original message which is replied or forwarded: message type (reply/forward), UID and folder.<br>
4639: * &emsp; **DraftUid** *string* Uid of message to save in Drafts folder.<br>
4640: * &emsp; **To** *string* Message recipients.<br>
4641: * &emsp; **Cc** *string* Recipients which will get a copy of the message.<br>
4642: * &emsp; **Bcc** *string* Recipients which will get a hidden copy of the message.<br>
4643: * &emsp; **Subject** *string* Subject of the message.<br>
4644: * &emsp; **Text** *string* Text of the message.<br>
4645: * &emsp; **IsHtml** *boolean* Indicates if text of the message is HTML or plain.<br>
4646: * &emsp; **Importance** *int* Importance of the message - LOW = 5, NORMAL = 3, HIGH = 1.<br>
4647: * &emsp; **SendReadingConfirmation** *boolean* Indicates if it is necessary to include header that says.<br>
4648: * &emsp; **Attachments** *array* List of attachments.<br>
4649: * &emsp; **InReplyTo** *string* Value of **In-Reply-To** header which is supplied in replies/forwards and contains Message-ID of the original message. This approach allows for organizing threads.<br>
4650: * &emsp; **References** *string* Content of References header block of the message.<br>
4651: * &emsp; **Sensitivity** *int* Sensitivity header for the message, its value will be returned: 1 for "Confidential", 2 for "Private", 3 for "Personal".<br>
4652: * &emsp; **SentFolder** *string* Full name of Sent folder.<br>
4653: * &emsp; **DraftFolder** *string* Full name of Drafts folder.<br>
4654: * &emsp; **ConfirmFolder** *string* Full name of folder that contains a message that should be marked as confirmed read.<br>
4655: * &emsp; **ConfirmUid** *string* Uid of message that should be marked as confirmed read.<br>
4656: * }
4657: *
4658: * @apiParamExample {json} Request-Example:
4659: * {
4660: * Module: 'Mail',
4661: * Method: 'SendMessage',
4662: * Parameters: '{ "AccountID": 12, "FetcherID": 0, "AliasID": 0, "IdentityID": 14, "DraftInfo": [], "DraftUid": "",
4663: * "To": "test@email", "Cc": "", "Bcc": "", "Subject": "", "Text": "text_value", "IsHtml": true,
4664: * "Importance": 3, "SendReadingConfirmation": false, "Attachments": [], "InReplyTo": "", "References": "",
4665: * "Sensitivity": 0, "SentFolder": "Sent", "DraftFolder": "Drafts", "ConfirmFolder": "", "ConfirmUid": "" }'
4666: * }
4667: *
4668: * @apiSuccess {object[]} Result Array of response objects.
4669: * @apiSuccess {string} Result.Module Module name.
4670: * @apiSuccess {string} Result.Method Method name.
4671: * @apiSuccess {boolean} Result.Result Indicates if message was sent successfully.
4672: * @apiSuccess {int} [Result.ErrorCode] Error code
4673: *
4674: * @apiSuccessExample {json} Success response example:
4675: * {
4676: * Module: 'Mail',
4677: * Method: 'SendMessage',
4678: * Result: true
4679: * }
4680: *
4681: * @apiSuccessExample {json} Error response example:
4682: * {
4683: * Module: 'Mail',
4684: * Method: 'SendMessage',
4685: * Result: false,
4686: * ErrorCode: 102
4687: * }
4688: */
4689: /**
4690: * Sends message.
4691: * @param int $AccountID Account identifier.
4692: * @param int $Fetcher Fetcher object is filled in by subscription. Webclient sends FetcherID parameter.
4693: * @param int $Alias Alias object is filled in by subscription. Webclient sends AliasID parameter.
4694: * @param int $IdentityID Identity identifier.
4695: * @param array $DraftInfo Contains information about the original message which is replied or forwarded: message type (reply/forward), UID and folder.
4696: * @param string $DraftUid Uid of message to save in Drafts folder.
4697: * @param string $To Message recipients.
4698: * @param string $Cc Recipients which will get a copy of the message.
4699: * @param string $Bcc Recipients which will get a hidden copy of the message.
4700: * @param array $Recipients Recipients that will be used to send messages through the SMTP. Use this parameter if you want real recipients to differ from those specified in the message body (To, CC, BCC).
4701: * @param string $Subject Subject of the message.
4702: * @param string $Text Text of the message.
4703: * @param boolean $IsHtml Indicates if text of the message is HTML or plain.
4704: * @param int $Importance Importance of the message - LOW = 5, NORMAL = 3, HIGH = 1.
4705: * @param boolean $SendReadingConfirmation Indicates if it is necessary to include header that says
4706: * @param array $Attachments List of attachments.
4707: * @param string $InReplyTo Value of **In-Reply-To** header which is supplied in replies/forwards and contains Message-ID of the original message. This approach allows for organizing threads.
4708: * @param string $References Content of References header block of the message.
4709: * @param int $Sensitivity Sensitivity header for the message, its value will be returned: 1 for "Confidential", 2 for "Private", 3 for "Personal".
4710: * @param string $SentFolder Full name of Sent folder.
4711: * @param string $DraftFolder Full name of Drafts folder.
4712: * @param string $ConfirmFolder Full name of folder that contains a message that should be marked as confirmed read.
4713: * @param string $ConfirmUid Uid of message that should be marked as confirmed read.
4714: * @param array $CustomHeaders list of custom headers
4715: * @return boolean
4716: * @throws \System\Exceptions\AuroraApiException
4717: */
4718: public function SendMessage(
4719: $AccountID,
4720: $Fetcher = null,
4721: $Alias = null,
4722: $IdentityID = 0,
4723: $DraftInfo = [],
4724: $DraftUid = "",
4725: $To = "",
4726: $Cc = "",
4727: $Bcc = "",
4728: $Recipients = array(),
4729: $Subject = "",
4730: $Text = "",
4731: $IsHtml = false,
4732: $Importance = \MailSo\Mime\Enumerations\MessagePriority::NORMAL,
4733: $SendReadingConfirmation = false,
4734: $Attachments = array(),
4735: $InReplyTo = "",
4736: $References = "",
4737: $Sensitivity = \MailSo\Mime\Enumerations\Sensitivity::NOTHING,
4738: $SentFolder = "",
4739: $DraftFolder = "",
4740: $ConfirmFolder = "",
4741: $ConfirmUid = "",
4742: $CustomHeaders = []
4743: ) {
4744: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
4745:
4746: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
4747:
4748: self::checkAccess($oAccount);
4749:
4750: $oIdentity = $IdentityID !== 0 ? $this->getIdentitiesManager()->getIdentity($IdentityID) : null;
4751:
4752: $oMessage = self::Decorator()->BuildMessage(
4753: $oAccount,
4754: $To,
4755: $Cc,
4756: $Bcc,
4757: $Subject,
4758: $IsHtml,
4759: $Text,
4760: $Attachments,
4761: $DraftInfo,
4762: $InReplyTo,
4763: $References,
4764: $Importance,
4765: $Sensitivity,
4766: $SendReadingConfirmation,
4767: $Fetcher,
4768: $Alias,
4769: false,
4770: $oIdentity,
4771: $CustomHeaders
4772: );
4773:
4774: if ($oMessage) {
4775: $mResult = $this->getMailManager()->sendMessage($oAccount, $oMessage, $Fetcher, $oIdentity, $SentFolder, $DraftFolder, $DraftUid, $Recipients);
4776:
4777: if ($mResult) {
4778: $aCollection = $oMessage->GetRcpt();
4779:
4780: $aEmails = array();
4781: $aCollection->ForeachList(function ($oEmail) use (&$aEmails) {
4782: $aEmails[strtolower($oEmail->GetEmail())] = trim($oEmail->GetDisplayName());
4783: });
4784:
4785: if (\is_array($aEmails)) {
4786: $aArgs = ['IdUser' => $oAccount->IdUser, 'Emails' => $aEmails];
4787: $this->broadcastEvent('AfterUseEmails', $aArgs);
4788: }
4789: }
4790:
4791: if (\is_array($DraftInfo) && 3 === \count($DraftInfo)) {
4792: $sDraftInfoType = $DraftInfo[0];
4793: $sDraftInfoUid = $DraftInfo[1];
4794: $sDraftInfoFolder = $DraftInfo[2];
4795:
4796: try {
4797: switch (\strtolower($sDraftInfoType)) {
4798: case 'reply':
4799: case 'reply-all':
4800: $this->getMailManager()->setMessageFlag(
4801: $oAccount,
4802: $sDraftInfoFolder,
4803: array($sDraftInfoUid),
4804: \MailSo\Imap\Enumerations\MessageFlag::ANSWERED,
4805: \Aurora\Modules\Mail\Enums\MessageStoreAction::Add
4806: );
4807: break;
4808: case 'forward':
4809: $this->getMailManager()->setMessageFlag(
4810: $oAccount,
4811: $sDraftInfoFolder,
4812: array($sDraftInfoUid),
4813: '$Forwarded',
4814: \Aurora\Modules\Mail\Enums\MessageStoreAction::Add
4815: );
4816: break;
4817: }
4818: } catch (\Exception $oException) {
4819: }
4820: }
4821:
4822: if (0 < \strlen($ConfirmFolder) && 0 < \strlen($ConfirmUid)) {
4823: try {
4824: $mResult = $this->getMailManager()->setMessageFlag(
4825: $oAccount,
4826: $ConfirmFolder,
4827: array($ConfirmUid),
4828: '$ReadConfirm',
4829: \Aurora\Modules\Mail\Enums\MessageStoreAction::Add,
4830: false,
4831: true
4832: );
4833: } catch (\Exception $oException) {
4834: }
4835: }
4836: }
4837:
4838: \Aurora\System\Api::LogEvent('message-send: ' . $oAccount->Email, self::GetName());
4839: return $mResult;
4840: }
4841:
4842: /**
4843: * @api {post} ?/Api/ SetupSystemFolders
4844: * @apiName SetupSystemFolders
4845: * @apiGroup Mail
4846: * @apiDescription Sets up new values of special folders.
4847: *
4848: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
4849: * @apiHeaderExample {json} Header-Example:
4850: * {
4851: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
4852: * }
4853: *
4854: * @apiParam {string=Mail} Module Module name
4855: * @apiParam {string=SetupSystemFolders} Method Method name
4856: * @apiParam {string} Parameters JSON.stringified object<br>
4857: * {<br>
4858: * &emsp; **AccountID** *int* Account identifier.<br>
4859: * &emsp; **Sent** *string* New value of Sent folder full name.<br>
4860: * &emsp; **Drafts** *string* New value of Drafts folder full name.<br>
4861: * &emsp; **Trash** *string* New value of Trash folder full name.<br>
4862: * &emsp; **Spam** *string* New value of Spam folder full name.<br>
4863: * }
4864: *
4865: * @apiParamExample {json} Request-Example:
4866: * {
4867: * Module: 'Mail',
4868: * Method: 'SetupSystemFolders',
4869: * Parameters: '{ "AccountID": 12, "Sent": "Sent", "Drafts": "Drafts", "Trash": "Trash", "Spam": "Spam" }'
4870: * }
4871: *
4872: * @apiSuccess {object[]} Result Array of response objects.
4873: * @apiSuccess {string} Result.Module Module name.
4874: * @apiSuccess {string} Result.Method Method name.
4875: * @apiSuccess {boolean} Result.Result Indicates if system folders were set up successfully.
4876: * @apiSuccess {int} [Result.ErrorCode] Error code
4877: *
4878: * @apiSuccessExample {json} Success response example:
4879: * {
4880: * Module: 'Mail',
4881: * Method: 'SetupSystemFolders',
4882: * Result: true
4883: * }
4884: *
4885: * @apiSuccessExample {json} Error response example:
4886: * {
4887: * Module: 'Mail',
4888: * Method: 'SetupSystemFolders',
4889: * Result: false,
4890: * ErrorCode: 102
4891: * }
4892: */
4893: /**
4894: * Sets up new values of special folders.
4895: * @param int $AccountID Account identifier.
4896: * @param string $Sent New value of Sent folder full name.
4897: * @param string $Drafts New value of Drafts folder full name.
4898: * @param string $Trash New value of Trash folder full name.
4899: * @param string $Spam New value of Spam folder full name.
4900: * @return boolean
4901: */
4902: public function SetupSystemFolders($AccountID, $Sent, $Drafts, $Trash, $Spam)
4903: {
4904: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
4905:
4906: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
4907:
4908: self::checkAccess($oAccount);
4909:
4910: $aSystemNames = [
4911: \Aurora\Modules\Mail\Enums\FolderType::Sent => \trim($Sent),
4912: \Aurora\Modules\Mail\Enums\FolderType::Drafts => \trim($Drafts),
4913: \Aurora\Modules\Mail\Enums\FolderType::Trash => \trim($Trash),
4914: \Aurora\Modules\Mail\Enums\FolderType::Spam => \trim($Spam)
4915: ];
4916:
4917: return $this->getMailManager()->updateSystemFolderNames($oAccount, $aSystemNames);
4918: }
4919:
4920: /**
4921: * @param int $AccountID Account identifier.
4922: * @param string $FolderFullName folder full name.
4923: * @param bool $AlwaysRefresh
4924: * @return boolean
4925: */
4926: public function SetAlwaysRefreshFolder($AccountID, $FolderFullName, $AlwaysRefresh)
4927: {
4928: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
4929:
4930: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
4931:
4932: self::checkAccess($oAccount);
4933:
4934: return $this->getMailManager()->setAlwaysRefreshFolder($oAccount, $FolderFullName, $AlwaysRefresh);
4935: }
4936:
4937: /**
4938: * Marks (or unmarks) folder as template folder.
4939: * @param int $AccountID Account identifier.
4940: * @param string $FolderFullName Full name of folder that should be marked/unmarked as template.
4941: * @param boolean $SetTemplate Indicates if template should be set or unset.
4942: * @return boolean
4943: */
4944: public function SetTemplateFolderType($AccountID, $FolderFullName, $SetTemplate)
4945: {
4946: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
4947:
4948: if ($this->getConfig('AllowTemplateFolders', false)) {
4949: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
4950:
4951: self::checkAccess($oAccount);
4952:
4953: return $this->getMailManager()->setSystemFolder($oAccount, $FolderFullName, \Aurora\Modules\Mail\Enums\FolderType::Template, $SetTemplate);
4954: }
4955:
4956: return false;
4957: }
4958:
4959: /**
4960: * @api {post} ?/Api/ SetEmailSafety
4961: * @apiName SetEmailSafety
4962: * @apiGroup Mail
4963: * @apiDescription Marks sender email as safety for authenticated user. So pictures in messages from this sender will be always displayed.
4964: *
4965: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
4966: * @apiHeaderExample {json} Header-Example:
4967: * {
4968: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
4969: * }
4970: *
4971: * @apiParam {string=Mail} Module Module name
4972: * @apiParam {string=SetEmailSafety} Method Method name
4973: * @apiParam {string} Parameters JSON.stringified object<br>
4974: * {<br>
4975: * &emsp; **AccountID** *int* Account identifier.<br>
4976: * &emsp; **Email** *string* Sender email.<br>
4977: * }
4978: *
4979: * @apiParamExample {json} Request-Example:
4980: * {
4981: * Module: 'Mail',
4982: * Method: 'SetEmailSafety',
4983: * Parameters: '{ "AccountID": 12, "Email": "test@email" }'
4984: * }
4985: *
4986: * @apiSuccess {object[]} Result Array of response objects.
4987: * @apiSuccess {string} Result.Module Module name.
4988: * @apiSuccess {string} Result.Method Method name.
4989: * @apiSuccess {boolean} Result.Result Indicates if email was marked as safety successfully.
4990: * @apiSuccess {int} [Result.ErrorCode] Error code
4991: *
4992: * @apiSuccessExample {json} Success response example:
4993: * {
4994: * Module: 'Mail',
4995: * Method: 'SetEmailSafety',
4996: * Result: true
4997: * }
4998: *
4999: * @apiSuccessExample {json} Error response example:
5000: * {
5001: * Module: 'Mail',
5002: * Method: 'SetEmailSafety',
5003: * Result: false,
5004: * ErrorCode: 102
5005: * }
5006: */
5007: /**
5008: * Marks sender email as safety for authenticated user. So pictures in messages from this sender will be always displayed.
5009: * @param int $AccountID Account identifier.
5010: * @param string $Email Sender email.
5011: * @return boolean
5012: * @throws \Aurora\System\Exceptions\ApiException
5013: */
5014: public function SetEmailSafety($AccountID, $Email)
5015: {
5016: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
5017:
5018: if (0 === \strlen(\trim($Email))) {
5019: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
5020: }
5021:
5022: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
5023:
5024: self::checkAccess($oAccount);
5025:
5026: $this->getMailManager()->setSafetySender($oAccount->IdUser, $Email);
5027:
5028: return true;
5029: }
5030:
5031: /**
5032: * @api {post} ?/Api/ CreateIdentity
5033: * @apiName CreateIdentity
5034: * @apiGroup Mail
5035: * @apiDescription Creates identity.
5036: *
5037: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
5038: * @apiHeaderExample {json} Header-Example:
5039: * {
5040: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
5041: * }
5042: *
5043: * @apiParam {string=Mail} Module Module name
5044: * @apiParam {string=CreateIdentity} Method Method name
5045: * @apiParam {string} Parameters JSON.stringified object<br>
5046: * {<br>
5047: * &emsp; **UserId** *int* (optional) User identifier.<br>
5048: * &emsp; **AccountID** *int* Account identifier.<br>
5049: * &emsp; **FriendlyName** *string* Identity friendly name.<br>
5050: * &emsp; **Email** *string* Identity email.<br>
5051: * }
5052: *
5053: * @apiParamExample {json} Request-Example:
5054: * {
5055: * Module: 'Mail',
5056: * Method: 'CreateIdentity',
5057: * Parameters: '{ "AccountID": 12, "FriendlyName": "My name", "Email": "test@email" }'
5058: * }
5059: *
5060: * @apiSuccess {object[]} Result Array of response objects.
5061: * @apiSuccess {string} Result.Module Module name.
5062: * @apiSuccess {string} Result.Method Method name.
5063: * @apiSuccess {mixed} Result.Result Identifier of created identity in case of success, otherwise **false**.
5064: * @apiSuccess {int} [Result.ErrorCode] Error code
5065: *
5066: * @apiSuccessExample {json} Success response example:
5067: * {
5068: * Module: 'Mail',
5069: * Method: 'CreateIdentity',
5070: * Result: 14
5071: * }
5072: *
5073: * @apiSuccessExample {json} Error response example:
5074: * {
5075: * Module: 'Mail',
5076: * Method: 'CreateIdentity',
5077: * Result: false,
5078: * ErrorCode: 102
5079: * }
5080: */
5081: /**
5082: * Creates identity.
5083: * @param int $UserId User identifier.
5084: * @param int $AccountID Account identifier.
5085: * @param string $FriendlyName Identity friendly name.
5086: * @param string $Email Identity email.
5087: * @return int|boolean
5088: */
5089: public function CreateIdentity($UserId, $AccountID, $FriendlyName, $Email)
5090: {
5091: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
5092:
5093: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
5094:
5095: self::checkAccess($oAccount);
5096:
5097: return $this->getIdentitiesManager()->createIdentity($UserId, $AccountID, $FriendlyName, $Email);
5098: }
5099:
5100: /**
5101: * @api {post} ?/Api/ UpdateIdentity
5102: * @apiName UpdateIdentity
5103: * @apiGroup Mail
5104: * @apiDescription Updates identity.
5105: *
5106: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
5107: * @apiHeaderExample {json} Header-Example:
5108: * {
5109: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
5110: * }
5111: *
5112: * @apiParam {string=Mail} Module Module name
5113: * @apiParam {string=UpdateIdentity} Method Method name
5114: * @apiParam {string} Parameters JSON.stringified object<br>
5115: * {<br>
5116: * &emsp; **UserId** *int* (optional) User identifier.<br>
5117: * &emsp; **AccountID** *int* Account identifier.<br>
5118: * &emsp; **Id** *int* Identity identifier.<br>
5119: * &emsp; **FriendlyName** *string* New value of identity friendly name.<br>
5120: * &emsp; **Email** *string* New value of identity email.<br>
5121: * &emsp; **Default** *boolean* Indicates if identity should be used by default.<br>
5122: * &emsp; **AccountPart** *boolean* Indicated if account should be updated, not any identity.<br>
5123: * }
5124: *
5125: * @apiParamExample {json} Request-Example:
5126: * {
5127: * Module: 'Mail',
5128: * Method: 'UpdateIdentity',
5129: * Parameters: '{ "AccountID": 12, "Id": 14, "FriendlyName": "New my name", "Email": "test@email",
5130: * "Default": false, "AccountPart": false }'
5131: * }
5132: *
5133: * @apiSuccess {object[]} Result Array of response objects.
5134: * @apiSuccess {string} Result.Module Module name.
5135: * @apiSuccess {string} Result.Method Method name.
5136: * @apiSuccess {boolean} Result.Result Indicates if identity was updated successfully.
5137: * @apiSuccess {int} [Result.ErrorCode] Error code
5138: *
5139: * @apiSuccessExample {json} Success response example:
5140: * {
5141: * Module: 'Mail',
5142: * Method: 'UpdateIdentity',
5143: * Result: true
5144: * }
5145: *
5146: * @apiSuccessExample {json} Error response example:
5147: * {
5148: * Module: 'Mail',
5149: * Method: 'UpdateIdentity',
5150: * Result: false,
5151: * ErrorCode: 102
5152: * }
5153: */
5154: /**
5155: * Updates identity.
5156: * @param int $UserId User identifier.
5157: * @param int $AccountID Account identifier.
5158: * @param int $Id Identity identifier.
5159: * @param string $FriendlyName New value of identity friendly name.
5160: * @param string $Email New value of identity email.
5161: * @param boolean $Default Indicates if identity should be used by default.
5162: * @param boolean $AccountPart Indicated if account should be updated, not any identity.
5163: * @return boolean
5164: */
5165: public function UpdateIdentity($UserId, $AccountID, $EntityId, $FriendlyName, $Email, $Default = false, $AccountPart = false)
5166: {
5167: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
5168:
5169: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
5170:
5171: self::checkAccess($oAccount);
5172:
5173: if ($Default) {
5174: $this->getIdentitiesManager()->resetDefaultIdentity($UserId, $AccountID);
5175: }
5176:
5177: if ($AccountPart) {
5178: return $this->UpdateAccount($AccountID, null, $Email, $FriendlyName);
5179: } else {
5180: return $this->getIdentitiesManager()->updateIdentity($EntityId, $FriendlyName, $Email, $Default);
5181: }
5182: }
5183:
5184: /**
5185: * @api {post} ?/Api/ DeleteIdentity
5186: * @apiName DeleteIdentity
5187: * @apiGroup Mail
5188: * @apiDescription Deletes identity.
5189: *
5190: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
5191: * @apiHeaderExample {json} Header-Example:
5192: * {
5193: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
5194: * }
5195: *
5196: * @apiParam {string=Mail} Module Module name
5197: * @apiParam {string=DeleteIdentity} Method Method name
5198: * @apiParam {string} Parameters JSON.stringified object<br>
5199: * {<br>
5200: * &emsp; **Id** *int* Identity identifier.<br>
5201: * }
5202: *
5203: * @apiParamExample {json} Request-Example:
5204: * {
5205: * Module: 'Mail',
5206: * Method: 'DeleteIdentity',
5207: * Parameters: '{ "Id": 14 }'
5208: * }
5209: *
5210: * @apiSuccess {object[]} Result Array of response objects.
5211: * @apiSuccess {string} Result.Module Module name.
5212: * @apiSuccess {string} Result.Method Method name.
5213: * @apiSuccess {boolean} Result.Result Indicates if identity was deleted successfully.
5214: * @apiSuccess {int} [Result.ErrorCode] Error code
5215: *
5216: * @apiSuccessExample {json} Success response example:
5217: * {
5218: * Module: 'Mail',
5219: * Method: 'DeleteIdentity',
5220: * Result: true
5221: * }
5222: *
5223: * @apiSuccessExample {json} Error response example:
5224: * {
5225: * Module: 'Mail',
5226: * Method: 'DeleteIdentity',
5227: * Result: false,
5228: * ErrorCode: 102
5229: * }
5230: */
5231: /**
5232: * Deletes identity.
5233: * @param int $EntityId Identity identifier.
5234: * @return boolean
5235: */
5236: public function DeleteIdentity($AccountID, $EntityId)
5237: {
5238: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
5239:
5240: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
5241:
5242: self::checkAccess($oAccount);
5243:
5244: return $this->getIdentitiesManager()->deleteIdentity($EntityId);
5245: }
5246:
5247: /**
5248: * @api {post} ?/Api/ GetIdentities
5249: * @apiName GetIdentities
5250: * @apiGroup Mail
5251: * @apiDescription Obtaines all identities of specified user.
5252: *
5253: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
5254: * @apiHeaderExample {json} Header-Example:
5255: * {
5256: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
5257: * }
5258: *
5259: * @apiParam {string=Mail} Module Module name
5260: * @apiParam {string=GetServers} Method Method name
5261: * @apiParam {string} [Parameters] JSON.stringified object<br>
5262: * {<br>
5263: * &emsp; **UserId** *int* (optional) User identifier.<br>
5264: * }
5265: *
5266: * @apiParamExample {json} Request-Example:
5267: * {
5268: * Module: 'Mail',
5269: * Method: 'GetIdentities'
5270: * }
5271: *
5272: * @apiSuccess {object[]} Result Array of response objects.
5273: * @apiSuccess {string} Result.Module Module name.
5274: * @apiSuccess {string} Result.Method Method name.
5275: * @apiSuccess {mixed} Result.Result List identities in case of success, otherwise **false**.
5276: * @apiSuccess {int} Result.Result.Id Identity identifier.
5277: * @apiSuccess {int} Result.Result.UUID Identity UUID.
5278: * @apiSuccess {int} Result.Result.IdUser User identifier.
5279: * @apiSuccess {int} Result.Result.IdAccount Identifier of account owns identity.
5280: * @apiSuccess {int} Result.Result.Default Indicates if signature should be used as default on compose screen.
5281: * @apiSuccess {int} Result.Result.Email Identity email.
5282: * @apiSuccess {int} Result.Result.FriendlyName Identity friendly name.
5283: * @apiSuccess {boolean} Result.Result.UseSignature Indicates if signature should be used in outgoing mails.
5284: * @apiSuccess {string} Result.Result.Signature Identity signature.
5285: * @apiSuccess {int} [Result.ErrorCode] Error code
5286: *
5287: * @apiSuccessExample {json} Success response example:
5288: * {
5289: * Module: 'Mail',
5290: * Method: 'GetIdentities',
5291: * Result: [ { "Id": 14, "UUID": "uuid_value", "IdUser": 3, "IdAccount": 12,
5292: * "Default": false, "Email": "test@email", "FriendlyName": "My name",
5293: * "UseSignature": true, "Signature": "signature_value" },
5294: * ... ]
5295: * }
5296: *
5297: * @apiSuccessExample {json} Error response example:
5298: * {
5299: * Module: 'Mail',
5300: * Method: 'GetIdentities',
5301: * Result: false,
5302: * ErrorCode: 102
5303: * }
5304: */
5305: /**
5306: * Obtains all identities of specified user.
5307: * @param int $UserId User identifier.
5308: * @return array|false
5309: */
5310: public function GetIdentities($UserId)
5311: {
5312: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
5313:
5314: self::checkAccess(null, $UserId);
5315:
5316: return $this->getIdentitiesManager()->getIdentities($UserId)->all();
5317: }
5318:
5319: /**
5320: * @api {post} ?/Api/ UpdateSignature
5321: * @apiName UpdateSignature
5322: * @apiGroup Mail
5323: * @apiDescription Updates signature.
5324: *
5325: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
5326: * @apiHeaderExample {json} Header-Example:
5327: * {
5328: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
5329: * }
5330: *
5331: * @apiParam {string=Mail} Module Module name
5332: * @apiParam {string=UpdateSignature} Method Method name
5333: * @apiParam {string} Parameters JSON.stringified object<br>
5334: * {<br>
5335: * &emsp; **AccountID** *int* Account identifier.<br>
5336: * &emsp; **UseSignature** *boolean* Indicates if signature should be used in outgoing mails.<br>
5337: * &emsp; **Signature** *string* Account or identity signature.<br>
5338: * &emsp; **IdentityID** *int* (optional) Identity identifier.<br>
5339: * }
5340: *
5341: * @apiParamExample {json} Request-Example:
5342: * {
5343: * Module: 'Mail',
5344: * Method: 'UpdateSignature',
5345: * Parameters: '{ "AccountID": 12, "UseSignature": true, "Signature": "signature_value", "IdentityID": 14 }'
5346: * }
5347: *
5348: * @apiSuccess {object[]} Result Array of response objects.
5349: * @apiSuccess {string} Result.Module Module name.
5350: * @apiSuccess {string} Result.Method Method name.
5351: * @apiSuccess {boolean} Result.Result Indicates if signature was updated successfully.
5352: * @apiSuccess {int} [Result.ErrorCode] Error code
5353: *
5354: * @apiSuccessExample {json} Success response example:
5355: * {
5356: * Module: 'Mail',
5357: * Method: 'UpdateSignature',
5358: * Result: true
5359: * }
5360: *
5361: * @apiSuccessExample {json} Error response example:
5362: * {
5363: * Module: 'Mail',
5364: * Method: 'UpdateSignature',
5365: * Result: false,
5366: * ErrorCode: 102
5367: * }
5368: */
5369: /**
5370: * Updates signature.
5371: * @param int $AccountID Account identifier.
5372: * @param boolean $UseSignature Indicates if signature should be used in outgoing mails.
5373: * @param string $Signature Account or identity signature.
5374: * @param int $IdentityId Identity identifier.
5375: * @return boolean
5376: * @throws \Aurora\System\Exceptions\ApiException
5377: */
5378: public function UpdateSignature($AccountID, $UseSignature = null, $Signature = null, $IdentityId = null)
5379: {
5380: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
5381:
5382: if ($AccountID > 0) {
5383: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
5384:
5385: self::checkAccess($oAccount);
5386:
5387: if ($this->getConfig('AllowIdentities', false) && $IdentityId !== null) {
5388: return $this->getIdentitiesManager()->updateIdentitySignature($IdentityId, $UseSignature, $Signature);
5389: } else {
5390: if ($oAccount) {
5391: if ($UseSignature !== null) {
5392: $oAccount->UseSignature = $UseSignature;
5393: }
5394: if ($Signature !== null) {
5395: $oAccount->Signature = $Signature;
5396: }
5397:
5398: return $this->getAccountsManager()->updateAccount($oAccount);
5399: }
5400: }
5401: } else {
5402: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
5403: }
5404:
5405: return false;
5406: }
5407:
5408: /**
5409: * @api {post} ?/Api/ UploadAttachment
5410: * @apiName UploadAttachment
5411: * @apiGroup Mail
5412: * @apiDescription Uploads attachment.
5413: *
5414: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
5415: * @apiHeaderExample {json} Header-Example:
5416: * {
5417: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
5418: * }
5419: *
5420: * @apiParam {string=Mail} Module Module name
5421: * @apiParam {string=UploadAttachment} Method Method name
5422: * @apiParam {string} [Parameters] JSON.stringified object<br>
5423: * {<br>
5424: * &emsp; **UserId** *int* (optional) User identifier.<br>
5425: * &emsp; **AccountID** *int* Account identifier.<br>
5426: * }
5427: * @apiParam {string} UploadData Data of uploaded file.
5428: *
5429: * @apiParamExample {json} Request-Example:
5430: * {
5431: * Module: 'Mail',
5432: * Method: 'UploadAttachment',
5433: * Parameters: '{ "AccountID": 12 }'
5434: * }
5435: *
5436: * @apiSuccess {object[]} Result Array of response objects.
5437: * @apiSuccess {string} Result.Module Module name.
5438: * @apiSuccess {string} Result.Method Method name.
5439: * @apiSuccess {mixed} Result.Result Attachment properties in case of success, otherwise **false**.
5440: * @apiSuccess {int} [Result.ErrorCode] Error code
5441: *
5442: * @apiSuccessExample {json} Success response example:
5443: * {
5444: * Module: 'Mail',
5445: * Method: 'UploadAttachment',
5446: * Result: { "Attachment": { "Name": "name.txt", "TempName": "temp_name_value", "MimeType": "text/plain",
5447: * "Size": 14, "Hash": "hash_value", "Actions": { "view": { "url": "url_value" },
5448: * "download": { "url": "url_value" } }, "ThumbnailUrl": "" } }
5449: * }
5450: *
5451: * @apiSuccessExample {json} Error response example:
5452: * {
5453: * Module: 'Mail',
5454: * Method: 'UploadAttachment',
5455: * Result: false,
5456: * ErrorCode: 102
5457: * }
5458: */
5459: /**
5460: * Uploads attachment.
5461: * @param int $UserId User identifier.
5462: * @param int $AccountID Account identifier.
5463: * @param array $UploadData Information about uploaded file.
5464: * @return array
5465: */
5466: public function UploadAttachment($UserId, $AccountID, $UploadData)
5467: {
5468: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
5469:
5470: $sUUID = \Aurora\System\Api::getUserUUIDById($UserId);
5471: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
5472:
5473: self::checkAccess($oAccount);
5474:
5475: $sError = '';
5476: $aResponse = array();
5477:
5478: if ($oAccount instanceof \Aurora\Modules\Mail\Models\MailAccount) {
5479: if (\is_array($UploadData)) {
5480: $sSavedName = 'upload-post-'.\md5($UploadData['name'].$UploadData['tmp_name']);
5481: $rData = false;
5482: if (\is_resource($UploadData['tmp_name'])) {
5483: $rData = $UploadData['tmp_name'];
5484: } else {
5485: if ($this->getFilecacheManager()->moveUploadedFile($sUUID, $sSavedName, $UploadData['tmp_name'])) {
5486: $rData = $this->getFilecacheManager()->getFile($sUUID, $sSavedName);
5487: }
5488: }
5489: if ($rData) {
5490: $sUploadName = $UploadData['name'];
5491: $iSize = $UploadData['size'];
5492: $aResponse['Attachment'] = \Aurora\System\Utils::GetClientFileResponse(
5493: null,
5494: $UserId,
5495: $sUploadName,
5496: $sSavedName,
5497: $iSize
5498: );
5499: } else {
5500: $sError = 'unknown';
5501: }
5502: } else {
5503: $sError = 'unknown';
5504: }
5505: } else {
5506: $sError = 'auth';
5507: }
5508:
5509: if (0 < strlen($sError)) {
5510: $aResponse['Error'] = $sError;
5511: }
5512:
5513: return $aResponse;
5514: }
5515:
5516: /**
5517: * @api {post} ?/Api/ SaveAttachmentsAsTempFiles
5518: * @apiName SaveAttachmentsAsTempFiles
5519: * @apiGroup Mail
5520: * @apiDescription Retrieves attachments from message and saves them as files in temporary folder.
5521: *
5522: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
5523: * @apiHeaderExample {json} Header-Example:
5524: * {
5525: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
5526: * }
5527: *
5528: * @apiParam {string=Mail} Module Module name
5529: * @apiParam {string=SaveAttachmentsAsTempFiles} Method Method name
5530: * @apiParam {string} [Parameters] JSON.stringified object<br>
5531: * {<br>
5532: * &emsp; **AccountID** *int* Account identifier.<br>
5533: * &emsp; **Attachments** *array* List of attachments hashes.<br>
5534: * }
5535: *
5536: * @apiParamExample {json} Request-Example:
5537: * {
5538: * Module: 'Mail',
5539: * Method: 'SaveAttachmentsAsTempFiles',
5540: * Parameters: '{ "Attachments": [ "hash_value" ], "AccountID": 12 }'
5541: * }
5542: *
5543: * @apiSuccess {object[]} Result Array of response objects.
5544: * @apiSuccess {string} Result.Module Module name.
5545: * @apiSuccess {string} Result.Method Method name.
5546: * @apiSuccess {mixed} Result.Result Attachments' properties in case of success, otherwise **false**.
5547: * @apiSuccess {int} [Result.ErrorCode] Error code
5548: *
5549: * @apiSuccessExample {json} Success response example:
5550: * {
5551: * Module: 'Mail',
5552: * Method: 'SaveAttachmentsAsTempFiles',
5553: * Result: { "temp_name_value": "hash_value" }
5554: * }
5555: *
5556: * @apiSuccessExample {json} Error response example:
5557: * {
5558: * Module: 'Mail',
5559: * Method: 'SaveAttachmentsAsTempFiles',
5560: * Result: false,
5561: * ErrorCode: 102
5562: * }
5563: */
5564: /**
5565: * Retrieves attachments from message and saves them as files in temporary folder.
5566: * @param int $AccountID Account identifier.
5567: * @param array $Attachments List of attachments hashes.
5568: * @return array|boolean
5569: * @throws \Aurora\System\Exceptions\ApiException
5570: */
5571: public function SaveAttachmentsAsTempFiles($AccountID, $Attachments = array())
5572: {
5573: $mResult = false;
5574: $self = $this;
5575:
5576: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
5577:
5578: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
5579:
5580: self::checkAccess($oAccount);
5581:
5582: if ($oAccount instanceof \Aurora\Modules\Mail\Models\MailAccount) {
5583: $sUUID = \Aurora\System\Api::getUserUUIDById($oAccount->IdUser);
5584: try {
5585: if (is_array($Attachments) && 0 < count($Attachments)) {
5586: $mResult = array();
5587: foreach ($Attachments as $sAttachment) {
5588: $aValues = \Aurora\System\Api::DecodeKeyValues($sAttachment);
5589: if (is_array($aValues)) {
5590: $sFolder = isset($aValues['Folder']) ? $aValues['Folder'] : '';
5591: $iUid = (int) isset($aValues['Uid']) ? $aValues['Uid'] : 0;
5592: $sMimeIndex = (string) isset($aValues['MimeIndex']) ? $aValues['MimeIndex'] : '';
5593:
5594: $sTempName = md5($sAttachment);
5595: if (!$this->getFilecacheManager()->isFileExists($sUUID, $sTempName)) {
5596: $this->getMailManager()->directMessageToStream(
5597: $oAccount,
5598: function ($rResource, $sContentType, $sFileName, $sMimeIndex = '') use ($sUUID, &$mResult, $sTempName, $sAttachment, $self) {
5599: if (is_resource($rResource)) {
5600: $sContentType = (empty($sFileName)) ? 'text/plain' : \MailSo\Base\Utils::MimeContentType($sFileName);
5601: $sFileName = \Aurora\System\Utils::clearFileName($sFileName, $sContentType, $sMimeIndex);
5602:
5603: if ($self->getFilecacheManager()->putFile($sUUID, $sTempName, $rResource)) {
5604: $mResult[$sTempName] = $sAttachment;
5605: }
5606: }
5607: },
5608: $sFolder,
5609: $iUid,
5610: $sMimeIndex
5611: );
5612: } else {
5613: $mResult[$sTempName] = $sAttachment;
5614: }
5615: }
5616: }
5617: }
5618: } catch (\Exception $oException) {
5619: throw new \Aurora\Modules\Mail\Exceptions\Exception(Enums\ErrorCodes::CannotConnectToMailServer, $oException, $oException->getMessage());
5620: }
5621: }
5622:
5623: return $mResult;
5624: }
5625:
5626: /**
5627: * @api {post} ?/Api/ SaveMessageAsTempFile
5628: * @apiName SaveMessageAsTempFile
5629: * @apiGroup Mail
5630: * @apiDescription Retrieves message and saves it as .eml file in temporary folder.
5631: *
5632: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
5633: * @apiHeaderExample {json} Header-Example:
5634: * {
5635: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
5636: * }
5637: *
5638: * @apiParam {string=Mail} Module Module name
5639: * @apiParam {string=SaveMessageAsTempFile} Method Method name
5640: * @apiParam {string} [Parameters] JSON.stringified object<br>
5641: * {<br>
5642: * &emsp; **AccountID** *int* Account identifier.<br>
5643: * &emsp; **MessageFolder** *string* Full name of folder.<br>
5644: * &emsp; **MessageUid** *string* Message uid.<br>
5645: * &emsp; **FileName** *string* Name of created .eml file.<br>
5646: * }
5647: *
5648: * @apiParamExample {json} Request-Example:
5649: * {
5650: * Module: 'Mail',
5651: * Method: 'SaveMessageAsTempFile',
5652: * Parameters: '{ "MessageFolder": "INBOX", "MessageUid": "1691", "FileName": "subject.eml",
5653: * "AccountID": 12 }'
5654: * }
5655: *
5656: * @apiSuccess {object[]} Result Array of response objects.
5657: * @apiSuccess {string} Result.Module Module name.
5658: * @apiSuccess {string} Result.Method Method name.
5659: * @apiSuccess {mixed} Result.Result .eml attachment properties in case of success, otherwise **false**.
5660: * @apiSuccess {int} [Result.ErrorCode] Error code
5661: *
5662: * @apiSuccessExample {json} Success response example:
5663: * {
5664: * Module: 'Mail',
5665: * Method: 'SaveMessageAsTempFile',
5666: * Result: { "Name": "subject.eml", "FileName": "subject.eml", "TempName":"temp_name_value",
5667: * "MimeType": "message/rfc822", "Size": 1669, "Hash": "hash_value",
5668: * "Actions": { "view": { "url": "view_url" }, "download": { "url": "download_url" } },
5669: * "ThumbnailUrl": "" } }
5670: * }
5671: *
5672: * @apiSuccessExample {json} Error response example:
5673: * {
5674: * Module: 'Mail',
5675: * Method: 'SaveMessageAsTempFile',
5676: * Result: false,
5677: * ErrorCode: 102
5678: * }
5679: */
5680: /**
5681: * Retrieves message and saves it as .eml file in temporary folder.
5682: * @param int $AccountID Account identifier.
5683: * @param string $MessageFolder Full name of folder.
5684: * @param string $MessageUid Message uid.
5685: * @param string $FileName Name of created .eml file.
5686: * @return array|boolean
5687: * @throws \Aurora\System\Exceptions\ApiException
5688: */
5689: public function SaveMessageAsTempFile($AccountID, $MessageFolder, $MessageUid, $FileName)
5690: {
5691: $mResult = false;
5692: $self = $this;
5693:
5694: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
5695:
5696: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
5697:
5698: self::checkAccess($oAccount);
5699:
5700: if ($oAccount instanceof \Aurora\Modules\Mail\Models\MailAccount) {
5701: $sUUID = \Aurora\System\Api::getUserUUIDById($oAccount->IdUser);
5702: try {
5703: $sMimeType = 'message/rfc822';
5704: $sTempName = md5($MessageFolder.$MessageUid);
5705: if (!$this->getFilecacheManager()->isFileExists($sUUID, $sTempName)) {
5706: $this->getMailManager()->directMessageToStream(
5707: $oAccount,
5708: function ($rResource, $sContentType, $sFileName) use ($sUUID, $sTempName, &$sMimeType, $self) {
5709: if (is_resource($rResource)) {
5710: $sMimeType = $sContentType;
5711: $sFileName = \Aurora\System\Utils::clearFileName($sFileName, $sMimeType, '');
5712: $self->getFilecacheManager()->putFile($sUUID, $sTempName, $rResource);
5713: }
5714: },
5715: $MessageFolder,
5716: $MessageUid
5717: );
5718: }
5719:
5720: if ($this->getFilecacheManager()->isFileExists($sUUID, $sTempName)) {
5721: $iSize = $this->getFilecacheManager()->fileSize($sUUID, $sTempName);
5722: $mResult = \Aurora\System\Utils::GetClientFileResponse(
5723: null,
5724: $oAccount->IdUser,
5725: $FileName,
5726: $sTempName,
5727: $iSize
5728: );
5729: }
5730: } catch (\Exception $oException) {
5731: throw new \Aurora\Modules\Mail\Exceptions\Exception(Enums\ErrorCodes::CannotConnectToMailServer, $oException, $oException->getMessage());
5732: }
5733: }
5734:
5735: return $mResult;
5736: }
5737:
5738: /**
5739: * @api {post} ?/Api/ UploadMessage
5740: * @apiName UploadMessage
5741: * @apiGroup Mail
5742: * @apiDescription Uploads message and puts it to specified folder.
5743: *
5744: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
5745: * @apiHeaderExample {json} Header-Example:
5746: * {
5747: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
5748: * }
5749: *
5750: * @apiParam {string=Mail} Module Module name
5751: * @apiParam {string=UploadMessage} Method Method name
5752: * @apiParam {string} [Parameters] JSON.stringified object<br>
5753: * {<br>
5754: * &emsp; **AccountID** *int* Account identifier.<br>
5755: * &emsp; **Folder** *string* Folder full name.<br>
5756: * }
5757: * @apiParam {string} UploadData Information about uploaded .eml file.
5758: *
5759: * @apiParamExample {json} Request-Example:
5760: * {
5761: * Module: 'Mail',
5762: * Method: 'UploadMessage',
5763: * Parameters: '{ "AccountID": 12, "Folder": "INBOX" }'
5764: * }
5765: *
5766: * @apiSuccess {object[]} Result Array of response objects.
5767: * @apiSuccess {string} Result.Module Module name.
5768: * @apiSuccess {string} Result.Method Method name.
5769: * @apiSuccess {boolean} Result.Result Indicates if message was uploaded successfully.
5770: * @apiSuccess {int} [Result.ErrorCode] Error code
5771: *
5772: * @apiSuccessExample {json} Success response example:
5773: * {
5774: * Module: 'Mail',
5775: * Method: 'UploadMessage',
5776: * Result: true
5777: * }
5778: *
5779: * @apiSuccessExample {json} Error response example:
5780: * {
5781: * Module: 'Mail',
5782: * Method: 'UploadMessage',
5783: * Result: false,
5784: * ErrorCode: 102
5785: * }
5786: */
5787: /**
5788: * Uploads message and puts it to specified folder.
5789: * @param int $AccountID Account identifier.
5790: * @param string $Folder Folder full name.
5791: * @param array $UploadData Information about uploaded .eml file.
5792: * @return boolean
5793: * @throws \ProjectCore\Exceptions\ClientException
5794: */
5795: public function UploadMessage($AccountID, $Folder, $UploadData)
5796: {
5797: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
5798:
5799: $bResult = false;
5800:
5801: $oAccount = $this->getAccountsManager()->getAccountById((int)$AccountID);
5802:
5803: self::checkAccess($oAccount);
5804:
5805: if ($oAccount) {
5806: $sUUID = \Aurora\System\Api::getUserUUIDById($oAccount->IdUser);
5807: if (is_array($UploadData)) {
5808: $sUploadName = $UploadData['name'];
5809: $bIsEmlExtension = strtolower(pathinfo($sUploadName, PATHINFO_EXTENSION)) === 'eml';
5810:
5811: if ($bIsEmlExtension) {
5812: $sSavedName = 'upload-post-' . md5($UploadData['name'] . $UploadData['tmp_name']);
5813: if (is_resource($UploadData['tmp_name'])) {
5814: $this->getFilecacheManager()->putFile($sUUID, $sSavedName, $UploadData['tmp_name']);
5815: } else {
5816: $this->getFilecacheManager()->moveUploadedFile($sUUID, $sSavedName, $UploadData['tmp_name']);
5817: }
5818: if ($this->getFilecacheManager()->isFileExists($sUUID, $sSavedName)) {
5819: $sSavedFullName = $this->getFilecacheManager()->generateFullFilePath($sUUID, $sSavedName);
5820: try {
5821: $this->getMailManager()->appendMessageFromFile($oAccount, $sSavedFullName, $Folder);
5822: $bResult = true;
5823: } catch (\Exception $oException) {
5824: throw new \Aurora\Modules\Mail\Exceptions\Exception(Enums\ErrorCodes::CannotUploadMessage, $oException, $oException->getMessage());
5825: }
5826: } else {
5827: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::UnknownError);
5828: }
5829: } else {
5830: throw new \Aurora\Modules\Mail\Exceptions\Exception(Enums\ErrorCodes::CannotUploadMessageFileNotEml);
5831: }
5832: }
5833: } else {
5834: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
5835: }
5836:
5837: return $bResult;
5838: }
5839:
5840: /**
5841: * @api {post} ?/Api/ ChangePassword
5842: * @apiName ChangePassword
5843: * @apiGroup Mail
5844: * @apiDescription Changes account password.
5845: *
5846: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
5847: * @apiHeaderExample {json} Header-Example:
5848: * {
5849: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
5850: * }
5851: *
5852: * @apiParam {string=Mail} Module Module name
5853: * @apiParam {string=ChangePassword} Method Method name
5854: * @apiParam {string} Parameters JSON.stringified object<br>
5855: * {<br>
5856: * &emsp; **AccountId** *int* Account identifier.<br>
5857: * &emsp; **CurrentPassword** *string* Current password.<br>
5858: * &emsp; **NewPassword** *string* New password.<br>
5859: * }
5860: *
5861: * @apiParamExample {json} Request-Example:
5862: * {
5863: * Module: 'Mail',
5864: * Method: 'ChangePassword',
5865: * Parameters: '{ "AccountId": 12, "CurrentPassword": "pass_value", "NewPassword": "new_pass_value" }'
5866: * }
5867: *
5868: * @apiSuccess {object[]} Result Array of response objects.
5869: * @apiSuccess {string} Result.Module Module name.
5870: * @apiSuccess {string} Result.Method Method name.
5871: * @apiSuccess {boolean} Result.Result Indicates if password was changed successfully.
5872: * @apiSuccess {int} [Result.ErrorCode] Error code
5873: *
5874: * @apiSuccessExample {json} Success response example:
5875: * {
5876: * Module: 'Mail',
5877: * Method: 'ChangePassword',
5878: * Result: true
5879: *
5880: * @apiSuccessExample {json} Error response example:
5881: * {
5882: * Module: 'Mail',
5883: * Method: 'ChangePassword',
5884: * Result: false,
5885: * ErrorCode: 102
5886: * }
5887: */
5888: /**
5889: * This method will trigger some event, subscribers of which perform all change password process
5890: *
5891: * @param int $AccountId Account identifier.
5892: * @param string $CurrentPassword Current password.
5893: * @param string $NewPassword New password.
5894: * @return boolean
5895: */
5896: public function ChangePassword($AccountId, $CurrentPassword, $NewPassword)
5897: {
5898: $mResult = false;
5899:
5900: if ($AccountId > 0) {
5901: $oAccount = $this->getAccountsManager()->getAccountById($AccountId);
5902:
5903: self::checkAccess($oAccount);
5904:
5905: $oUser = \Aurora\System\Api::getAuthenticatedUser();
5906: if ($oAccount instanceof \Aurora\Modules\Mail\Models\MailAccount &&
5907: $oUser instanceof \Aurora\Modules\Core\Models\User &&
5908: (($oUser->isNormalOrTenant() && $oUser->Id === $oAccount->IdUser) ||
5909: $oUser->Role === \Aurora\System\Enums\UserRole::SuperAdmin)
5910: ) {
5911: if ($oUser->Role !== \Aurora\System\Enums\UserRole::SuperAdmin && $oAccount->getPassword() !== $CurrentPassword) {
5912: \Aurora\System\Api::LogEvent('password-change-failed: ' . $oAccount->Email, self::GetName());
5913: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Exceptions\Errs::UserManager_AccountOldPasswordNotCorrect);
5914: }
5915:
5916: $aArgs = [
5917: 'Account' => $oAccount,
5918: 'CurrentPassword' => $CurrentPassword,
5919: 'NewPassword' => $NewPassword
5920: ];
5921: $aResponse = [
5922: 'AccountPasswordChanged' => false
5923: ];
5924:
5925: \Aurora\System\Api::GetModule('Core')->broadcastEvent(
5926: 'Mail::ChangeAccountPassword',
5927: $aArgs,
5928: $aResponse
5929: );
5930:
5931: if ($aResponse['AccountPasswordChanged']) {
5932: $oAccount->setPassword($NewPassword);
5933: if ($this->getAccountsManager()->updateAccount($oAccount)) {
5934: $mResult = $oAccount;
5935: $mResult->RefreshToken = \Aurora\System\Api::UserSession()->UpdateTimestamp(\Aurora\System\Api::getAuthToken(), time());
5936: \Aurora\System\Api::LogEvent('password-change-success: ' . $oAccount->Email, self::GetName());
5937: \Aurora\System\Api::UserSession()->DeleteAllUserSessions($oUser->Id);
5938: }
5939: }
5940: }
5941: }
5942: if (!$mResult) {
5943: \Aurora\System\Api::LogEvent('password-change-failed: ' . ($oAccount ? $oAccount->Email : 'Account ID ') . $AccountId, self::GetName());
5944: }
5945:
5946: return $mResult;
5947: }
5948:
5949: /**
5950: * @api {post} ?/Api/ GetFilters
5951: * @apiName GetFilters
5952: * @apiGroup Mail
5953: * @apiDescription Obtains filters for specified account.
5954: *
5955: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
5956: * @apiHeaderExample {json} Header-Example:
5957: * {
5958: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
5959: * }
5960: *
5961: * @apiParam {string=Mail} Module Module name
5962: * @apiParam {string=GetFilters} Method Method name
5963: * @apiParam {string} [Parameters] JSON.stringified object<br>
5964: * {<br>
5965: * &emsp; **AccountID** *int* Account identifier.<br>
5966: * }
5967: *
5968: * @apiParamExample {json} Request-Example:
5969: * {
5970: * Module: 'Mail',
5971: * Method: 'GetFilters',
5972: * Parameters: '{ "AccountID": 12 }'
5973: * }
5974: *
5975: * @apiSuccess {object[]} Result Array of response objects.
5976: * @apiSuccess {string} Result.Module Module name.
5977: * @apiSuccess {string} Result.Method Method name.
5978: * @apiSuccess {mixed} Result.Result List of filters in case of success, otherwise **false**.
5979: * @apiSuccess {int} [Result.ErrorCode] Error code
5980: *
5981: * @apiSuccessExample {json} Success response example:
5982: * {
5983: * Module: 'Mail',
5984: * Method: 'GetFilters',
5985: * Result: []
5986: * }
5987: *
5988: * @apiSuccessExample {json} Error response example:
5989: * {
5990: * Module: 'Mail',
5991: * Method: 'GetFilters',
5992: * Result: false,
5993: * ErrorCode: 102
5994: * }
5995: */
5996: /**
5997: * Obtains filters for specified account.
5998: * @param int $AccountID Account identifier.
5999: * @return array|boolean
6000: */
6001: public function GetFilters($AccountID)
6002: {
6003: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
6004:
6005: $mResult = false;
6006:
6007: $oAccount = $this->getAccountsManager()->getAccountById((int) $AccountID);
6008:
6009: self::checkAccess($oAccount);
6010:
6011: if ($oAccount) {
6012: $mResult = $this->getSieveManager()->getSieveFilters($oAccount);
6013: }
6014:
6015: return $mResult;
6016: }
6017:
6018: /**
6019: * @api {post} ?/Api/ UpdateFilters
6020: * @apiName UpdateFilters
6021: * @apiGroup Mail
6022: * @apiDescription Updates filters.
6023: *
6024: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
6025: * @apiHeaderExample {json} Header-Example:
6026: * {
6027: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
6028: * }
6029: *
6030: * @apiParam {string=Mail} Module Module name
6031: * @apiParam {string=UpdateFilters} Method Method name
6032: * @apiParam {string} Parameters JSON.stringified object<br>
6033: * {<br>
6034: * &emsp; **AccountID** *int* Account identifier<br>
6035: * &emsp; **Filters** *array* New filters data.<br>
6036: * }
6037: *
6038: * @apiParamExample {json} Request-Example:
6039: * {
6040: * Module: 'Mail',
6041: * Method: 'UpdateFilters',
6042: * Parameters: '{ "AccountID": 12, "Filters": [ { "Enable": "1", "Field": 0, "Filter": "test",
6043: * "Condition": 0, "Action": 3, "FolderFullName": "test" } ] }'
6044: * }
6045: *
6046: * @apiSuccess {object[]} Result Array of response objects.
6047: * @apiSuccess {string} Result.Module Module name.
6048: * @apiSuccess {string} Result.Method Method name.
6049: * @apiSuccess {boolean} Result.Result Indicates if filters were updated successfully.
6050: * @apiSuccess {int} [Result.ErrorCode] Error code
6051: *
6052: * @apiSuccessExample {json} Success response example:
6053: * {
6054: * Module: 'Mail',
6055: * Method: 'UpdateFilters',
6056: * Result: true
6057: * }
6058: *
6059: * @apiSuccessExample {json} Error response example:
6060: * {
6061: * Module: 'Mail',
6062: * Method: 'UpdateFilters',
6063: * Result: false,
6064: * ErrorCode: 102
6065: * }
6066: */
6067: /**
6068: * Updates filters.
6069: * @param int $AccountID Account identifier
6070: * @param array $Filters New filters data.
6071: * @return boolean
6072: */
6073: public function UpdateFilters($AccountID, $Filters)
6074: {
6075: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
6076:
6077: $bResult = false;
6078:
6079: $oAccount = $this->getAccountsManager()->getAccountById((int) $AccountID);
6080:
6081: self::checkAccess($oAccount);
6082:
6083: if ($oAccount) {
6084: $aFilters = array();
6085:
6086: if (is_array($Filters)) {
6087: foreach ($Filters as $aFilterData) {
6088: $oFilter = $this->getSieveManager()->createFilterInstance($oAccount, $aFilterData);
6089:
6090: $aArgs = [
6091: 'Account' => $oAccount,
6092: 'Filter' => &$oFilter,
6093: ];
6094: $this->broadcastEvent('CreateFilterInstance', $aArgs);
6095:
6096: if ($oFilter) {
6097: $aFilters[] = $oFilter;
6098: }
6099: }
6100: }
6101:
6102: $bResult = $this->getSieveManager()->updateSieveFilters($oAccount, $aFilters);
6103: }
6104:
6105: return $bResult;
6106: }
6107:
6108: /**
6109: * @api {post} ?/Api/ GetForward
6110: * @apiName GetForward
6111: * @apiGroup Mail
6112: * @apiDescription Obtains forward data for specified account.
6113: *
6114: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
6115: * @apiHeaderExample {json} Header-Example:
6116: * {
6117: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
6118: * }
6119: *
6120: * @apiParam {string=Mail} Module Module name
6121: * @apiParam {string=GetForward} Method Method name
6122: * @apiParam {string} Parameters JSON.stringified object<br>
6123: * {<br>
6124: * &emsp; **AccountID** *int* Account identifier.<br>
6125: * }
6126: *
6127: * @apiParamExample {json} Request-Example:
6128: * {
6129: * Module: 'Mail',
6130: * Method: 'GetForward',
6131: * Parameters: '{ "AccountID": 12 }'
6132: * }
6133: *
6134: * @apiSuccess {object[]} Result Array of response objects.
6135: * @apiSuccess {string} Result.Module Module name.
6136: * @apiSuccess {string} Result.Method Method name.
6137: * @apiSuccess {mixed} Result.Result Forward properties in case of success, otherwise **false**.
6138: * @apiSuccess {boolean} Result.Result.Enable Indicates if forward is enabled.
6139: * @apiSuccess {string} Result.Result.Email Forward email.
6140: * @apiSuccess {int} [Result.ErrorCode] Error code
6141: *
6142: * @apiSuccessExample {json} Success response example:
6143: * {
6144: * Module: 'Mail',
6145: * Method: 'GetForward',
6146: * Result: { "Enable": false, "Email": "" }
6147: * }
6148: *
6149: * @apiSuccessExample {json} Error response example:
6150: * {
6151: * Module: 'Mail',
6152: * Method: 'GetForward',
6153: * Result: false,
6154: * ErrorCode: 102
6155: * }
6156: */
6157: /**
6158: * Obtains forward data for specified account.
6159: * @param int $AccountID Account identifier.
6160: * @return array|boolean
6161: */
6162: public function GetForward($AccountID)
6163: {
6164: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
6165:
6166: $mResult = false;
6167:
6168: $oAccount = $this->getAccountsManager()->getAccountById((int) $AccountID);
6169:
6170: self::checkAccess($oAccount);
6171:
6172: if ($oAccount) {
6173: $mResult = $this->getSieveManager()->getForward($oAccount);
6174: }
6175:
6176: return $mResult;
6177: }
6178:
6179: /**
6180: * @api {post} ?/Api/ UpdateForward
6181: * @apiName UpdateForward
6182: * @apiGroup Mail
6183: * @apiDescription Updates forward.
6184: *
6185: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
6186: * @apiHeaderExample {json} Header-Example:
6187: * {
6188: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
6189: * }
6190: *
6191: * @apiParam {string=Mail} Module Module name
6192: * @apiParam {string=UpdateForward} Method Method name
6193: * @apiParam {string} Parameters JSON.stringified object<br>
6194: * {<br>
6195: * &emsp; **AccountID** *int* Account identifier.<br>
6196: * &emsp; **Enable** *boolean* Indicates if forward is enabled.<br>
6197: * &emsp; **Email** *string* Email that should be used for message forward.<br>
6198: * }
6199: *
6200: * @apiParamExample {json} Request-Example:
6201: * {
6202: * Module: 'Mail',
6203: * Method: 'UpdateForward',
6204: * Parameters: '{ "AccountID": 12, "Enable": true, "Email": "test2@email" }'
6205: * }
6206: *
6207: * @apiSuccess {object[]} Result Array of response objects.
6208: * @apiSuccess {string} Result.Module Module name.
6209: * @apiSuccess {string} Result.Method Method name.
6210: * @apiSuccess {boolean} Result.Result Indicates if server was updated successfully.
6211: * @apiSuccess {int} [Result.ErrorCode] Error code
6212: *
6213: * @apiSuccessExample {json} Success response example:
6214: * {
6215: * Module: 'Mail',
6216: * Method: 'UpdateForward',
6217: * Result: true
6218: * }
6219: *
6220: * @apiSuccessExample {json} Error response example:
6221: * {
6222: * Module: 'Mail',
6223: * Method: 'UpdateForward',
6224: * Result: false,
6225: * ErrorCode: 102
6226: * }
6227: */
6228: /**
6229: * Updates forward.
6230: * @param int $AccountID Account identifier.
6231: * @param boolean $Enable Indicates if forward is enabled.
6232: * @param string $Email Email that should be used for message forward.
6233: * @return boolean
6234: */
6235: public function UpdateForward($AccountID, $Enable = false, $Email = "")
6236: {
6237: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
6238:
6239: $mResult = false;
6240:
6241: $oAccount = $this->getAccountsManager()->getAccountById((int) $AccountID);
6242:
6243: self::checkAccess($oAccount);
6244:
6245: if ($oAccount) {
6246: $mResult = $this->getSieveManager()->setForward($oAccount, $Email, $Enable);
6247: }
6248:
6249: return $mResult;
6250: }
6251:
6252: /**
6253: * @api {post} ?/Api/ GetAutoresponder
6254: * @apiName GetAutoresponder
6255: * @apiGroup Mail
6256: * @apiDescription Obtains autoresponder for specified account.
6257: *
6258: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
6259: * @apiHeaderExample {json} Header-Example:
6260: * {
6261: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
6262: * }
6263: *
6264: * @apiParam {string=Mail} Module Module name
6265: * @apiParam {string=GetAutoresponder} Method Method name
6266: * @apiParam {string} Parameters JSON.stringified object<br>
6267: * {<br>
6268: * &emsp; **AccountID** *int* Account identifier.<br>
6269: * }
6270: *
6271: * @apiParamExample {json} Request-Example:
6272: * {
6273: * Module: 'Mail',
6274: * Method: 'GetAutoresponder',
6275: * Parameters: '{ "AccountID": 12 }'
6276: * }
6277: *
6278: * @apiSuccess {object[]} Result Array of response objects.
6279: * @apiSuccess {string} Result.Module Module name.
6280: * @apiSuccess {string} Result.Method Method name.
6281: * @apiSuccess {mixed} Result.Result Autoresponder properties in case of success, otherwise **false**.
6282: * @apiSuccess {boolean} Result.Result.Enable Indicates if autoresponder is enabled.
6283: * @apiSuccess {string} Result.Result.Subject Subject of auto-respond message.
6284: * @apiSuccess {string} Result.Result.Message Text of auto-respond message.
6285: * @apiSuccess {int} [Result.ErrorCode] Error code
6286: *
6287: * @apiSuccessExample {json} Success response example:
6288: * {
6289: * Module: 'Mail',
6290: * Method: 'GetAutoresponder',
6291: * Result: { Enable: false, Subject: "", Message: "" }
6292: * }
6293: *
6294: * @apiSuccessExample {json} Error response example:
6295: * {
6296: * Module: 'Mail',
6297: * Method: 'GetAutoresponder',
6298: * Result: false,
6299: * ErrorCode: 102
6300: * }
6301: */
6302: /**
6303: * Obtains autoresponder for specified account.
6304: * @param int $AccountID Account identifier.
6305: * @return array|boolean
6306: */
6307: public function GetAutoresponder($AccountID)
6308: {
6309: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
6310:
6311: $mResult = false;
6312:
6313: $oAccount = $this->getAccountsManager()->getAccountById((int) $AccountID);
6314:
6315: self::checkAccess($oAccount);
6316:
6317: if ($oAccount) {
6318: $mResult = $this->getSieveManager()->getAutoresponder($oAccount);
6319: }
6320:
6321: return $mResult;
6322: }
6323:
6324: /**
6325: * @api {post} ?/Api/ UpdateAutoresponder
6326: * @apiName UpdateAutoresponder
6327: * @apiGroup Mail
6328: * @apiDescription Updates autoresponder data.
6329: *
6330: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
6331: * @apiHeaderExample {json} Header-Example:
6332: * {
6333: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
6334: * }
6335: *
6336: * @apiParam {string=Mail} Module Module name
6337: * @apiParam {string=UpdateAutoresponder} Method Method name
6338: * @apiParam {string} Parameters JSON.stringified object<br>
6339: * {<br>
6340: * &emsp; **AccountID** *int* Account identifier.<br>
6341: * &emsp; **Enable** *boolean* Indicates if autoresponder is enabled.<br>
6342: * &emsp; **Subject** *string* Subject of auto-respond message.<br>
6343: * &emsp; **Message** *string* Text of auto-respond message.<br>
6344: * }
6345: *
6346: * @apiParamExample {json} Request-Example:
6347: * {
6348: * Module: 'Mail',
6349: * Method: 'UpdateAutoresponder',
6350: * Parameters: '{ "AccountID": 12, "Enable": true, "Subject": "subject_value", "Text": "text_value" }'
6351: * }
6352: *
6353: * @apiSuccess {object[]} Result Array of response objects.
6354: * @apiSuccess {string} Result.Module Module name.
6355: * @apiSuccess {string} Result.Method Method name.
6356: * @apiSuccess {boolean} Result.Result Indicates if Autoresponder was updated successfully.
6357: * @apiSuccess {int} [Result.ErrorCode] Error code
6358: *
6359: * @apiSuccessExample {json} Success response example:
6360: * {
6361: * Module: 'Mail',
6362: * Method: 'UpdateAutoresponder',
6363: * Result: true
6364: * }
6365: *
6366: * @apiSuccessExample {json} Error response example:
6367: * {
6368: * Module: 'Mail',
6369: * Method: 'UpdateAutoresponder',
6370: * Result: false,
6371: * ErrorCode: 102
6372: * }
6373: */
6374: /**
6375: * Updates autoresponder data.
6376: * @param int $AccountID Account identifier.
6377: * @param boolean $Enable Indicates if autoresponder is enabled.
6378: * @param string $Subject Subject of auto-respond message.
6379: * @param string $Message Text of auto-respond message.
6380: * @return boolean
6381: */
6382: public function UpdateAutoresponder($AccountID, $Enable = false, $Subject = "", $Message = "")
6383: {
6384: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
6385:
6386: $mResult = false;
6387:
6388: $oAccount = $this->getAccountsManager()->getAccountById((int) $AccountID);
6389:
6390: self::checkAccess($oAccount);
6391:
6392: if ($Enable && \trim($Subject) === "" && \trim($Message) === "") {
6393: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
6394: }
6395:
6396: if ($oAccount) {
6397: $mResult = $this->getSieveManager()->setAutoresponder($oAccount, $Subject, $Message, $Enable);
6398: }
6399:
6400: return $mResult;
6401: }
6402:
6403: public function SetAccountSpamSettings($AccountID, $SpamScore, $AllowList, $BlockList)
6404: {
6405: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
6406:
6407: $mResult = false;
6408:
6409: $oAccount = $this->getAccountsManager()->getAccountById((int) $AccountID);
6410:
6411: self::checkAccess($oAccount);
6412:
6413: if ($oAccount) {
6414: $mResult = $this->getSieveManager()->setAllowBlockLists($oAccount, $AllowList, $BlockList, $SpamScore);
6415: }
6416:
6417: return $mResult;
6418: }
6419:
6420: public function GetAccountSpamSettings($AccountID)
6421: {
6422: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
6423:
6424: $mResult = false;
6425:
6426: $oAccount = $this->getAccountsManager()->getAccountById((int) $AccountID);
6427:
6428: self::checkAccess($oAccount);
6429:
6430: if ($oAccount) {
6431: $mResult = $this->getSieveManager()->getAllowBlockLists($oAccount);
6432: }
6433:
6434: return $mResult;
6435: }
6436:
6437: public function AddEmailToAllowList($AccountID, $Email)
6438: {
6439: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
6440:
6441: $mResult = false;
6442:
6443: $oAccount = $this->getAccountsManager()->getAccountById((int) $AccountID);
6444:
6445: self::checkAccess($oAccount);
6446:
6447: if ($oAccount) {
6448: $mResult = $this->getSieveManager()->addRowToAllowList($oAccount, $Email);
6449: }
6450:
6451: return $mResult;
6452: }
6453:
6454: public function AddEmailToBlockList($AccountID, $Email)
6455: {
6456: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
6457:
6458: $mResult = false;
6459:
6460: $oAccount = $this->getAccountsManager()->getAccountById((int) $AccountID);
6461:
6462: self::checkAccess($oAccount);
6463:
6464: if ($oAccount) {
6465: $mResult = $this->getSieveManager()->addRowToBlockList($oAccount, $Email);
6466: }
6467:
6468: return $mResult;
6469: }
6470: /***** public functions might be called with web API *****/
6471:
6472: /***** private functions *****/
6473:
6474: /**
6475: * Deletes all mail accounts which are belonged to the specified user.
6476: * Called from subscribed event.
6477: * @ignore
6478: * @param array $aArgs
6479: * @param int $mResult User identifier.
6480: */
6481: public function onBeforeDeleteUser($aArgs, &$mResult)
6482: {
6483: $mResult = $this->getAccountsManager()->getUserAccounts($aArgs["UserId"]);
6484:
6485: foreach ($mResult as $oItem) {
6486: self::Decorator()->DeleteAccount($oItem->Id);
6487: }
6488: }
6489:
6490: public function onAfterDeleteUser($aArgs, &$mResult)
6491: {
6492: if ($mResult) {
6493: Identity::where('IdUser', $aArgs["UserId"])->delete();
6494: TrustedSender::where('IdUser', $aArgs["UserId"])->delete();
6495: }
6496: }
6497:
6498: /**
6499: * Obtains a server object for the specified domain.
6500: * @param string $Domain
6501: * @param bool $AllowWildcardDomain the parameter indicates whether the wildcard server should be returned if no servers found
6502: * @return array
6503: */
6504: public function GetMailServerByDomain($Domain, $AllowWildcardDomain = false)
6505: {
6506: $aResult = [];
6507: $bFoundWithWildcard = false;
6508:
6509: $oServer = $this->getServersManager()->getServerByDomain($Domain);
6510:
6511: if (!($oServer instanceof \Aurora\Modules\Mail\Models\Server) && $AllowWildcardDomain) {
6512: $oServer = $this->getServersManager()->getServerByDomain('*');
6513: $bFoundWithWildcard = true;
6514: }
6515:
6516: if (!($oServer instanceof \Aurora\Modules\Mail\Models\Server) && $AllowWildcardDomain) {
6517: $oServer = $this->getServersManager()->getServerByDomain('');
6518: $bFoundWithWildcard = true;
6519: }
6520:
6521: if ($oServer instanceof \Aurora\Modules\Mail\Models\Server) {
6522: $aResult = [
6523: 'Server' => $oServer,
6524: 'FoundWithWildcard' => $bFoundWithWildcard
6525: ];
6526: }
6527:
6528: return $aResult;
6529: }
6530:
6531: /**
6532: * Attempts to authorize user via mail account with specified credentials.
6533: * Called from subscribed event.
6534: * @ignore
6535: * @param array $aArgs Credentials.
6536: * @param array|boolean $mResult List of results values.
6537: * @return boolean
6538: */
6539: public function onLogin($aArgs, &$mResult)
6540: {
6541: $bResult = false;
6542: $iUserId = 0;
6543:
6544: $sEmail = $aArgs['Login'];
6545: $sMailLogin = $aArgs['Login'];
6546: $oAccount = $this->getAccountsManager()->getAccountUsedToAuthorize($sEmail);
6547:
6548: $bNewAccount = false;
6549: $bAutocreateMailAccountOnNewUserFirstLogin = $this->getConfig('AutocreateMailAccountOnNewUserFirstLogin', false);
6550: if (!$bAutocreateMailAccountOnNewUserFirstLogin && !$oAccount) {
6551: $oUser = \Aurora\System\Api::GetModuleDecorator('Core')->GetUserByPublicId($sEmail);
6552: if ($oUser instanceof \Aurora\Modules\Core\Models\User) {
6553: $bAutocreateMailAccountOnNewUserFirstLogin = true;
6554: }
6555: }
6556:
6557: $oServer = null;
6558: if ($bAutocreateMailAccountOnNewUserFirstLogin && !$oAccount) {
6559: $sDomain = \MailSo\Base\Utils::GetDomainFromEmail($sEmail);
6560: if (!empty(trim($sDomain))) {
6561: $aGetMailServerResult = self::Decorator()->GetMailServerByDomain($sDomain, /*AllowWildcardDomain*/true);
6562: if (!empty($aGetMailServerResult) && isset($aGetMailServerResult['Server']) && $aGetMailServerResult['Server'] instanceof \Aurora\Modules\Mail\Models\Server) {
6563: $oServer = $aGetMailServerResult['Server'];
6564: }
6565:
6566: $oTenant = \Aurora\System\Api::getTenantByWebDomain();
6567: if ($oServer && (!$oTenant || $oServer->OwnerType === \Aurora\Modules\Mail\Enums\ServerOwnerType::SuperAdmin || $oServer->TenantId === $oTenant->Id)) {
6568: $sMailLogin = !$oServer->UseFullEmailAddressAsLogin && preg_match('/(.+)@.+$/', $sEmail, $matches) && $matches[1] ? $matches[1] : $sEmail;
6569:
6570: $oAccount = new \Aurora\Modules\Mail\Models\MailAccount();
6571: $oAccount->Email = $sEmail;
6572: $oAccount->IncomingLogin = $sMailLogin;
6573: $oAccount->setPassword($aArgs['Password']);
6574: $oAccount->ServerId = $oServer->Id;
6575: $bNewAccount = true;
6576: } else {
6577: throw new \Aurora\System\Exceptions\ApiException(
6578: Enums\ErrorCodes::DomainIsNotAllowedForLoggingIn,
6579: null,
6580: '',
6581: [],
6582: $this
6583: );
6584: }
6585: }
6586: }
6587:
6588: if ($oAccount instanceof \Aurora\Modules\Mail\Models\MailAccount) {
6589: try {
6590: if ($bAutocreateMailAccountOnNewUserFirstLogin || !$bNewAccount) {
6591: $sOldPassword = $oAccount->getPassword();
6592: $sNewPassword = $aArgs['Password'];
6593:
6594: $oAccount->setPassword($sNewPassword);
6595: $mValidResult = $this->getMailManager()->validateAccountConnection($oAccount, false);
6596: $bResult = !($mValidResult instanceof \Exception);
6597: if ($bResult && $sNewPassword !== $sOldPassword) {
6598: // Update password in DB only if account passed connection validation
6599: $this->getAccountsManager()->updateAccount($oAccount);
6600: }
6601: }
6602:
6603: if ($bResult && $bAutocreateMailAccountOnNewUserFirstLogin && $bNewAccount) {
6604: $oUser = null;
6605: $aSubArgs = array(
6606: 'UserName' => $sEmail,
6607: 'Email' => $sEmail,
6608: 'UserId' => $iUserId,
6609: 'TenantId' => $oServer->TenantId
6610: );
6611: $this->broadcastEvent(
6612: 'CreateAccount',
6613: $aSubArgs,
6614: $oUser
6615: );
6616:
6617: if ($oUser instanceof \Aurora\Modules\Core\Models\User) {
6618: $iUserId = $oUser->Id;
6619: $bPrevState = \Aurora\System\Api::skipCheckUserRole(true);
6620: $oAccount = self::Decorator()->CreateAccount(
6621: $iUserId,
6622: '',
6623: $sEmail,
6624: $sMailLogin,
6625: $aArgs['Password'],
6626: array('ServerId' => $oServer->Id)
6627: );
6628: \Aurora\System\Api::skipCheckUserRole($bPrevState);
6629: if ($oAccount) {
6630: $oAccount->UseToAuthorize = true;
6631: $oAccount->UseThreading = $oServer->EnableThreading;
6632: $bResult = $this->getAccountsManager()->updateAccount($oAccount);
6633: } else {
6634: $bResult = false;
6635: }
6636: }
6637: }
6638:
6639: if ($bResult) {
6640: $mResult = \Aurora\System\UserSession::getTokenData($oAccount, $aArgs['SignMe']);
6641: }
6642: } catch (\Aurora\System\Exceptions\ApiException $oException) {
6643: throw $oException;
6644: } catch (\Exception $oException) {
6645: }
6646: }
6647:
6648: return $bResult;
6649: }
6650:
6651: /**
6652: *
6653: * @param array $aArgs
6654: * @param array $aResult
6655: */
6656: public function onGetAccounts($aArgs, &$aResult)
6657: {
6658: $aUserInfo = \Aurora\System\Api::getAuthenticatedUserInfo($aArgs['AuthToken']);
6659: if (isset($aUserInfo['userId'])) {
6660: $mResult = $this->GetAccounts($aUserInfo['userId']);
6661: if (\is_array($mResult)) {
6662: foreach ($mResult as $oItem) {
6663: $aResult[] = [
6664: 'Type' => $oItem->getName(),
6665: 'Module' => $oItem->getModule(),
6666: 'Id' => $oItem->Id,
6667: 'UUID' => $oItem->UUID,
6668: 'Login' => $oItem->IncomingLogin
6669: ];
6670: }
6671: }
6672: }
6673: }
6674:
6675: /**
6676: * Puts on or off some flag of message.
6677: * @param int $AccountID account identifier.
6678: * @param string $sFolderFullNameRaw Folder full name.
6679: * @param string $sUids List of messages' uids.
6680: * @param boolean $bSetAction Indicates if flag should be set or removed.
6681: * @param string $sFlagName Name of message flag.
6682: * @return boolean
6683: * @throws \Aurora\System\Exceptions\ApiException
6684: */
6685: private function setMessageFlag($AccountID, $sFolderFullNameRaw, $sUids, $bSetAction, $sFlagName)
6686: {
6687: $aUids = \Aurora\System\Utils::ExplodeIntUids((string) $sUids);
6688:
6689: if (0 === \strlen(\trim($sFolderFullNameRaw)) || !\is_array($aUids) || 0 === \count($aUids)) {
6690: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
6691: }
6692:
6693: $oAccount = $this->getAccountsManager()->getAccountById($AccountID);
6694:
6695: return $this->getMailManager()->setMessageFlag(
6696: $oAccount,
6697: $sFolderFullNameRaw,
6698: $aUids,
6699: $sFlagName,
6700: $bSetAction ? \Aurora\Modules\Mail\Enums\MessageStoreAction::Add : \Aurora\Modules\Mail\Enums\MessageStoreAction::Remove
6701: );
6702: }
6703:
6704: /**
6705: * When using a memory stream and the read
6706: * filter "convert.base64-encode" the last
6707: * character is missing from the output if
6708: * the base64 conversion needs padding bytes.
6709: * @param string $sRaw
6710: * @return string
6711: */
6712: private function fixBase64EncodeOmitsPaddingBytes($sRaw)
6713: {
6714: $rStream = \fopen('php://memory', 'r+');
6715: \fwrite($rStream, '0');
6716: \rewind($rStream);
6717: $rFilter = \stream_filter_append($rStream, 'convert.base64-encode');
6718:
6719: if (0 === \strlen(\stream_get_contents($rStream))) {
6720: $iFileSize = \strlen($sRaw);
6721: $sRaw = \str_pad($sRaw, $iFileSize + ($iFileSize % 3));
6722: }
6723:
6724: return $sRaw;
6725: }
6726:
6727: /**
6728: * Builds message for further sending or saving.
6729: * @param \Aurora\Modules\StandardAuth\Models\MailAccount $oAccount
6730: * @param string $sTo Message recipients.
6731: * @param string $sCc Recipients which will get a copy of the message.
6732: * @param string $sBcc Recipients which will get a hidden copy of the message.
6733: * @param string $sSubject Subject of the message.
6734: * @param boolean $bTextIsHtml Indicates if text of the message is HTML or plain.
6735: * @param string $sText Text of the message.
6736: * @param array $aAttachments List of attachments.
6737: * @param array $aDraftInfo Contains information about the original message which is replied or forwarded: message type (reply/forward), UID and folder.
6738: * @param string $sInReplyTo Value of **In-Reply-To** header which is supplied in replies/forwards and contains Message-ID of the original message. This approach allows for organizing threads.
6739: * @param string $sReferences Content of References header block of the message.
6740: * @param int $iImportance Importance of the message - LOW = 5, NORMAL = 3, HIGH = 1.
6741: * @param int $iSensitivity Sensitivity header for the message, its value will be returned: 1 for "Confidential", 2 for "Private", 3 for "Personal".
6742: * @param boolean $bSendReadingConfirmation Indicates if it is necessary to include header that says
6743: * @param object $oFetcher
6744: * @param object $oAlias
6745: * @param boolean $bWithDraftInfo
6746: * @param \Aurora\Modules\Mail\Models\Identity $oIdentity
6747: * @param array $aCustomHeaders
6748: * @return \MailSo\Mime\Message
6749: */
6750: public function BuildMessage(
6751: $oAccount,
6752: $sTo = '',
6753: $sCc = '',
6754: $sBcc = '',
6755: $sSubject = '',
6756: $bTextIsHtml = false,
6757: $sText = '',
6758: $aAttachments = null,
6759: $aDraftInfo = null,
6760: $sInReplyTo = '',
6761: $sReferences = '',
6762: $iImportance = '',
6763: $iSensitivity = 0,
6764: $bSendReadingConfirmation = false,
6765: $oFetcher = null,
6766: $oAlias = null,
6767: $bWithDraftInfo = true,
6768: $oIdentity = null,
6769: $aCustomHeaders = []
6770: ) {
6771: self::checkAccess($oAccount);
6772:
6773: $oMessage = \MailSo\Mime\Message::NewInstance();
6774: $oMessage->RegenerateMessageId();
6775:
6776: $sUUID = \Aurora\System\Api::getUserUUIDById($oAccount->IdUser);
6777:
6778: $sXMailer = $this->getConfig('XMailerValue', '');
6779: if (0 < \strlen($sXMailer)) {
6780: $oMessage->SetXMailer($sXMailer);
6781: }
6782:
6783: $sXOriginatingIPHeaderName = $this->getConfig('XOriginatingIPHeaderName', '');
6784: if (!empty($sXOriginatingIPHeaderName)) {
6785: $sIP = $this->oHttp->GetClientIp();
6786: $oMessage->SetCustomHeader(
6787: $sXOriginatingIPHeaderName,
6788: $this->oHttp->IsLocalhost($sIP) ? '127.0.0.1' : $sIP
6789: );
6790: }
6791:
6792: if ($oIdentity) {
6793: $oFrom = \MailSo\Mime\Email::NewInstance($oIdentity->Email, $oIdentity->FriendlyName);
6794: } elseif ($oAlias) {
6795: $oFrom = \MailSo\Mime\Email::NewInstance($oAlias->Email, $oAlias->FriendlyName);
6796: } else {
6797: $oFrom = $oFetcher
6798: ? \MailSo\Mime\Email::NewInstance($oFetcher->Email, $oFetcher->Name)
6799: : \MailSo\Mime\Email::NewInstance($oAccount->Email, $oAccount->FriendlyName);
6800: }
6801:
6802: $oMessage
6803: ->SetFrom($oFrom)
6804: ->SetSubject($sSubject)
6805: ;
6806:
6807: $oToEmails = \MailSo\Mime\EmailCollection::NewInstance($sTo);
6808: if ($oToEmails && $oToEmails->Count()) {
6809: $oMessage->SetTo($oToEmails);
6810: }
6811:
6812: $oCcEmails = \MailSo\Mime\EmailCollection::NewInstance($sCc);
6813: if ($oCcEmails && $oCcEmails->Count()) {
6814: $oMessage->SetCc($oCcEmails);
6815: }
6816:
6817: $oBccEmails = \MailSo\Mime\EmailCollection::NewInstance($sBcc);
6818: if ($oBccEmails && $oBccEmails->Count()) {
6819: $oMessage->SetBcc($oBccEmails);
6820: }
6821:
6822: if ($bWithDraftInfo && \is_array($aDraftInfo) && !empty($aDraftInfo[0]) && !empty($aDraftInfo[1]) && !empty($aDraftInfo[2])) {
6823: $oMessage->SetDraftInfo($aDraftInfo[0], $aDraftInfo[1], $aDraftInfo[2]);
6824: }
6825:
6826: if (0 < \strlen($sInReplyTo)) {
6827: $oMessage->SetInReplyTo($sInReplyTo);
6828: }
6829:
6830: if (0 < \strlen($sReferences)) {
6831: $oMessage->SetReferences($sReferences);
6832: }
6833:
6834: if (\in_array($iImportance, array(
6835: \MailSo\Mime\Enumerations\MessagePriority::HIGH,
6836: \MailSo\Mime\Enumerations\MessagePriority::NORMAL,
6837: \MailSo\Mime\Enumerations\MessagePriority::LOW
6838: ))) {
6839: $oMessage->SetPriority($iImportance);
6840: }
6841:
6842: if (\in_array($iSensitivity, array(
6843: \MailSo\Mime\Enumerations\Sensitivity::NOTHING,
6844: \MailSo\Mime\Enumerations\Sensitivity::CONFIDENTIAL,
6845: \MailSo\Mime\Enumerations\Sensitivity::PRIVATE_,
6846: \MailSo\Mime\Enumerations\Sensitivity::PERSONAL,
6847: ))) {
6848: $oMessage->SetSensitivity((int) $iSensitivity);
6849: }
6850:
6851: if (is_array($aCustomHeaders)) {
6852: foreach ($aCustomHeaders as $sHeaderName => $sHeaderValue) {
6853: $oMessage->SetCustomHeader($sHeaderName, $sHeaderValue);
6854: }
6855: }
6856:
6857: if ($bSendReadingConfirmation) {
6858: $oMessage->SetReadConfirmation($oFetcher ? $oFetcher->Email : $oAccount->Email);
6859: }
6860:
6861: $aFoundCids = array();
6862:
6863: if ($bTextIsHtml) {
6864: $sTextConverted = \MailSo\Base\HtmlUtils::ConvertHtmlToPlain($sText);
6865: $oMessage->AddText($sTextConverted, false);
6866: }
6867:
6868: $mFoundDataURL = array();
6869: $aFoundedContentLocationUrls = array();
6870:
6871: $sTextConverted = $bTextIsHtml ?
6872: \MailSo\Base\HtmlUtils::BuildHtml($sText, $aFoundCids, $mFoundDataURL, $aFoundedContentLocationUrls) : $sText;
6873:
6874: $oMessage->AddText($sTextConverted, $bTextIsHtml);
6875:
6876: if (\is_array($aAttachments)) {
6877: foreach ($aAttachments as $sTempName => $aData) {
6878: if (\is_array($aData) && isset($aData[0], $aData[1], $aData[2], $aData[3])) {
6879: $sFileName = (string) $aData[0];
6880: $sCID = (string) $aData[1];
6881: $bIsInline = '1' === (string) $aData[2];
6882: $bIsLinked = '1' === (string) $aData[3];
6883: $sContentLocation = isset($aData[4]) ? (string) $aData[4] : '';
6884:
6885: $rResource = $this->getFilecacheManager()->getFile($sUUID, $sTempName);
6886: if (\is_resource($rResource)) {
6887: $iFileSize = $this->getFilecacheManager()->fileSize($sUUID, $sTempName);
6888:
6889: $sCID = \trim(\trim($sCID), '<>');
6890: $bIsFounded = 0 < \strlen($sCID) ? \in_array($sCID, $aFoundCids) : false;
6891:
6892: if (!$bIsLinked || $bIsFounded) {
6893: $oMessage->Attachments()->Add(
6894: \MailSo\Mime\Attachment::NewInstance(
6895: $rResource,
6896: $sFileName,
6897: $iFileSize,
6898: $bIsInline,
6899: $bIsLinked,
6900: $bIsLinked ? '<'.$sCID.'>' : '',
6901: array(),
6902: $sContentLocation
6903: )
6904: );
6905: }
6906: } else {
6907: \Aurora\System\Api::Log('Error: there is no temp file for attachment ' . $sFileName);
6908: }
6909: }
6910: }
6911: }
6912:
6913: if ($mFoundDataURL && \is_array($mFoundDataURL) && 0 < \count($mFoundDataURL)) {
6914: foreach ($mFoundDataURL as $sCidHash => $sDataUrlString) {
6915: $aMatch = array();
6916: $sCID = '<'.$sCidHash.'>';
6917: if (\preg_match('/^data:(image\/[a-zA-Z0-9]+\+?[a-zA-Z0-9]+);base64,(.+)$/i', $sDataUrlString, $aMatch) &&
6918: !empty($aMatch[1]) && !empty($aMatch[2])) {
6919: $sRaw = \MailSo\Base\Utils::Base64Decode($aMatch[2]);
6920: $iFileSize = \strlen($sRaw);
6921: if (0 < $iFileSize) {
6922: $sFileName = \preg_replace('/[^a-z0-9]+/i', '.', \MailSo\Base\Utils::NormalizeContentType($aMatch[1]));
6923:
6924: // fix bug #68532 php < 5.5.21 or php < 5.6.5
6925: $sRaw = $this->fixBase64EncodeOmitsPaddingBytes($sRaw);
6926:
6927: $rResource = \MailSo\Base\ResourceRegistry::CreateMemoryResourceFromString($sRaw);
6928:
6929: $sRaw = '';
6930: unset($sRaw);
6931: unset($aMatch);
6932:
6933: $oMessage->Attachments()->Add(
6934: \MailSo\Mime\Attachment::NewInstance($rResource, $sFileName, $iFileSize, true, true, $sCID)
6935: );
6936: }
6937: }
6938: }
6939: }
6940:
6941: return $oMessage;
6942: }
6943:
6944: public function onAfterDeleteTenant(&$aArgs, &$mResult)
6945: {
6946: $TenantId = $aArgs['TenantId'];
6947: $aServers = self::Decorator()->GetServers($TenantId);
6948: if (is_array($aServers) && $aServers['Count'] > 0) {
6949: foreach ($aServers['Items'] as $oServer) {
6950: if ($oServer['TenantId'] === $TenantId) {
6951: self::Decorator()->DeleteServer($oServer['Id'], $TenantId);
6952: }
6953: }
6954: }
6955: }
6956:
6957: public function onAfterGetAutodiscover(&$aArgs, &$mResult)
6958: {
6959: $sIncomingServer = \trim($this->getConfig('ExternalHostNameOfLocalImap'));
6960: $sOutgoingServer = \trim($this->getConfig('ExternalHostNameOfLocalSmtp'));
6961: $sEmail = $aArgs['Email'];
6962:
6963: if (0 < \strlen($sIncomingServer) && 0 < \strlen($sOutgoingServer)) {
6964: $iIncomingPort = 143;
6965: $iOutgoingPort = 25;
6966:
6967: $aMatch = array();
6968: if (\preg_match('/:([\d]+)$/', $sIncomingServer, $aMatch) && !empty($aMatch[1]) && \is_numeric($aMatch[1])) {
6969: $sIncomingServer = \preg_replace('/:[\d]+$/', $sIncomingServer, '');
6970: $iIncomingPort = (int) $aMatch[1];
6971: }
6972:
6973: $aMatch = array();
6974: if (\preg_match('/:([\d]+)$/', $sOutgoingServer, $aMatch) && !empty($aMatch[1]) && \is_numeric($aMatch[1])) {
6975: $sOutgoingServer = \preg_replace('/:[\d]+$/', $sOutgoingServer, '');
6976: $iOutgoingPort = (int) $aMatch[1];
6977: }
6978:
6979: $sResult = \implode("\n", array(
6980: ' <Account>',
6981: ' <AccountType>email</AccountType>',
6982: ' <Action>settings</Action>',
6983: ' <Protocol>',
6984: ' <Type>IMAP</Type>',
6985: ' <Server>'.$sIncomingServer.'</Server>',
6986: ' <LoginName>'.$sEmail.'</LoginName>',
6987: ' <Port>'.$iIncomingPort.'</Port>',
6988: ' <SSL>'.(993 === $iIncomingPort ? 'on' : 'off').'</SSL>',
6989: ' <SPA>off</SPA>',
6990: ' <AuthRequired>on</AuthRequired>',
6991: ' </Protocol>',
6992: ' <Protocol>',
6993: ' <Type>SMTP</Type>',
6994: ' <Server>'.$sOutgoingServer.'</Server>',
6995: ' <LoginName>'.$sEmail.'</LoginName>',
6996: ' <Port>'.$iOutgoingPort.'</Port>',
6997: ' <SSL>'.(465 === $iOutgoingPort ? 'on' : 'off').'</SSL>',
6998: ' <SPA>off</SPA>',
6999: ' <AuthRequired>on</AuthRequired>',
7000: ' </Protocol>',
7001: ' </Account>'
7002: ));
7003: $mResult = $mResult . $sResult;
7004: }
7005: }
7006:
7007: public function EntryMessageNewtab()
7008: {
7009: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
7010:
7011: $oApiIntegrator = \Aurora\System\Managers\Integrator::getInstance();
7012:
7013: if ($oApiIntegrator) {
7014: \Aurora\Modules\CoreWebclient\Module::Decorator()->SetHtmlOutputHeaders();
7015: $aConfig = array(
7016: 'new_tab' => true,
7017: 'modules_list' => $oApiIntegrator->GetModulesForEntry('MailWebclient')
7018: );
7019:
7020: $oCoreWebclientModule = \Aurora\System\Api::GetModule('CoreWebclient');
7021: if ($oCoreWebclientModule instanceof \Aurora\System\Module\AbstractModule) {
7022: $sResult = \file_get_contents($oCoreWebclientModule->GetPath().'/templates/Index.html');
7023: if (\is_string($sResult)) {
7024: return strtr($sResult, array(
7025: '{{AppVersion}}' => AU_APP_VERSION,
7026: '{{IntegratorDir}}' => $oApiIntegrator->isRtl() ? 'rtl' : 'ltr',
7027: '{{IntegratorLinks}}' => $oApiIntegrator->buildHeadersLink(),
7028: '{{IntegratorBody}}' => $oApiIntegrator->buildBody($aConfig)
7029: ));
7030: }
7031: }
7032: }
7033: }
7034:
7035: public function EntryDownloadAttachment()
7036: {
7037: $sHash = (string) \Aurora\System\Router::getItemByIndex(1, '');
7038: $aValues = \Aurora\System\Api::DecodeKeyValues($sHash);
7039: $sAuthToken = isset($aValues['AuthToken']) ? $aValues['AuthToken'] : null;
7040: if (isset($sAuthToken)) {
7041: \Aurora\System\Api::setUserId(
7042: \Aurora\System\Api::getAuthenticatedUserId($sAuthToken)
7043: );
7044: \Aurora\System\Api::setAuthToken($sAuthToken);
7045: }
7046:
7047: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
7048:
7049: if ($this->getConfig('CleanupOutputBeforeDownload', false)) {
7050: @ob_clean(); // discard any data in the output buffer (if possible)
7051: }
7052:
7053: $this->getRaw(
7054: $sHash,
7055: (string) \Aurora\System\Router::getItemByIndex(2, '')
7056: );
7057: }
7058:
7059: public function onBeforeRunEntry(&$aArguments, &$aResult)
7060: {
7061: $sEntry = 'mail-attachment';
7062: if ($aArguments['EntryName'] === $sEntry) {
7063: $sParam3 = \Aurora\System\Router::getItemByIndex(3, null);
7064: if (isset($sParam3) && $sParam3 === 'get-expired-link') {
7065: $sHash = (string) \Aurora\System\Router::getItemByIndex(1, '');
7066: $sAction = (string) \Aurora\System\Router::getItemByIndex(2, '');
7067: $iTime = $this->getConfig('ExpiredLinkLifetimeMinutes ', 30);
7068:
7069: $aValues = \Aurora\System\Api::DecodeKeyValues($sHash);
7070:
7071: if (!isset($aValues['AuthToken'])) {
7072: $aValues['AuthToken'] = \Aurora\System\Api::UserSession()->Set(
7073: array(
7074: 'token' => 'auth',
7075: 'id' => \Aurora\System\Api::getAuthenticatedUserId(),
7076: ),
7077: time(),
7078: time() + 60 * $iTime
7079: );
7080:
7081: $sHash = \Aurora\System\Api::EncodeKeyValues($aValues);
7082: }
7083:
7084: \header('Location: ' . \MailSo\Base\Http::SingletonInstance()->GetFullUrl() . '?' . $sEntry .'/' . $sHash . '/' . $sAction);
7085: }
7086: }
7087: }
7088:
7089: public function EntryDownloadAttachmentCookieless()
7090: {
7091: $sAuthToken = $_GET['AuthToken'];
7092:
7093: $re = '/^[a-zA-Z0-9_-]+$/';
7094: $bSafeToken = preg_match($re, $sAuthToken);
7095:
7096: if ($sAuthToken !== '' && !!$bSafeToken) {
7097: \Aurora\System\Api::authorise($sAuthToken);
7098: $this->EntryDownloadAttachment();
7099: }
7100: }
7101:
7102: /**
7103: * @param string $sHash
7104: * @param string $sAction
7105: * @return boolean
7106: */
7107: private function getRaw($sHash, $sAction = '')
7108: {
7109: $self = $this;
7110: $bDownload = true;
7111: $bThumbnail = false;
7112:
7113: switch ($sAction) {
7114: case 'view':
7115: $bDownload = false;
7116: $bThumbnail = false;
7117: break;
7118: case 'thumb':
7119: $bDownload = false;
7120: $bThumbnail = true;
7121: break;
7122: default:
7123: $bDownload = true;
7124: $bThumbnail = false;
7125: break;
7126: }
7127:
7128: $aValues = \Aurora\System\Api::DecodeKeyValues($sHash);
7129:
7130: $sFolder = '';
7131: $iUid = 0;
7132: $sMimeIndex = '';
7133:
7134: $oAccount = null;
7135:
7136: $iUserId = null;
7137:
7138: if (isset($aValues['AccountID'])) {
7139: $oAccount = $this->getAccountsManager()->getAccountById((int) $aValues['AccountID']);
7140:
7141: self::checkAccess($oAccount);
7142:
7143: if (!$oAccount || \Aurora\System\Api::getAuthenticatedUserId() !== $oAccount->IdUser) {
7144: return false;
7145: }
7146: $iUserId = $oAccount->IdUser;
7147: }
7148:
7149: $sFolder = isset($aValues['Folder']) ? $aValues['Folder'] : '';
7150: $iUid = (int) (isset($aValues['Uid']) ? $aValues['Uid'] : 0);
7151: $sMimeIndex = (string) (isset($aValues['MimeIndex']) ? $aValues['MimeIndex'] : '');
7152: $sContentTypeIn = (string) (isset($aValues['MimeType']) ? $aValues['MimeType'] : '');
7153: $sFileNameIn = (string) (isset($aValues['FileName']) ? $aValues['FileName'] : '');
7154:
7155: // SVG files should not be viewed because they may contain JS
7156: if (!$bDownload && strtolower(pathinfo($sFileNameIn, PATHINFO_EXTENSION)) === 'svg') {
7157: $this->oHttp->StatusHeader(403);
7158: exit();
7159: }
7160:
7161: $bCache = true;
7162: if ($bCache && 0 < \strlen($sFolder) && 0 < $iUid) {
7163: \Aurora\System\Managers\Response::verifyCacheByKey($sHash);
7164: }
7165:
7166: if ($bThumbnail) {
7167: $sThumbnail = \Aurora\System\Managers\Thumb::GetResourceCache($iUserId, $sFileNameIn);
7168: if ($sThumbnail) {
7169: $sContentType = \MailSo\Base\Utils::MimeContentType($sFileNameIn);
7170: \Aurora\System\Managers\Response::OutputHeaders($bDownload, $sContentType, $sFileNameIn);
7171: echo $sThumbnail;
7172: exit();
7173: }
7174: }
7175:
7176: return $this->getMailManager()->directMessageToStream(
7177: $oAccount,
7178: function ($rResource, $sContentType, $sFileName, $sMimeIndex = '') use ($self, $iUserId, $sHash, $bCache, $sContentTypeIn, $sFileNameIn, $bThumbnail, $bDownload) {
7179: if (\is_resource($rResource)) {
7180: $sContentTypeOut = $sContentTypeIn;
7181: if (empty($sContentTypeOut)) {
7182: $sContentTypeOut = $sContentType;
7183: if (empty($sContentTypeOut)) {
7184: $sContentTypeOut = (empty($sFileName)) ? 'text/plain' : \MailSo\Base\Utils::MimeContentType($sFileName);
7185: }
7186: }
7187:
7188: $sFileNameOut = $sFileNameIn;
7189: if (empty($sFileNameOut) || '.' === $sFileNameOut[0]) {
7190: $sFileNameOut = $sFileName;
7191: }
7192:
7193: $sFileNameOut = \Aurora\System\Utils::clearFileName($sFileNameOut, $sContentType, $sMimeIndex);
7194:
7195: if ($bCache) {
7196: \Aurora\System\Managers\Response::cacheByKey($sHash);
7197: }
7198:
7199: \Aurora\System\Utils::OutputFileResource($iUserId, $sContentType, $sFileName, $rResource, $bThumbnail, $bDownload);
7200: }
7201: },
7202: $sFolder,
7203: $iUid,
7204: $sMimeIndex
7205: );
7206: }
7207:
7208: public function onGetDigestHash($aArgs, &$mResult)
7209: {
7210: $oAccount = $this->getAccountsManager()->getAccountUsedToAuthorize($aArgs['Login']);
7211: if (is_a($oAccount, $aArgs['Type'])) {
7212: $mResult = \md5($aArgs['Login'] . ':' . $aArgs['Realm'] . ':' . $oAccount->GetPassword());
7213: return true;
7214: }
7215: }
7216:
7217: public function onGetAccountUsedToAuthorize($aArgs, &$mResult)
7218: {
7219: $oAccount = $this->getAccountsManager()->getAccountUsedToAuthorize($aArgs['Login']);
7220: if ($oAccount) {
7221: $mResult = $oAccount;
7222: return true;
7223: }
7224: }
7225:
7226: public function onCastExtendedProp($aArgs, &$mValue)
7227: {
7228: if ($aArgs['Model'] instanceof User) {
7229: if ($aArgs['PropertyName'] === $this->GetName() . '::UserSpaceLimitMb') {
7230: $mValue = (int) $mValue;
7231: }
7232: if ($aArgs['PropertyName'] === $this->GetName() . '::AllowAutosaveInDrafts') {
7233: $mValue = (bool) $mValue;
7234: }
7235: }
7236:
7237: if ($aArgs['Model'] instanceof Tenant) {
7238: if ($aArgs['PropertyName'] === $this->GetName() . '::TenantSpaceLimitMb' ||
7239: $aArgs['PropertyName'] === $this->GetName() . '::UserSpaceLimitMb' ||
7240: $aArgs['PropertyName'] === $this->GetName() . '::AllocatedSpaceMb'
7241: ) {
7242: $mValue = (int) $mValue;
7243: }
7244: if ($aArgs['PropertyName'] === $this->GetName() . '::AllowChangeUserSpaceLimit') {
7245: $mValue = (bool) $mValue;
7246: }
7247: }
7248: }
7249:
7250: public function GetServerDomains($ServerId, $TenantId)
7251: {
7252: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
7253: $aResult = [];
7254:
7255: $oServer = $this->getServersManager()->getServer($ServerId);
7256: if ($oServer instanceof Models\Server) {
7257: $aResult = explode("\n", $oServer->Domains);
7258: $iWildcard = array_search('*', $aResult);
7259: if ($iWildcard !== false) {
7260: unset($aResult[$iWildcard]);
7261: }
7262: }
7263:
7264: return $aResult;
7265: }
7266:
7267: public function IsEmailAllowedForCreation($Email)
7268: {
7269: //Method available only for admin or tenant-admin
7270: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
7271: if (
7272: $oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::SuperAdmin
7273: || $oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::TenantAdmin
7274: ) {
7275: $oUser = \Aurora\System\Api::GetModuleDecorator('Core')->GetUserByPublicId($Email);
7276: if ($oUser instanceof \Aurora\Modules\Core\Models\User) {
7277: return false;
7278: }
7279: $aAccounts = $this->getAccountsManager()->getAccounts([
7280: 'Email' => $Email,
7281: 'IsDisabled' => false
7282: ]);
7283: if (is_array($aAccounts) && count($aAccounts) > 0) {
7284: return false;
7285: }
7286:
7287: return true;
7288: } else {
7289: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::AccessDenied);
7290: }
7291: }
7292:
7293: /***** private functions *****/
7294: }
7295: