|   1:  | <?php | 
|   2:  |  | 
|   3:  |  | 
|   4:  |  | 
|   5:  |  | 
|   6:  |  | 
|   7:  |  | 
|   8:  | namespace Aurora\Modules\ImportExportMailPlugin; | 
|   9:  |  | 
|  10:  |  | 
|  11:  |  | 
|  12:  |  | 
|  13:  |  | 
|  14:  |  | 
|  15:  |  | 
|  16:  |  | 
|  17:  | class Module extends \Aurora\System\Module\AbstractModule | 
|  18:  | { | 
|  19:  |      | 
|  20:  |  | 
|  21:  |  | 
|  22:  |     public $oFilecacheManager = null; | 
|  23:  |     public $sLogPrefix = 'plugin-import-export-mail-'; | 
|  24:  |  | 
|  25:  |     public function init() | 
|  26:  |     { | 
|  27:  |         $this->aErrors = [ | 
|  28:  |             Enums\ErrorCodes::UnknownError	=> $this->i18N('UNKNOWN_ERROR'), | 
|  29:  |             Enums\ErrorCodes::ErrorSizeLimit	=> $this->i18N('ERROR_SIZE_LIMIT', ['SIZE' => $this->getConfig('UploadSizeLimitMb', 0)]) | 
|  30:  |         ]; | 
|  31:  |  | 
|  32:  |         $this->AddEntry('transfer-mail', 'EntryTransferMail'); | 
|  33:  |     } | 
|  34:  |  | 
|  35:  |      | 
|  36:  |  | 
|  37:  |  | 
|  38:  |  | 
|  39:  |  | 
|  40:  |     public function GetSettings() | 
|  41:  |     { | 
|  42:  |         \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous); | 
|  43:  |  | 
|  44:  |         return [ | 
|  45:  |             'AllowZip' => class_exists('ZipArchive'), | 
|  46:  |             'UploadSizeLimitMb' => $this->getConfig('UploadSizeLimitMb', 0) | 
|  47:  |         ]; | 
|  48:  |     } | 
|  49:  |  | 
|  50:  |      | 
|  51:  |  | 
|  52:  |  | 
|  53:  |  | 
|  54:  |  | 
|  55:  |     public function ExportMailPrepare() | 
|  56:  |     { | 
|  57:  |         \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser); | 
|  58:  |         $mResult = false; | 
|  59:  |         $oUser = \Aurora\System\Api::getAuthenticatedUser(); | 
|  60:  |  | 
|  61:  |         if ($oUser instanceof \Aurora\Modules\Core\Models\User) { | 
|  62:  |             $sZipName = \md5(\time().\rand(1000, 9999)); | 
|  63:  |             $mResult = [ | 
|  64:  |                 'Zip' => $sZipName, | 
|  65:  |             ]; | 
|  66:  |             $this->getFilecacheManager()->put($oUser->PublicId, $sZipName, '', '.zip'); | 
|  67:  |             $this->getFilecacheManager()->put($oUser->PublicId, $sZipName, 'prepare', '.info'); | 
|  68:  |         } | 
|  69:  |  | 
|  70:  |         return $mResult; | 
|  71:  |     } | 
|  72:  |  | 
|  73:  |      | 
|  74:  |  | 
|  75:  |  | 
|  76:  |  | 
|  77:  |  | 
|  78:  |  | 
|  79:  |  | 
|  80:  |  | 
|  81:  |  | 
|  82:  |     public function ExportMailGenerate($AccountId, $Folder, $Zip) | 
|  83:  |     { | 
|  84:  |         \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser); | 
|  85:  |         $bResult = false; | 
|  86:  |         $oUser = \Aurora\System\Api::getAuthenticatedUser(); | 
|  87:  |  | 
|  88:  |         if ($oUser instanceof \Aurora\Modules\Core\Models\User) { | 
|  89:  |             $sUserPublicId = $oUser->PublicId; | 
|  90:  |             try { | 
|  91:  |                 $aTempFiles = []; | 
|  92:  |  | 
|  93:  |                 $this->getFilecacheManager()->put($oUser->PublicId, $Zip, 'generate', '.info'); | 
|  94:  |                 $oAccount = \Aurora\System\Api::GetModule('Mail')->GetAccount($AccountId); | 
|  95:  |  | 
|  96:  |                 if ($Folder !== null && $Zip !== null | 
|  97:  |                     && $oAccount | 
|  98:  |                     && $oAccount->IdUser === $oUser->Id) { | 
|  99:  |                     $oApiMail = $this->getMailManager(); | 
| 100:  |                     $iOffset = 0; | 
| 101:  |                     $iLimit = 20; | 
| 102:  |  | 
| 103:  |                     $sZipFilePath = $this->getFilecacheManager()->generateFullFilePath($sUserPublicId, $Zip, '.zip'); | 
| 104:  |                     $rZipResource = fopen($sZipFilePath, 'w+b'); | 
| 105:  |                     $oZip = new \ZipStream\ZipStream(null, [\ZipStream\ZipStream::OPTION_OUTPUT_STREAM => $rZipResource]); | 
| 106:  |                     $this->Log('Start fetching mail'); | 
| 107:  |  | 
| 108:  |                     $self = $this; | 
| 109:  |  | 
| 110:  |                     $aData = $oApiMail->getFolderInformation($oAccount, $Folder); | 
| 111:  |                     $iCount = (is_array($aData) && 4 === count($aData)) ? $aData[0] : 0; | 
| 112:  |  | 
| 113:  |                     while ($iOffset <= $iCount) { | 
| 114:  |                         $oMessageListCollection =  $oApiMail->getMessageList($oAccount, $Folder, $iOffset, $iLimit); | 
| 115:  |                         $oMessageListCollection->ForeachList(function ($oMessage) use ($oApiMail, $sUserPublicId, $oAccount, $self, $Folder, &$oZip, &$aTempFiles) { | 
| 116:  |                             $iUid = $oMessage->getUid(); | 
| 117:  |                             $oApiMail->directMessageToStream( | 
| 118:  |                                 $oAccount, | 
| 119:  |                                 function ($rResource, $sContentType, $sFileName, $sMimeIndex = '') use ($sUserPublicId, $self, $iUid, &$oZip, &$aTempFiles) { | 
| 120:  |                                     $sTempName = \md5(\time().\rand(1000, 9999).$sFileName); | 
| 121:  |                                     $aTempFiles[] = $sTempName; | 
| 122:  |  | 
| 123:  |                                     if (is_resource($rResource) && $self->getFilecacheManager()->putFile($sUserPublicId, $sTempName, $rResource)) { | 
| 124:  |                                         $sFilePath = $self->getFilecacheManager()->generateFullFilePath($sUserPublicId, $sTempName); | 
| 125:  |                                         $rSubResource = fopen($sFilePath, 'rb'); | 
| 126:  |                                         if (is_resource($rSubResource)) { | 
| 127:  |                                             $sFileName = 'uid-' . $iUid . '.eml'; | 
| 128:  |                                             $self->Log('Append file \'' . $sFileName . '\' to ZIP'); | 
| 129:  |                                             $oZip->addFileFromStream($sFileName, $rSubResource, [], \ZipStream\ZipStream::METHOD_STORE); | 
| 130:  |                                             $MemoryUsage = memory_get_usage(true)/(1024*1024); | 
| 131:  |                                             $self->Log('Memory usage: ' . $MemoryUsage); | 
| 132:  |                                             @fclose($rSubResource); | 
| 133:  |                                         } | 
| 134:  |                                     } | 
| 135:  |                                 }, | 
| 136:  |                                 $Folder, | 
| 137:  |                                 $iUid | 
| 138:  |                             ); | 
| 139:  |                         }); | 
| 140:  |                         $iOffset = $iOffset + $iLimit; | 
| 141:  |                     } | 
| 142:  |                     $this->Log('End fetching mail'); | 
| 143:  |                     $oZip->finish(); | 
| 144:  |                     $this->Log('Create ZIP file'); | 
| 145:  |                     foreach ($aTempFiles as $sTempName) { | 
| 146:  |                         $this->Log('Remove temp file: ' . $sTempName); | 
| 147:  |                         $self->getFilecacheManager()->clear($sUserPublicId, $sTempName); | 
| 148:  |                     } | 
| 149:  |                 } | 
| 150:  |                 $this->Log('Generating ZIP Result: '); | 
| 151:  |                 $this->getFilecacheManager()->put($sUserPublicId, $Zip, 'ready', '.info'); | 
| 152:  |                 $bResult = true; | 
| 153:  |             } catch (\Exception $oException) { | 
| 154:  |                 $this->getFilecacheManager()->put($sUserPublicId, $Zip, 'error', '.info'); | 
| 155:  |                 $this->Log($oException, true); | 
| 156:  |                 throw $oException; | 
| 157:  |             } | 
| 158:  |         } | 
| 159:  |  | 
| 160:  |         return $bResult; | 
| 161:  |     } | 
| 162:  |  | 
| 163:  |      | 
| 164:  |  | 
| 165:  |  | 
| 166:  |  | 
| 167:  |  | 
| 168:  |  | 
| 169:  |     public function ExportMailStatus($Zip) | 
| 170:  |     { | 
| 171:  |         \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser); | 
| 172:  |         $mResult = false; | 
| 173:  |         $oUser = \Aurora\System\Api::getAuthenticatedUser(); | 
| 174:  |  | 
| 175:  |         if ($oUser instanceof \Aurora\Modules\Core\Models\User) { | 
| 176:  |             if ($this->getFilecacheManager()->isFileExists($oUser->PublicId, $Zip, '.info')) { | 
| 177:  |                 $mResult = [ | 
| 178:  |                     'Status' => $this->getFilecacheManager()->get($oUser->PublicId, $Zip, '.info') | 
| 179:  |                 ]; | 
| 180:  |             } | 
| 181:  |         } | 
| 182:  |  | 
| 183:  |         return $mResult; | 
| 184:  |     } | 
| 185:  |  | 
| 186:  |      | 
| 187:  |  | 
| 188:  |  | 
| 189:  |     public function EntryTransferMail() | 
| 190:  |     { | 
| 191:  |         \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser); | 
| 192:  |  | 
| 193:  |         $sAction = (string) \Aurora\System\Router::getItemByIndex(1, ''); | 
| 194:  |         $sFileName = (string) \Aurora\System\Router::getItemByIndex(2, ''); | 
| 195:  |         if ($sAction === 'export') { | 
| 196:  |             $this->ExportMail($sFileName); | 
| 197:  |         } | 
| 198:  |     } | 
| 199:  |  | 
| 200:  |      | 
| 201:  |  | 
| 202:  |  | 
| 203:  |  | 
| 204:  |  | 
| 205:  |     public function ExportMail($sFileName) | 
| 206:  |     { | 
| 207:  |         \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser); | 
| 208:  |         $oUser = \Aurora\System\Api::getAuthenticatedUser(); | 
| 209:  |         @ob_start(); | 
| 210:  |         ini_set('display_errors', 0); | 
| 211:  |         if ($oUser instanceof \Aurora\Modules\Core\Models\User) { | 
| 212:  |             $this->getFilecacheManager()->put($oUser->PublicId, $sFileName, 'download', '.info'); | 
| 213:  |             $this->Log('Start downloading ZIP file.. '); | 
| 214:  |  | 
| 215:  |             $sZipFilePath = $this->getFilecacheManager()->generateFullFilePath($oUser->PublicId, $sFileName, '.zip'); | 
| 216:  |             $iFileSize = filesize($sZipFilePath); | 
| 217:  |             $this->Log('ZIP file size: ' . $iFileSize); | 
| 218:  |  | 
| 219:  |             header("Content-type: application/zip"); | 
| 220:  |             header("Content-Disposition: attachment; filename=export-mail.zip"); | 
| 221:  |             header('Accept-Ranges: none', true); | 
| 222:  |             header('Content-Transfer-Encoding: binary'); | 
| 223:  |             header("Content-Length: " . $iFileSize); | 
| 224:  |             header("Pragma: no-cache"); | 
| 225:  |             header("Expires: 0"); | 
| 226:  |  | 
| 227:  |             $rZipResource = \fopen($sZipFilePath, 'rb'); | 
| 228:  |             if ($rZipResource !== false) { | 
| 229:  |                 $this->Log('Start write data to buffer'); | 
| 230:  |                 rewind($rZipResource); | 
| 231:  |                 while (!\feof($rZipResource)) { | 
| 232:  |                     $MemoryUsage = memory_get_usage(true)/(1024*1024); | 
| 233:  |                     $this->Log('Write data to buffer - memory usage:' . $MemoryUsage); | 
| 234:  |                     $sBuffer = @\fread($rZipResource, 8192); | 
| 235:  |                     if (false !== $sBuffer) { | 
| 236:  |                         echo $sBuffer; | 
| 237:  |                         ob_flush(); | 
| 238:  |                         flush(); | 
| 239:  |                         \MailSo\Base\Utils::ResetTimeLimit(); | 
| 240:  |                         continue; | 
| 241:  |                     } | 
| 242:  |                     break; | 
| 243:  |                 } | 
| 244:  |                 @\fclose($rZipResource); | 
| 245:  |                 $this->Log('End write data to buffer'); | 
| 246:  |             } else { | 
| 247:  |                 $this->Log("Error. File {$sZipFilePath} not found."); | 
| 248:  |             } | 
| 249:  |             $this->Log('Finish ZIP file downloading'); | 
| 250:  |         } | 
| 251:  |         @ob_get_clean(); | 
| 252:  |         exit; | 
| 253:  |     } | 
| 254:  |  | 
| 255:  |      | 
| 256:  |  | 
| 257:  |  | 
| 258:  |  | 
| 259:  |  | 
| 260:  |  | 
| 261:  |  | 
| 262:  |  | 
| 263:  |  | 
| 264:  |  | 
| 265:  |     public function ImportMail($AccountId, $Folder, $UploadData) | 
| 266:  |     { | 
| 267:  |         \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser); | 
| 268:  |  | 
| 269:  |         $bResult = false; | 
| 270:  |         $oAccount = \Aurora\System\Api::GetModule('Mail')->GetAccount($AccountId); | 
| 271:  |  | 
| 272:  |         if ($oAccount instanceof \Aurora\Modules\Mail\Models\MailAccount && is_array($UploadData)) { | 
| 273:  |             $oUser = \Aurora\System\Api::getAuthenticatedUser(); | 
| 274:  |             if (is_array($UploadData) && $oUser instanceof \Aurora\Modules\Core\Models\User) { | 
| 275:  |                 $iSize = (int) $UploadData['size']; | 
| 276:  |                 $iUploadSizeLimitMb = $this->getConfig('UploadSizeLimitMb', 0); | 
| 277:  |                 if ($iUploadSizeLimitMb > 0 && $iSize/(1024*1024) > $iUploadSizeLimitMb) { | 
| 278:  |                     throw new \Aurora\System\Exceptions\BaseException(Enums\ErrorCodes::ErrorSizeLimit); | 
| 279:  |                 } | 
| 280:  |                 $sUploadName = $UploadData['name']; | 
| 281:  |                 $bIsZipExtension  = strtolower(pathinfo($sUploadName, PATHINFO_EXTENSION)) === 'zip'; | 
| 282:  |                 if ($bIsZipExtension) { | 
| 283:  |                     $sSavedName = 'upload-post-' . md5($UploadData['name'] . $UploadData['tmp_name']); | 
| 284:  |                     if (is_resource($UploadData['tmp_name'])) { | 
| 285:  |                         $this->getFilecacheManager()->putFile($oUser->UUID, $sSavedName, $UploadData['tmp_name']); | 
| 286:  |                     } else { | 
| 287:  |                         $this->getFilecacheManager()->moveUploadedFile($oUser->UUID, $sSavedName, $UploadData['tmp_name']); | 
| 288:  |                     } | 
| 289:  |                     if ($this->getFilecacheManager()->isFileExists($oUser->UUID, $sSavedName)) { | 
| 290:  |                         $sSavedFullName = $this->getFilecacheManager()->generateFullFilePath($oUser->UUID, $sSavedName); | 
| 291:  |                         if (class_exists('ZipArchive')) { | 
| 292:  |                             $oZip = new \ZipArchive(); | 
| 293:  |                             if ($oZip->open($sSavedFullName)) { | 
| 294:  |                                 for ($i = 0; $i < $oZip->numFiles; $i++) { | 
| 295:  |                                     $sFileName = $oZip->getNameIndex($i); | 
| 296:  |                                     if (strtolower(pathinfo($sFileName, PATHINFO_EXTENSION)) === 'eml') { | 
| 297:  |                                         $aFileParams = $oZip->statIndex($i); | 
| 298:  |                                         $iStreamSize = $aFileParams['size']; | 
| 299:  |                                         $rMessage = $oZip->getStream($sFileName); | 
| 300:  |                                         if (is_resource($rMessage)) { | 
| 301:  |                                             $this->getMailManager()->appendMessageFromStream($oAccount, $rMessage, $Folder, $iStreamSize); | 
| 302:  |                                             @fclose($rMessage); | 
| 303:  |                                         } | 
| 304:  |                                     } | 
| 305:  |                                 } | 
| 306:  |                                 $oZip->close(); | 
| 307:  |                                 $bResult = true; | 
| 308:  |                             } | 
| 309:  |                         } else { | 
| 310:  |                             throw new \Aurora\System\Exceptions\BaseException(Enums\ErrorCodes::ZipArchiveClassNotFound); | 
| 311:  |                         } | 
| 312:  |                     } else { | 
| 313:  |                         throw new \Aurora\System\Exceptions\BaseException(Enums\ErrorCodes::UnknownError); | 
| 314:  |                     } | 
| 315:  |                 } | 
| 316:  |             } | 
| 317:  |         } else { | 
| 318:  |             throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter); | 
| 319:  |         } | 
| 320:  |  | 
| 321:  |         return $bResult; | 
| 322:  |     } | 
| 323:  |  | 
| 324:  |      | 
| 325:  |     private function getMailManager() | 
| 326:  |     { | 
| 327:  |         static $oMailManager = null; | 
| 328:  |         if ($oMailManager === null) { | 
| 329:  |             $oMailManager = new \Aurora\Modules\Mail\Managers\Main\Manager($this); | 
| 330:  |         } | 
| 331:  |  | 
| 332:  |         return $oMailManager; | 
| 333:  |     } | 
| 334:  |  | 
| 335:  |     private function getFilecacheManager() | 
| 336:  |     { | 
| 337:  |         if ($this->oFilecacheManager === null) { | 
| 338:  |             $this->oFilecacheManager = new \Aurora\System\Managers\Filecache(); | 
| 339:  |         } | 
| 340:  |  | 
| 341:  |         return $this->oFilecacheManager; | 
| 342:  |     } | 
| 343:  |  | 
| 344:  |     private function Log($mLog, $bIsException = false, $bIsObject = false) | 
| 345:  |     { | 
| 346:  |         if ($bIsException) { | 
| 347:  |             \Aurora\System\Api::LogException($mLog, \Aurora\System\Enums\LogLevel::Full, $this->sLogPrefix); | 
| 348:  |         } elseif ($bIsObject) { | 
| 349:  |             \Aurora\System\Api::LogObject($mLog, \Aurora\System\Enums\LogLevel::Full, $this->sLogPrefix); | 
| 350:  |         } else { | 
| 351:  |             \Aurora\System\Api::Log($mLog, \Aurora\System\Enums\LogLevel::Full, $this->sLogPrefix); | 
| 352:  |         } | 
| 353:  |     } | 
| 354:  | } | 
| 355:  |  |