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