diff --git a/README.md b/README.md index 831e34b7a..d560775a6 100644 --- a/README.md +++ b/README.md @@ -116,23 +116,23 @@ RainLoop 1.15 vs SnappyMail |js/* |RainLoop |Snappy | |--------------- |--------: |--------: | -|admin.js |2.158.025 | 100.608 | -|app.js |4.215.733 | 495.934 | -|boot.js | 672.433 | 4.726 | -|libs.js | 647.679 | 227.974 | +|admin.js |2.158.025 | 94.549 | +|app.js |4.215.733 | 458.762 | +|boot.js | 672.433 | 4.554 | +|libs.js | 647.679 | 218.511 | |polyfills.js | 325.908 | 0 | |serviceworker.js | 0 | 285 | -|TOTAL |8.019.778 | 829.355 | +|TOTAL |8.019.778 | 776.661 | |js/min/* |RainLoop |Snappy |RL gzip |SM gzip |RL brotli |SM brotli | |--------------- |--------: |--------: |------: |------: |--------: |--------: | -|admin.min.js | 255.514 | 50.607 | 73.899 | 14.944 | 60.674 | 13.364 | -|app.min.js | 516.000 | 240.553 |140.430 | 70.291 |110.657 | 59.309 | +|admin.min.js | 255.514 | 49.871 | 73.899 | 14.771 | 60.674 | 13.213 | +|app.min.js | 516.000 | 235.474 |140.430 | 69.223 |110.657 | 58.398 | |boot.min.js | 66.456 | 2.442 | 22.553 | 1.371 | 20.043 | 1.178 | -|libs.min.js | 574.626 | 115.877 |177.280 | 42.809 |151.855 | 38.099 | +|libs.min.js | 574.626 | 106.574 |177.280 | 38.600 |151.855 | 34.532 | |polyfills.min.js | 32.608 | 0 | 11.315 | 0 | 10.072 | 0 | -|TOTAL |1.445.204 | 409.479 |425.477 |129.415 |353.301 |111.950 | -|TOTAL (no admin) |1.189.690 | 358.872 |351.061 |114.471 |292.627 | 98.586 | +|TOTAL |1.445.204 | 394.361 |425.477 |123.965 |353.301 |107.321 | +|TOTAL (no admin) |1.189.690 | 344.490 |351.061 |109.194 |292.627 | 94.108 | For a user its around 66% smaller and faster than traditional RainLoop. @@ -166,12 +166,12 @@ For a user its around 66% smaller and faster than traditional RainLoop. |css/* |RainLoop |Snappy |RL gzip |SM gzip |SM brotli | |------------ |-------: |-------: |------: |------: |--------: | -|app.css | 340.334 | 107.279 | 46,959 | 18.816 | 16.160 | -|app.min.css | 274.791 | 88.402 | 39.618 | 16.831 | 14.827 | +|app.css | 340.334 | 106.864 | 46,959 | 18.751 | 16.110 | +|app.min.css | 274.791 | 88.077 | 39.618 | 16.788 | 14.787 | |boot.css | | 2.066 | | 913 | 742 | |boot.min.css | | 1.696 | | 818 | 664 | -|admin.css | | 46.393 | | 9.237 | 8.073 | -|admin.min.css | | 37.306 | | 8.191 | 7.282 | +|admin.css | | 46.337 | | 9.221 | 8.058 | +|admin.min.css | | 37.251 | | 8.178 | 7.269 | ### Squire vs CKEditor @@ -190,8 +190,3 @@ Still TODO: CKEditor including the 7 asset requests (css,language,plugins,icons) is 633.46 KB / 180.47 KB (gzip). To use the old CKEditor, you must install the plugin. - -### PHP73 branch - -There's a RainLoop 1.14.0 branch with only the PHP 7.3 changes at -https://github.com/the-djmaze/snappymail/tree/php73 diff --git a/dev/App/User.js b/dev/App/User.js index becf923ff..c2b9bd087 100644 --- a/dev/App/User.js +++ b/dev/App/User.js @@ -79,7 +79,6 @@ import { AbstractApp } from 'App/Abstract'; import { ComposePopupView } from 'View/Popup/Compose'; import { FolderSystemPopupView } from 'View/Popup/FolderSystem'; import { AskPopupView } from 'View/Popup/Ask'; -import { TwoFactorConfigurationPopupView } from 'View/Popup/TwoFactorConfiguration'; // Every 5 minutes const refreshFolders = 300000; @@ -187,16 +186,18 @@ class AppUser extends AbstractApp { } MessageUserStore.listLoading(false); }, - FolderUserStore.currentFolderFullNameRaw(), - iOffset, - SettingsUserStore.messagesPerPage(), - MessageUserStore.listSearch(), - MessageUserStore.listThreadUid() + { + Folder: FolderUserStore.currentFolderFullNameRaw(), + Offset: iOffset, + Limit: SettingsUserStore.messagesPerPage(), + Search: MessageUserStore.listSearch(), + ThreadUid: MessageUserStore.listThreadUid() + } ); } recacheInboxMessageList() { - Remote.messageList(()=>{}, getFolderInboxName(), 0, SettingsUserStore.messagesPerPage(), '', '', true); + Remote.messageList(null, {Folder: getFolderInboxName()}, true); } /** @@ -910,136 +911,124 @@ class AppUser extends AbstractApp { rl.setWindowTitle(); if (SettingsGet('Auth')) { - if ( - Settings.capa(Capa.TwoFactor) && - Settings.capa(Capa.TwoFactorForce) && - SettingsGet('RequireTwoFactor') - ) { - this.bootend(); - showScreenPopup(TwoFactorConfigurationPopupView, [true]); - } else { - rl.setWindowTitle(i18n('GLOBAL/LOADING')); + rl.setWindowTitle(i18n('GLOBAL/LOADING')); - // require.ensure([], function() { // require code splitting + this.foldersReload(value => { + try { + this.bootend(); - this.foldersReload(value => { - try { - this.bootend(); - - if (value) { - if (startupUrl) { - rl.route.setHash(root(startupUrl), true); - } - - if (window.crypto && crypto.getRandomValues && Settings.capa(Capa.OpenPGP)) { - const openpgpCallback = () => { - if (!window.openpgp) { - return false; - } - PgpUserStore.openpgp = openpgp; - - if (window.Worker) { - try { - PgpUserStore.openpgp.initWorker({ path: openPgpWorkerJs() }); - } catch (e) { - console.error(e); - } - } - - PgpUserStore.openpgpKeyring = new openpgp.Keyring(); - PgpUserStore.capaOpenPGP(true); - - this.reloadOpenPgpKeys(); - - return true; - }; - - if (!openpgpCallback()) { - const script = createElement('script', {src:openPgpJs()}); - script.onload = openpgpCallback; - script.onerror = () => console.error(script.src); - doc.head.append(script); - } - } else { - PgpUserStore.capaOpenPGP(false); - } - - startScreens([ - MailBoxUserScreen, - Settings.capa(Capa.Settings) ? SettingsUserScreen : null - // false ? AboutUserScreen : null - ]); - - setInterval(() => { - const cF = FolderUserStore.currentFolderFullNameRaw(), - iF = getFolderInboxName(); - this.folderInformation(iF); - if (iF !== cF) { - this.folderInformation(cF); - } - this.folderInformationMultiply(); - }, refreshFolders); - - // Every 15 minutes - setInterval(this.quota, 900000); - // Every 20 minutes - setInterval(this.foldersReload, 1200000); - - setTimeout(this.contactsSync, 10000); - contactsSyncInterval = 5 <= contactsSyncInterval ? contactsSyncInterval : 20; - contactsSyncInterval = 320 >= contactsSyncInterval ? contactsSyncInterval : 320; - setInterval(this.contactsSync, contactsSyncInterval * 60000 + 5000); - - this.accountsAndIdentities(true); - - setTimeout(() => { - const cF = FolderUserStore.currentFolderFullNameRaw(); - if (getFolderInboxName() !== cF) { - this.folderInformation(cF); - } - this.folderInformationMultiply(true); - }, 1000); - - setTimeout(this.quota, 5000); - setTimeout(() => Remote.appDelayStart(()=>{}), 35000); - - // When auto-login is active - if ( - !!SettingsGet('AccountSignMe') && - navigator.registerProtocolHandler && - Settings.capa(Capa.Composer) - ) { - setTimeout(() => { - try { - navigator.registerProtocolHandler( - 'mailto', - location.protocol + '//' + location.host + location.pathname + '?mailto&to=%s', - (SettingsGet('Title') || 'SnappyMail') - ); - } catch (e) {} // eslint-disable-line no-empty - - if (SettingsGet('MailToEmail')) { - mailToHelper(SettingsGet('MailToEmail')); - } - }, 500); - } - - ['touchstart','mousedown','mousemove','keydown'].forEach( - t => doc.addEventListener(t, SettingsUserStore.delayLogout, {passive:true}) - ); - SettingsUserStore.delayLogout(); - - setTimeout(() => this.initVerticalLayoutResizer(), 1); - } else { - this.logout(); + if (value) { + if (startupUrl) { + rl.route.setHash(root(startupUrl), true); } - } catch (e) { - console.error(e); - } - }); - // }); // require code splitting - } + if (window.crypto && crypto.getRandomValues && Settings.capa(Capa.OpenPGP)) { + const openpgpCallback = () => { + if (!window.openpgp) { + return false; + } + PgpUserStore.openpgp = openpgp; + + if (window.Worker) { + try { + PgpUserStore.openpgp.initWorker({ path: openPgpWorkerJs() }); + } catch (e) { + console.error(e); + } + } + + PgpUserStore.openpgpKeyring = new openpgp.Keyring(); + PgpUserStore.capaOpenPGP(true); + + this.reloadOpenPgpKeys(); + + return true; + }; + + if (!openpgpCallback()) { + const script = createElement('script', {src:openPgpJs()}); + script.onload = openpgpCallback; + script.onerror = () => console.error(script.src); + doc.head.append(script); + } + } else { + PgpUserStore.capaOpenPGP(false); + } + + startScreens([ + MailBoxUserScreen, + Settings.capa(Capa.Settings) ? SettingsUserScreen : null + // false ? AboutUserScreen : null + ]); + + setInterval(() => { + const cF = FolderUserStore.currentFolderFullNameRaw(), + iF = getFolderInboxName(); + this.folderInformation(iF); + if (iF !== cF) { + this.folderInformation(cF); + } + this.folderInformationMultiply(); + }, refreshFolders); + + // Every 15 minutes + setInterval(this.quota, 900000); + // Every 20 minutes + setInterval(this.foldersReload, 1200000); + + setTimeout(this.contactsSync, 10000); + contactsSyncInterval = 5 <= contactsSyncInterval ? contactsSyncInterval : 20; + contactsSyncInterval = 320 >= contactsSyncInterval ? contactsSyncInterval : 320; + setInterval(this.contactsSync, contactsSyncInterval * 60000 + 5000); + + this.accountsAndIdentities(true); + + setTimeout(() => { + const cF = FolderUserStore.currentFolderFullNameRaw(); + if (getFolderInboxName() !== cF) { + this.folderInformation(cF); + } + this.folderInformationMultiply(true); + }, 1000); + + setTimeout(this.quota, 5000); + setTimeout(() => Remote.appDelayStart(()=>{}), 35000); + + // When auto-login is active + if ( + !!SettingsGet('AccountSignMe') && + navigator.registerProtocolHandler && + Settings.capa(Capa.Composer) + ) { + setTimeout(() => { + try { + navigator.registerProtocolHandler( + 'mailto', + location.protocol + '//' + location.host + location.pathname + '?mailto&to=%s', + (SettingsGet('Title') || 'SnappyMail') + ); + } catch (e) {} // eslint-disable-line no-empty + + if (SettingsGet('MailToEmail')) { + mailToHelper(SettingsGet('MailToEmail')); + } + }, 500); + } + + ['touchstart','mousedown','mousemove','keydown'].forEach( + t => doc.addEventListener(t, SettingsUserStore.delayLogout, {passive:true}) + ); + SettingsUserStore.delayLogout(); + + setTimeout(() => this.initVerticalLayoutResizer(), 1); + } else { + this.logout(); + } + } catch (e) { + console.error(e); + } + }); + } else { this.bootend(); startScreens([LoginUserScreen]); diff --git a/dev/Common/Enums.js b/dev/Common/Enums.js index 84b7f5598..eafe441df 100644 --- a/dev/Common/Enums.js +++ b/dev/Common/Enums.js @@ -4,8 +4,6 @@ * @enum {string} */ export const Capa = { - TwoFactor: 'TWO_FACTOR', - TwoFactorForce: 'TWO_FACTOR_FORCE', OpenPGP: 'OPEN_PGP', Prefetch: 'PREFETCH', Composer: 'COMPOSER', @@ -86,9 +84,6 @@ export const Notification = { DomainNotAllowed: 109, AccountNotAllowed: 110, - AccountTwoFactorAuthRequired: 120, - AccountTwoFactorAuthError: 121, - ContactsSyncError: 140, CantGetMessageList: 201, diff --git a/dev/Common/EnumsUser.js b/dev/Common/EnumsUser.js index 19d382c70..9ede882ee 100644 --- a/dev/Common/EnumsUser.js +++ b/dev/Common/EnumsUser.js @@ -14,6 +14,22 @@ export const FolderType = { User: 99 }; +/** + * @enum {string} + */ +export const FolderSortMode = { + DateDesc: '', // default 'REVERSE DATE' + DateAsc: 'DATE', + FromDesc: 'REVERSE FROM', + FromAsc: 'FROM', + SizeDesc: 'REVERSE SIZE', + SizeAsc: 'SIZE', + SubjectDesc: 'REVERSE SUBJECT', + SubjectAsc: 'SUBJECT' +// ToDesc: 'REVERSE TO', +// ToAsc: 'TO', +}; + /** * @enum {string} */ diff --git a/dev/Common/File.js b/dev/Common/File.js index 70622c862..28bc2943f 100644 --- a/dev/Common/File.js +++ b/dev/Common/File.js @@ -11,113 +11,109 @@ const sizes = ['B', 'KiB', 'MiB', 'GiB', 'TiB'], exts = { - eml: 'message/rfc822', - mime: 'message/rfc822', - rtx: 'text/richtext', - vcard: 'text/vcard', - vcf: 'text/vcard', - htm: 'text/html', - html: 'text/html', - csv: 'text/csv', - ics: 'text/calendar', - ifb: 'text/calendar', - xml: 'text/xml', - json: app+'json', - p10: app+'pkcs10', - p7c: app+'pkcs7-mime', - p7m: app+'pkcs7-mime', - p7s: app+'pkcs7-signature', - torrent: app+'x-bittorrent', + eml: 'message/rfc822', + mime: 'message/rfc822', + vcard: 'text/vcard', + vcf: 'text/vcard', + htm: 'text/html', + html: 'text/html', + csv: 'text/csv', + ics: 'text/calendar', + xml: 'text/xml', + json: app+'json', + asc: app+'pgp-signature', + p10: app+'pkcs10', + p7c: app+'pkcs7-mime', + p7m: app+'pkcs7-mime', + p7s: app+'pkcs7-signature', + torrent: app+'x-bittorrent', - // scripts - js: app+'javascript', - pl: 'text/perl', - css: 'text/css', - asp: 'text/asp', - php: app+'x-httpd-php', - phtml: app+'x-httpd-php', + // scripts + js: app+'javascript', + pl: 'text/perl', + css: 'text/css', + asp: 'text/asp', + php: app+'x-php', - // images - jpg: 'image/jpeg', - ico: 'image/x-icon', - tif: 'image/tiff', - svg: 'image/svg+xml', - svgz: 'image/svg+xml', + // images + jpg: 'image/jpeg', + ico: 'image/x-icon', + tif: 'image/tiff', + svg: 'image/svg+xml', + svgz: 'image/svg+xml', - // archives - zip: app+'zip', - '7z': app+'x-7z-compressed', - rar: app+'x-rar-compressed', - cab: app+'vnd.ms-cab-compressed', - gz: app+'x-gzip', - tgz: app+'x-gzip', - bz: app+'x-bzip', - bz2: app+'x-bzip2', - deb: app+'x-debian-package', + // archives + zip: app+'zip', + '7z': app+'x-7z-compressed', + rar: app+'x-rar-compressed', + cab: app+'vnd.ms-cab-compressed', + gz: app+'x-gzip', + tgz: app+'x-gzip', + bz: app+'x-bzip', + bz2: app+'x-bzip2', + deb: app+'x-debian-package', - // audio - mp3: 'audio/mpeg', - wav: 'audio/x-wav', - mp4a: 'audio/mp4', - weba: 'audio/webm', - m3u: 'audio/x-mpegurl', + // audio + mp3: 'audio/mpeg', + wav: 'audio/x-wav', + mp4a: 'audio/mp4', + weba: 'audio/webm', + m3u: 'audio/x-mpegurl', - // video - qt: 'video/quicktime', - mov: 'video/quicktime', - wmv: 'video/windows-media', - avi: 'video/x-msvideo', - '3gp': 'video/3gpp', - '3g2': 'video/3gpp2', - mp4v: 'video/mp4', - mpg4: 'video/mp4', - ogv: 'video/ogg', - m4v: 'video/x-m4v', - asf: 'video/x-ms-asf', - asx: 'video/x-ms-asf', - wm: 'video/x-ms-wm', - wmx: 'video/x-ms-wmx', - wvx: 'video/x-ms-wvx', - movie: 'video/x-sgi-movie', + // video + qt: 'video/quicktime', + mov: 'video/quicktime', + wmv: 'video/windows-media', + avi: 'video/x-msvideo', + '3gp': 'video/3gpp', + '3g2': 'video/3gpp2', + mp4v: 'video/mp4', + mpg4: 'video/mp4', + ogv: 'video/ogg', + m4v: 'video/x-m4v', + asf: 'video/x-ms-asf', + asx: 'video/x-ms-asf', + wm: 'video/x-ms-wm', + wmx: 'video/x-ms-wmx', + wvx: 'video/x-ms-wvx', + movie: 'video/x-sgi-movie', - // adobe - pdf: app+'pdf', - psd: 'image/vnd.adobe.photoshop', - ai: app+'postscript', - eps: app+'postscript', - ps: app+'postscript', + // adobe + pdf: app+'pdf', + psd: 'image/vnd.adobe.photoshop', + ai: app+'postscript', + eps: app+'postscript', + ps: app+'postscript', - // ms office - doc: app+'msword', - rtf: app+'rtf', - xls: app+'vnd.ms-excel', - ppt: app+'vnd.ms-powerpoint', - docx: msOffice+'wordprocessingml.document', - xlsx: msOffice+'spreadsheetml.sheet', - dotx: msOffice+'wordprocessingml.template', - pptx: msOffice+'presentationml.presentation', + // ms office + doc: app+'msword', + rtf: app+'rtf', + xls: app+'vnd.ms-excel', + ppt: app+'vnd.ms-powerpoint', + docx: msOffice+'wordprocessingml.document', + xlsx: msOffice+'spreadsheetml.sheet', + dotx: msOffice+'wordprocessingml.template', + pptx: msOffice+'presentationml.presentation', - // open office - odt: openDoc+'text', - ods: openDoc+'spreadsheet', - odp: openDoc+'presentation' -}; + // open office + odt: openDoc+'text', + ods: openDoc+'spreadsheet', + odp: openDoc+'presentation' + }; export const FileType = { Unknown: 'unknown', Text: 'text', - Html: 'html', Code: 'code', Eml: 'eml', - WordText: 'word-text', + Word: 'word', Pdf: 'pdf', Image: 'image', Audio: 'audio', Video: 'video', - Sheet: 'sheet', + Spreadsheet: 'spreadsheet', Presentation: 'presentation', Certificate: 'certificate', - CertificateBin: 'certificate-bin', Archive: 'archive' }; @@ -138,7 +134,7 @@ export const FileInfo = { return app + 'ms-tnef'; } let ext = fileName.split('.').pop(); - if (/^(txt|text|def|list|in|ini|log|sql|cfg|conf|asc)$/.test(ext)) + if (/^(txt|text|def|list|in|ini|log|sql|cfg|conf)$/.test(ext)) return 'text/plain'; if (/^(mpe?g|mpe|m1v|m2v)$/.test(ext)) return 'video/mpeg'; @@ -186,15 +182,12 @@ export const FileInfo = { case 'video' == mimeTypeParts[0] || 'mkv' == ext || 'avi' == ext: result = FileType.Video; break; - case ['php', 'js', 'css'].includes(ext): + case ['php', 'js', 'css', 'xml', 'html'].includes(ext) || 'text/html' == mimeType: result = FileType.Code; break; case 'eml' == ext || ['message/delivery-status', 'message/rfc822'].includes(mimeType): result = FileType.Eml; break; - case 'text/html' == mimeType || 'html' == ext: - result = FileType.Html; - break; case 'text' == mimeTypeParts[0] || 'txt' == ext || 'log' == ext: result = FileType.Text; break; @@ -204,19 +197,17 @@ export const FileInfo = { case 'pdf' == type || 'pdf' == ext: result = FileType.Pdf; break; - case [app+'pgp-signature', app+'pgp-keys'].includes(mimeType) || - ['asc', 'pem', 'ppk'].includes(ext): + case [app+'pgp-signature', app+'pgp-keys'].includes(mimeType) + || ['asc', 'pem', 'ppk'].includes(ext) + || [app+'pkcs7-signature'].includes(mimeType) || 'p7s' == ext: result = FileType.Certificate; break; - case [app+'pkcs7-signature'].includes(mimeType) || 'p7s' == ext: - result = FileType.CertificateBin; - break; case match(msOffice+'.wordprocessingml') || match(openDoc+'.text') || match('vnd.ms-word') || ['rtf', 'msword', 'vnd.msword'].includes(type): - result = FileType.WordText; + result = FileType.Word; break; case match(msOffice+'.spreadsheetml') || match(openDoc+'.spreadsheet') || match('ms-excel'): - result = FileType.Sheet; + result = FileType.Spreadsheet; break; case match(msOffice+'.presentationml') || match(openDoc+'.presentation') || match('ms-powerpoint'): result = FileType.Presentation; @@ -232,45 +223,23 @@ export const FileInfo = { * @returns {string} */ getTypeIconClass: fileType => { - let result = ['icon-file', '']; + let result = 'icon-file'; switch (fileType) { case FileType.Text: case FileType.Eml: - case FileType.WordText: - result[0] += '-text'; - break; - case FileType.Html: - case FileType.Code: - result[0] += '-code'; - break; - case FileType.Image: - result[0] += '-image'; - break; - case FileType.Audio: - result[0] += '-music'; - break; - case FileType.Video: - result[0] += '-movie'; - break; - case FileType.Archive: - result[0] += '-zip'; - break; - case FileType.Certificate: - case FileType.CertificateBin: - result[0] += '-certificate'; - break; - case FileType.Sheet: - result[0] += '-excel'; - break; - case FileType.Presentation: - result[0] += '-chart-graph'; - break; case FileType.Pdf: - result = ['icon-none', 'pdf']; - break; - // no default + case FileType.Word: + return result + '-text'; + case FileType.Code: + case FileType.Image: + case FileType.Audio: + case FileType.Video: + case FileType.Archive: + case FileType.Certificate: + case FileType.Spreadsheet: + case FileType.Presentation: + return result + '-' + fileType; } - return result; }, @@ -283,7 +252,7 @@ export const FileInfo = { getCombinedIconClass: data => { if (isNonEmptyArray(data)) { let icons = data - .map(item => item ? FileInfo.getIconClass(FileInfo.getExtension(item[0]), item[1])[0] : '') + .map(item => item ? FileInfo.getIconClass(FileInfo.getExtension(item[0]), item[1]) : '') .validUnique(); return (icons && 1 === icons.length && 'icon-file' !== icons[0]) @@ -297,7 +266,7 @@ export const FileInfo = { friendlySize: bytes => { bytes = parseInt(bytes, 10) || 0; let i = Math.floor(Math.log(bytes) / Math.log(1024)); - return (bytes / Math.pow(1024, i)).toFixed(2>i ? 0 : 1) + sizes[i]; + return (bytes / Math.pow(1024, i)).toFixed(2>i ? 0 : 1) + ' ' + sizes[i]; } }; diff --git a/dev/Common/Links.js b/dev/Common/Links.js index 47928e239..c53d87b1d 100644 --- a/dev/Common/Links.js +++ b/dev/Common/Links.js @@ -179,12 +179,13 @@ export function mailBox(folder, page = 1, search = '', threadUid = '') { } if (1 < page) { - result = result.replace(/[/]+$/, '') + '/p' + page; + result = result.replace(/\/+$/, '') + '/p' + page; } if (search) { - result = result.replace(/[/]+$/, '') + '/' + encodeURI(search); + result = result.replace(/\/+$/, '') + '/' + encodeURI(search); } return result; } + diff --git a/dev/Common/Translator.js b/dev/Common/Translator.js index 552d16d15..a979eb817 100644 --- a/dev/Common/Translator.js +++ b/dev/Common/Translator.js @@ -3,7 +3,7 @@ import { Notification, UploadErrorCode } from 'Common/Enums'; import { langLink } from 'Common/Links'; import { doc, createElement } from 'Common/Globals'; -let I18N_DATA = window.rainloopI18N || {}; +let I18N_DATA = window.snappymailI18N || {}; export const trigger = ko.observable(false); @@ -14,14 +14,16 @@ export const trigger = ko.observable(false); * @returns {string} */ export function i18n(key, valueList, defaulValue) { - let result = I18N_DATA[key] || defaulValue || key; - + let path = key.split('/'); + if (!I18N_DATA[path[0]] || !path[1]) { + return defaulValue || key; + } + let result = I18N_DATA[path[0]][path[1]] || defaulValue || key; if (valueList) { Object.entries(valueList).forEach(([key, value]) => { result = result.replace('%' + key + '%', value); }); } - return result; } @@ -75,7 +77,7 @@ function getNotificationMessage(code) { let key = getKeyByValue(Notification, code); if (key) { key = i18nKey(key).replace('_NOTIFICATION', '_ERROR'); - return I18N_DATA['NOTIFICATIONS/' + key]; + return I18N_DATA.NOTIFICATIONS[key]; } } @@ -125,13 +127,13 @@ export function reload(admin, language) { const script = createElement('script'); script.onload = () => { // reload the data - if (window.rainloopI18N) { - I18N_DATA = window.rainloopI18N || {}; + if (window.snappymailI18N) { + I18N_DATA = window.snappymailI18N; i18nToNodes(doc); dispatchEvent(new CustomEvent('reload-time')); trigger(!trigger()); } - window.rainloopI18N = null; + window.snappymailI18N = null; script.remove(); resolve(); }; @@ -150,7 +152,7 @@ export function reload(admin, language) { */ export function convertLangName(language, isEng = false) { return i18n( - 'LANGS_NAMES' + (true === isEng ? '_EN' : '') + '/LANG_' + language.toUpperCase().replace(/[^a-zA-Z0-9]+/g, '_'), + 'LANGS_NAMES' + (true === isEng ? '_EN' : '') + '/' + language, null, language ); diff --git a/dev/Component/AbstractCheckbox.js b/dev/Component/AbstractCheckbox.js index 146d73eaa..e84824299 100644 --- a/dev/Component/AbstractCheckbox.js +++ b/dev/Component/AbstractCheckbox.js @@ -27,7 +27,6 @@ class AbstractCheckbox extends AbstractComponent { this.inline = !!params.inline; this.labeled = undefined !== params.label; - this.labelAnimated = !!params.labelAnimated; } click() { diff --git a/dev/Model/Attachment.js b/dev/Model/Attachment.js index 880090761..4c2573857 100644 --- a/dev/Model/Attachment.js +++ b/dev/Model/Attachment.js @@ -10,8 +10,6 @@ import { AbstractModel } from 'Knoin/AbstractModel'; import { SMAudio } from 'Common/Audio'; -const bAllowPdfPreview = undefined !== navigator.mimeTypes['application/pdf']; - export class AttachmentModel extends AbstractModel { constructor() { super(); @@ -92,27 +90,21 @@ export class AttachmentModel extends AbstractModel { * @returns {boolean} */ isText() { - return ( - FileType.Text === this.fileType || - FileType.Eml === this.fileType || - FileType.Certificate === this.fileType || - FileType.Html === this.fileType || - FileType.Code === this.fileType - ); + return FileType.Text === this.fileType || FileType.Eml === this.fileType; } /** * @returns {boolean} */ - isPdf() { - return FileType.Pdf === this.fileType; + pdfPreview() { + return null != navigator.mimeTypes['application/pdf'] && FileType.Pdf === this.fileType; } /** * @returns {boolean} */ hasPreview() { - return this.isImage() || (this.isPdf() && bAllowPdfPreview) || this.isText(); + return this.isImage() || this.pdfPreview() || this.isText(); } /** @@ -155,13 +147,6 @@ export class AttachmentModel extends AbstractModel { return link ? 'background:url(' + link + ')' : ''; } - /** - * @returns {string} - */ - linkPreviewAsPlain() { - return serverRequestRaw('ViewAsPlain', this.download); - } - /** * @returns {string} */ @@ -169,11 +154,11 @@ export class AttachmentModel extends AbstractModel { let result = ''; switch (true) { case this.isImage(): - case this.isPdf() && bAllowPdfPreview: + case this.pdfPreview(): result = this.linkPreview(); break; case this.isText(): - result = this.linkPreviewAsPlain(); + result = serverRequestRaw('ViewAsPlain', this.download); break; // no default } @@ -181,18 +166,6 @@ export class AttachmentModel extends AbstractModel { return result; } - /** - * @returns {string} - */ - generateTransferDownloadUrl() { - let link = this.linkDownload(); - if ('http' !== link.substr(0, 4)) { - link = location.protocol + '//' + location.host + location.pathname + link; - } - - return this.mimeType + ':' + this.fileName + ':' + link; - } - /** * @param {AttachmentModel} attachment * @param {*} event @@ -201,7 +174,11 @@ export class AttachmentModel extends AbstractModel { eventDragStart(attachment, event) { const localEvent = event.originalEvent || event; if (attachment && localEvent && localEvent.dataTransfer && localEvent.dataTransfer.setData) { - localEvent.dataTransfer.setData('DownloadURL', this.generateTransferDownloadUrl()); + let link = this.linkDownload(); + if ('http' !== link.substr(0, 4)) { + link = location.protocol + '//' + location.host + location.pathname + link; + } + localEvent.dataTransfer.setData('DownloadURL', this.mimeType + ':' + this.fileName + ':' + link); } return true; @@ -211,13 +188,6 @@ export class AttachmentModel extends AbstractModel { * @returns {string} */ iconClass() { - return FileInfo.getTypeIconClass(this.fileType)[0]; - } - - /** - * @returns {string} - */ - iconText() { - return FileInfo.getTypeIconClass(this.fileType)[1]; + return FileInfo.getTypeIconClass(this.fileType); } } diff --git a/dev/Model/ComposeAttachment.js b/dev/Model/ComposeAttachment.js index 6ee36dade..231e1deb4 100644 --- a/dev/Model/ComposeAttachment.js +++ b/dev/Model/ComposeAttachment.js @@ -96,13 +96,6 @@ export class ComposeAttachmentModel extends AbstractModel { * @returns {string} */ iconClass() { - return FileInfo.getIconClass(this.fileExt(), this.mimeType())[0]; - } - - /** - * @returns {string} - */ - iconText() { - return FileInfo.getIconClass(this.fileExt(), this.mimeType())[1]; + return FileInfo.getIconClass(this.fileExt(), this.mimeType()); } } diff --git a/dev/Model/FolderCollection.js b/dev/Model/FolderCollection.js index 017fa37a9..0b4112f9d 100644 --- a/dev/Model/FolderCollection.js +++ b/dev/Model/FolderCollection.js @@ -10,6 +10,7 @@ import * as Local from 'Storage/Client'; import { AppUserStore } from 'Stores/User/App'; import { FolderUserStore } from 'Stores/User/Folder'; +import { SettingsUserStore } from 'Stores/User/Settings'; import ko from 'ko'; @@ -113,6 +114,7 @@ export class FolderCollectionModel extends AbstractCollectionModel AppUserStore.threadsAllowed(!!(Settings.app('useImapThread') && this.IsThreadsSupported)); FolderUserStore.folderListOptimized(!!this.Optimized); + FolderUserStore.sortSupported(!!this.IsSortSupported); let update = false; @@ -123,8 +125,7 @@ export class FolderCollectionModel extends AbstractCollectionModel SettingsGet('DraftFolder') + SettingsGet('SpamFolder') + SettingsGet('TrashFolder') + - SettingsGet('ArchiveFolder') + - SettingsGet('NullFolder')) + SettingsGet('ArchiveFolder')) ) { Settings.set('SentFolder', this.SystemFolders[ServerFolderType.SENT] || null); Settings.set('DraftFolder', this.SystemFolders[ServerFolderType.DRAFTS] || null); @@ -147,8 +148,7 @@ export class FolderCollectionModel extends AbstractCollectionModel DraftFolder: FolderUserStore.draftFolder(), SpamFolder: FolderUserStore.spamFolder(), TrashFolder: FolderUserStore.trashFolder(), - ArchiveFolder: FolderUserStore.archiveFolder(), - NullFolder: 'NullFolder' + ArchiveFolder: FolderUserStore.archiveFolder() }); } @@ -301,7 +301,10 @@ export class FolderModel extends AbstractModel { canBeDeleted: () => !folder.isSystemFolder() && !folder.subFolders.length, - canBeSubscribed: () => !folder.isSystemFolder() && folder.selectable && Settings.app('useImapSubscribe'), + canBeSubscribed: () => !folder.isSystemFolder() + && SettingsUserStore.hideUnsubscribed() + && folder.selectable + && Settings.app('useImapSubscribe'), canBeSelected: () => !folder.isSystemFolder() && folder.selectable, diff --git a/dev/Model/Message.js b/dev/Model/Message.js index 9c0264258..a5b4b0dd1 100644 --- a/dev/Model/Message.js +++ b/dev/Model/Message.js @@ -45,6 +45,9 @@ export class MessageModel extends AbstractModel { this.addObservables({ subject: '', size: 0, + spamScore: 0, + spamResult: '', + isSpam: false, dateTimeStampInUTC: 0, priority: MessagePriority.Normal, @@ -116,6 +119,9 @@ export class MessageModel extends AbstractModel { this._reset(); this.subject(''); this.size(0); + this.spamScore(0); + this.spamResult(''); + this.isSpam(false); this.dateTimeStampInUTC(0); this.priority(MessagePriority.Normal); @@ -211,10 +217,10 @@ export class MessageModel extends AbstractModel { /** * @param {boolean} friendlyView - * @param {boolean=} wrapWithLink = false + * @param {boolean=} wrapWithLink * @returns {string} */ - fromToLine(friendlyView, wrapWithLink = false) { + fromToLine(friendlyView, wrapWithLink) { return this.from.toString(friendlyView, wrapWithLink); } @@ -232,37 +238,37 @@ export class MessageModel extends AbstractModel { /** * @param {boolean} friendlyView - * @param {boolean=} wrapWithLink = false + * @param {boolean=} wrapWithLink * @returns {string} */ - toToLine(friendlyView, wrapWithLink = false) { + toToLine(friendlyView, wrapWithLink) { return this.to.toString(friendlyView, wrapWithLink); } /** * @param {boolean} friendlyView - * @param {boolean=} wrapWithLink = false + * @param {boolean=} wrapWithLink * @returns {string} */ - ccToLine(friendlyView, wrapWithLink = false) { + ccToLine(friendlyView, wrapWithLink) { return this.cc.toString(friendlyView, wrapWithLink); } /** * @param {boolean} friendlyView - * @param {boolean=} wrapWithLink = false + * @param {boolean=} wrapWithLink * @returns {string} */ - bccToLine(friendlyView, wrapWithLink = false) { + bccToLine(friendlyView, wrapWithLink) { return this.bcc.toString(friendlyView, wrapWithLink); } /** * @param {boolean} friendlyView - * @param {boolean=} wrapWithLink = false + * @param {boolean=} wrapWithLink * @returns {string} */ - replyToToLine(friendlyView, wrapWithLink = false) { + replyToToLine(friendlyView, wrapWithLink) { return this.replyTo.toString(friendlyView, wrapWithLink); } @@ -318,7 +324,7 @@ export class MessageModel extends AbstractModel { * @param {boolean=} last = false * @returns {Array} */ - replyEmails(excludeEmails, last = false) { + replyEmails(excludeEmails, last) { const result = [], unic = undefined === excludeEmails ? {} : excludeEmails; @@ -339,7 +345,7 @@ export class MessageModel extends AbstractModel { * @param {boolean=} last = false * @returns {Array.} */ - replyAllEmails(excludeEmails, last = false) { + replyAllEmails(excludeEmails, last) { let data = []; const toResult = [], ccResult = [], @@ -364,7 +370,7 @@ export class MessageModel extends AbstractModel { /** * @param {boolean=} print = false */ - viewPopupMessage(print = false) { + viewPopupMessage(print) { const timeStampInUTC = this.dateTimeStampInUTC() || 0, ccLine = this.ccToLine(false), m = 0 < timeStampInUTC ? new Date(timeStampInUTC * 1000) : null, @@ -414,6 +420,9 @@ export class MessageModel extends AbstractModel { this.subject(message.subject()); this.size(message.size()); + this.spamScore(message.spamScore()); + this.spamResult(message.spamResult()); + this.isSpam(message.isSpam()); this.dateTimeStampInUTC(message.dateTimeStampInUTC()); this.priority(message.priority()); diff --git a/dev/Remote/User/Fetch.js b/dev/Remote/User/Fetch.js index 182f15a23..9f272e60f 100644 --- a/dev/Remote/User/Fetch.js +++ b/dev/Remote/User/Fetch.js @@ -55,76 +55,17 @@ class RemoteUserFetch extends AbstractFetchRemote { * @param {string} sPassword * @param {boolean} bSignMe * @param {string=} sLanguage - * @param {string=} sAdditionalCode - * @param {boolean=} bAdditionalCodeSignMe */ - login(fCallback, sEmail, sPassword, bSignMe, sLanguage, sAdditionalCode, bAdditionalCodeSignMe) { + login(fCallback, sEmail, sPassword, bSignMe, sLanguage) { this.defaultRequest(fCallback, 'Login', { Email: sEmail, Login: '', Password: sPassword, Language: sLanguage || '', - AdditionalCode: sAdditionalCode || '', - AdditionalCodeSignMe: bAdditionalCodeSignMe ? 1 : 0, SignMe: bSignMe ? 1 : 0 }); } - /** - * @param {?Function} fCallback - */ - getTwoFactor(fCallback) { - this.defaultRequest(fCallback, 'GetTwoFactorInfo'); - } - - /** - * @param {?Function} fCallback - */ - createTwoFactor(fCallback) { - this.defaultRequest(fCallback, 'CreateTwoFactorSecret'); - } - - /** - * @param {?Function} fCallback - */ - clearTwoFactor(fCallback) { - this.defaultRequest(fCallback, 'ClearTwoFactorInfo'); - } - - /** - * @param {?Function} fCallback - */ - showTwoFactorSecret(fCallback) { - this.defaultRequest(fCallback, 'ShowTwoFactorSecret'); - } - - /** - * @param {?Function} fCallback - * @param {string} sCode - */ - testTwoFactor(fCallback, sCode) { - this.defaultRequest(fCallback, 'TestTwoFactorInfo', { - Code: sCode - }); - } - - /** - * @param {?Function} fCallback - * @param {boolean} bEnable - */ - enableTwoFactor(fCallback, bEnable) { - this.defaultRequest(fCallback, 'EnableTwoFactor', { - Enable: bEnable ? 1 : 0 - }); - } - - /** - * @param {?Function} fCallback - */ - clearTwoFactorInfo(fCallback) { - this.defaultRequest(fCallback, 'ClearTwoFactorInfo'); - } - /** * @param {?Function} fCallback */ @@ -297,54 +238,44 @@ class RemoteUserFetch extends AbstractFetchRemote { /** * @param {Function} fCallback - * @param {string} sFolderFullNameRaw - * @param {number=} iOffset = 0 - * @param {number=} iLimit = 20 - * @param {string=} sSearch = '' - * @param {string=} sThreadUid = '' + * @param {object} params * @param {boolean=} bSilent = false */ - messageList(fCallback, sFolderFullNameRaw, iOffset = 0, iLimit = 20, sSearch = '', sThreadUid = '', bSilent = false) { - sFolderFullNameRaw = pString(sFolderFullNameRaw); - - const folderHash = getFolderHash(sFolderFullNameRaw), - useThreads = AppUserStore.threadsAllowed() && SettingsUserStore.useThreads(), + messageList(fCallback, params, bSilent = false) { + const + sFolderFullNameRaw = pString(params.Folder), + folderHash = getFolderHash(sFolderFullNameRaw), + useThreads = AppUserStore.threadsAllowed() && SettingsUserStore.useThreads() ? 1 : 0, inboxUidNext = getFolderInboxName() === sFolderFullNameRaw ? getFolderUidNext(sFolderFullNameRaw) : ''; - let params = {}, sGetAdd = ''; + params.Folder = sFolderFullNameRaw; + params.ThreadUid = useThreads ? params.ThreadUid : ''; + params = Object.assign({ + Folder: '', + Offset: 0, + Limit: SettingsUserStore.messagesPerPage(), + Search: '', + UidNext: inboxUidNext, + UseThreads: useThreads, + ThreadUid: '', + Sort: FolderUserStore.sortMode() + }, params); - if (folderHash && (!sSearch || !sSearch.includes('is:'))) { + let sGetAdd = ''; + + if (folderHash && (!params.Search || !params.Search.includes('is:'))) { sGetAdd = 'MessageList/' + SUB_QUERY_PREFIX + '/' + - urlsafeArray([ - sFolderFullNameRaw, - iOffset, - iLimit, - sSearch, - SettingsGet('ProjectHash'), - folderHash, - inboxUidNext, - useThreads ? 1 : 0, - useThreads ? sThreadUid : '' - ]); - } else { - params = { - Folder: sFolderFullNameRaw, - Offset: iOffset, - Limit: iLimit, - Search: sSearch, - UidNext: inboxUidNext, - UseThreads: useThreads ? 1 : 0, - ThreadUid: useThreads ? sThreadUid : '' - }; + urlsafeArray([SettingsGet('ProjectHash'),folderHash].concat(Object.values(params))); + params = {}; } this.defaultRequest( fCallback, 'MessageList', params, - sSearch ? 300000 : 30000, + 30000, sGetAdd, bSilent ? [] : ['MessageList'] ); @@ -562,7 +493,7 @@ class RemoteUserFetch extends AbstractFetchRemote { * @param {Object} oData */ sendMessage(fCallback, oData) { - this.defaultRequest(fCallback, 'SendMessage', oData, 300000); + this.defaultRequest(fCallback, 'SendMessage', oData, 30000); } /** diff --git a/dev/Screen/User/MailBox.js b/dev/Screen/User/MailBox.js index 83e7c3e28..c445a3876 100644 --- a/dev/Screen/User/MailBox.js +++ b/dev/Screen/User/MailBox.js @@ -74,7 +74,7 @@ export class MailBoxUserScreen extends AbstractScreen { FolderUserStore.currentFolder(folder); - MessageUserStore.listPage(page); + MessageUserStore.listPage(1 > page ? 1 : page); MessageUserStore.listSearch(search); MessageUserStore.listThreadUid(threadUid); @@ -119,23 +119,15 @@ export class MailBoxUserScreen extends AbstractScreen { */ routes() { const - fNormS = (request, vals) => { - if (request) { - vals[0] = decodeURI(pString(vals[0])); - vals[1] = pInt(vals[1]); - } else { - vals[0] = getFolderInboxName(); - vals[1] = 1; - } - return [vals[0], 1 > vals[1] ? 1 : vals[1], decodeURI(pString(vals[2]))]; - }, - fNormD = (request, vals) => - [decodeURI(request ? pString(vals[0]) : getFolderInboxName()), 1, decodeURI(pString(vals[1]))]; + folder = (request, vals) => request ? decodeURI(pString(vals[0])) : getFolderInboxName(), + fNormS = (request, vals) => [folder(request, vals), request ? pInt(vals[1]) : 1, decodeURI(pString(vals[2]))]; return [ - [/^([^/]*)$/, { 'normalize_': fNormS }], - [/^([a-zA-Z0-9~]+)\/(.+)\/?$/, { 'normalize_': fNormD }], - [/^([a-zA-Z0-9~]+)\/p([1-9][0-9]*)(?:\/(.+)\/?)?$/, { 'normalize_': fNormS }] + [/^([^/]*)$/, { normalize_: fNormS }], + [/^([a-zA-Z0-9~]+)\/(.+)\/?$/, { normalize_: (request, vals) => + [folder(request, vals), 1, decodeURI(pString(vals[1]))] + }], + [/^([a-zA-Z0-9~]+)\/p([1-9][0-9]*)(?:\/(.+)\/?)?$/, { normalize_: fNormS }] ]; } } diff --git a/dev/Screen/User/Settings.js b/dev/Screen/User/Settings.js index 88d5675cd..70cce520f 100644 --- a/dev/Screen/User/Settings.js +++ b/dev/Screen/User/Settings.js @@ -64,7 +64,7 @@ export class SettingsUserScreen extends AbstractSettingsScreen { settingsAddViewModel(FiltersUserSettings, 'SettingsFilters', 'SETTINGS_LABELS/LABEL_FILTERS_NAME', 'filters'); } - if (Settings.capa(Capa.AutoLogout) || Settings.capa(Capa.TwoFactor)) { + if (Settings.capa(Capa.AutoLogout)) { settingsAddViewModel(SecurityUserSettings, 'SettingsSecurity', 'SETTINGS_LABELS/LABEL_SECURITY_NAME', 'security'); } diff --git a/dev/Settings/Admin/Contacts.js b/dev/Settings/Admin/Contacts.js index 7e0fe8a83..9bcd91f56 100644 --- a/dev/Settings/Admin/Contacts.js +++ b/dev/Settings/Admin/Contacts.js @@ -19,7 +19,7 @@ export class ContactsAdminSettings { addObservablesTo(this, { enableContacts: !!SettingsGet('ContactsEnable'), contactsSync: !!SettingsGet('ContactsSync'), - contactsType: '', + contactsType: SettingsGet('ContactsPdoType'), pdoDsn: SettingsGet('ContactsPdoDsn'), pdoUser: SettingsGet('ContactsPdoUser'), @@ -69,8 +69,6 @@ export class ContactsAdminSettings { }) .extend({ notify: 'always' }); - this.contactsType(SettingsGet('ContactsPdoType')); - addSubscribablesTo(this, { enableContacts: value => Remote.saveAdminConfig(null, { diff --git a/dev/Settings/Admin/General.js b/dev/Settings/Admin/General.js index 22066fbce..7a0f459d6 100644 --- a/dev/Settings/Admin/General.js +++ b/dev/Settings/Admin/General.js @@ -53,7 +53,11 @@ export class GeneralAdminSettings { this.weakPassword = rl.app.weakPassword; -// fetch('./data/VERSION?' + Math.random()).then(response => this.dataFolderAccess(response.ok)); + /** https://github.com/RainLoop/rainloop-webmail/issues/1924 + if (this.weakPassword) { + fetch('./data/VERSION?' + Math.random()).then(response => this.dataFolderAccess(response.ok)); + } + */ this.mainAttachmentLimit = ko .observable(pInt(SettingsGet('AttachmentLimit')) / (1024 * 1024)) diff --git a/dev/Settings/Admin/Security.js b/dev/Settings/Admin/Security.js index c8c4b3eb3..b1a582db2 100644 --- a/dev/Settings/Admin/Security.js +++ b/dev/Settings/Admin/Security.js @@ -16,10 +16,6 @@ export class SecurityAdminSettings { verifySslCertificate: !!SettingsGet('VerifySslCertificate'), allowSelfSigned: !!SettingsGet('AllowSelfSigned'), - isTwoFactorDropperShown: false, - twoFactorDropperUser: '', - twoFactorDropperUserFocused: false, - adminLogin: SettingsGet('AdminLogin'), adminLoginError: false, adminPassword: '', @@ -30,9 +26,7 @@ export class SecurityAdminSettings { adminPasswordUpdateError: false, adminPasswordUpdateSuccess: false, - capaOpenPGP: Settings.capa(Capa.OpenPGP), - capaTwoFactorAuth: Settings.capa(Capa.TwoFactor), - capaTwoFactorAuthForce: Settings.capa(Capa.TwoFactorForce) + capaOpenPGP: Settings.capa(Capa.OpenPGP) }); addSubscribablesTo(this, { @@ -60,18 +54,6 @@ export class SecurityAdminSettings { CapaOpenPGP: value ? 1 : 0 }), - capaTwoFactorAuth: value => { - value || this.capaTwoFactorAuthForce(false); - Remote.saveAdminConfig(null, { - CapaTwoFactorAuth: value ? 1 : 0 - }); - }, - - capaTwoFactorAuthForce: value => - Remote.saveAdminConfig(null, { - CapaTwoFactorAuthForce: value ? 1 : 0 - }), - useLocalProxyForExternalImages: value => Remote.saveAdminConfig(null, { UseLocalProxyForExternalImages: value ? 1 : 0 @@ -120,15 +102,6 @@ export class SecurityAdminSettings { return true; } - showTwoFactorDropper() { - this.twoFactorDropperUser(''); - this.isTwoFactorDropperShown(true); - - setTimeout(() => { - this.twoFactorDropperUserFocused(true); - }, 50); - } - onNewAdminPasswordResponse(iError, data) { if (iError) { this.adminPasswordUpdateError(true); @@ -147,9 +120,5 @@ export class SecurityAdminSettings { this.adminPassword(''); this.adminPasswordNew(''); this.adminPasswordNew2(''); - - this.isTwoFactorDropperShown(false); - this.twoFactorDropperUser(''); - this.twoFactorDropperUserFocused(false); } } diff --git a/dev/Settings/User/Folders.js b/dev/Settings/User/Folders.js index e51ada363..7f30d88cb 100644 --- a/dev/Settings/User/Folders.js +++ b/dev/Settings/User/Folders.js @@ -2,6 +2,7 @@ import ko from 'ko'; import { Notification } from 'Common/Enums'; import { ClientSideKeyName } from 'Common/EnumsUser'; +import { Settings } from 'Common/Globals'; import { getNotification } from 'Common/Translator'; import { removeFolderFromCacheList } from 'Common/Cache'; @@ -9,6 +10,7 @@ import { removeFolderFromCacheList } from 'Common/Cache'; import * as Local from 'Storage/Client'; import { FolderUserStore } from 'Stores/User/Folder'; +import { SettingsUserStore } from 'Stores/User/Settings'; import Remote from 'Remote/User/Fetch'; @@ -23,6 +25,7 @@ export class FoldersUserSettings { this.folderList = FolderUserStore.folderList; this.folderListOptimized = FolderUserStore.folderListOptimized; this.folderListError = FolderUserStore.folderListError; + this.hideUnsubscribed = SettingsUserStore.hideUnsubscribed; this.loading = ko.computed(() => { const loading = FolderUserStore.foldersLoading(), @@ -36,6 +39,9 @@ export class FoldersUserSettings { this.folderForDeletion = ko.observable(null).deleteAccessHelper(); this.folderForEdit = ko.observable(null).extend({ toggleSubscribeProperty: [this, 'edited'] }); + + this.useImapSubscribe = Settings.app('useImapSubscribe'); + this.hideUnsubscribed.subscribe(value => Remote.saveSetting('HideUnsubscribed', value ? 1 : 0)); } folderEditOnEnter(folder) { diff --git a/dev/Settings/User/Security.js b/dev/Settings/User/Security.js index 55ed0e458..6c37c3a4f 100644 --- a/dev/Settings/User/Security.js +++ b/dev/Settings/User/Security.js @@ -5,18 +5,13 @@ import { Capa, SaveSettingsStep } from 'Common/Enums'; import { Settings } from 'Common/Globals'; import { i18n, trigger as translatorTrigger } from 'Common/Translator'; -import { showScreenPopup } from 'Knoin/Knoin'; - import { SettingsUserStore } from 'Stores/User/Settings'; import Remote from 'Remote/User/Fetch'; -import { TwoFactorConfigurationPopupView } from 'View/Popup/TwoFactorConfiguration'; - export class SecurityUserSettings { constructor() { this.capaAutoLogout = Settings.capa(Capa.AutoLogout); - this.capaTwoFactor = Settings.capa(Capa.TwoFactor); this.autoLogout = SettingsUserStore.autoLogout; this.autoLogoutTrigger = ko.observable(SaveSettingsStep.Idle); @@ -43,8 +38,4 @@ export class SecurityUserSettings { )); } } - - configureTwoFactor() { - showScreenPopup(TwoFactorConfigurationPopupView); - } } diff --git a/dev/Stores/User/Folder.js b/dev/Stores/User/Folder.js index 0cc19c389..34ed105bf 100644 --- a/dev/Stores/User/Folder.js +++ b/dev/Stores/User/Folder.js @@ -1,6 +1,6 @@ import ko from 'ko'; -import { FolderType } from 'Common/EnumsUser'; +import { FolderType, FolderSortMode } from 'Common/EnumsUser'; import { UNUSED_OPTION_VALUE } from 'Common/Consts'; import { addObservablesTo, addSubscribablesTo } from 'Common/Utils'; import { folderListOptionsBuilder } from 'Common/UtilsUser'; @@ -19,6 +19,12 @@ export const FolderUserStore = new class { */ displaySpecSetting: false, + /** + * If the IMAP server supports SORT + */ + sortSupported: false, +// sortMode: '', + sentFolder: '', draftFolder: '', spamFolder: '', @@ -36,6 +42,8 @@ export const FolderUserStore = new class { foldersInboxUnreadCount: 0 }); + this.sortMode = ko.observable('').extend({ limitedList: Object.values(FolderSortMode) }); + this.namespace = ''; this.folderList = ko.observableArray(); diff --git a/dev/Stores/User/Settings.js b/dev/Stores/User/Settings.js index cd157fb65..d3b20fd73 100644 --- a/dev/Stores/User/Settings.js +++ b/dev/Stores/User/Settings.js @@ -30,6 +30,7 @@ export const SettingsUserStore = new class { allowDraftAutosave: !!SettingsGet('AllowDraftAutosave'), useThreads: !!SettingsGet('UseThreads'), replySameFolder: !!SettingsGet('ReplySameFolder'), + hideUnsubscribed: !!SettingsGet('HideUnsubscribed'), autoLogout: pInt(SettingsGet('AutoLogout')) }); diff --git a/dev/Styles/@Main.less b/dev/Styles/@Main.less index 38ec808e0..b46372da1 100644 --- a/dev/Styles/@Main.less +++ b/dev/Styles/@Main.less @@ -42,7 +42,6 @@ @import "Filter.less"; @import "Template.less"; @import "OpenPgpKey.less"; -@import "TwoFactor.less"; @import "Identity.less"; @import "AdvancedSearch.less"; @import "Attachmnets.less"; diff --git a/dev/Styles/Attachmnets.less b/dev/Styles/Attachmnets.less index 247010ba8..85ddab889 100644 --- a/dev/Styles/Attachmnets.less +++ b/dev/Styles/Attachmnets.less @@ -29,11 +29,10 @@ } .checkboxAttachment { - position: absolute; - top: 0; - right: 0; - padding: 1px 4px 0 5px; + bottom: 6px; cursor: pointer; + position: absolute; + right: 6px; } .attachmentSize { @@ -104,16 +103,6 @@ } } - .attachmentIconText { - display: inline-block; - font-size: 28px; - width: 60px; - height: 56px; - color: #aaa; - line-height: 56px; - font-style: normal; - } - /* .attachmentIconParent.hasPreview.isImage { .iconMain { diff --git a/dev/Styles/Compose.less b/dev/Styles/Compose.less index 322450ec6..5cab01450 100644 --- a/dev/Styles/Compose.less +++ b/dev/Styles/Compose.less @@ -18,14 +18,9 @@ } .attachmentAreaParent { - padding: 10px 10px 6px 10px; - background: #ddd; border-top: 1px solid #ccc; - overflow-y: auto; - } - - .attachmentAreaParent { + padding: 10px 10px 6px 10px; .no-attachments-desc { padding: 50px 10px; diff --git a/dev/Styles/Login.less b/dev/Styles/Login.less index 610e147af..89bb310fc 100644 --- a/dev/Styles/Login.less +++ b/dev/Styles/Login.less @@ -54,7 +54,7 @@ } .controls { - .inputLoginForm, .inputEmail, .inputLogin, .inputPassword, .inputAdditionalCode { + .inputLoginForm, .inputEmail, .inputLogin, .inputPassword { font-size: 18px; height: 40px; line-height: 20px; diff --git a/dev/Styles/MessageList.less b/dev/Styles/MessageList.less index f7021d2ff..8a73446de 100644 --- a/dev/Styles/MessageList.less +++ b/dev/Styles/MessageList.less @@ -6,6 +6,11 @@ html.rl-no-preview-pane { } } +#sort-list-dropdown-id { + padding-left: 6px; + padding-right: 6px; +} + .messageList { .toolbar { @@ -254,9 +259,9 @@ html.rl-no-preview-pane { padding: 0 10px 0 5px; } - time { + time, .sizeParent { margin: 0 5px; - color: #999; + opacity: 0.6; font-size: 11px; white-space: nowrap; } @@ -472,7 +477,7 @@ html .messageList .line-loading { line-height: 16px; margin-left: 30px; order: 1; - width: calc(100% - 60px); + width: calc(100% - 120px); } .senderParent { @@ -483,9 +488,13 @@ html .messageList .line-loading { order: 1; } - .attachmentParent { + .sizeParent { order: 2; } + + .attachmentParent { + order: 3; + } } } diff --git a/dev/Styles/MessageView.less b/dev/Styles/MessageView.less index 9242cf769..60d89596a 100644 --- a/dev/Styles/MessageView.less +++ b/dev/Styles/MessageView.less @@ -136,15 +136,8 @@ } .informationFull { - margin-top: 10px; - border: 1px solid #999; - border-radius: 5px; - padding: 8px 0; - overflow: hidden; + margin-top: 30px; - .size { - margin-left: 4px; - } table { width: 100%; @@ -155,7 +148,7 @@ } td { - padding: 0 10px; + padding: 4px; vertical-align: top; min-width: 43px; } @@ -163,17 +156,15 @@ td:first-child { border-right: 1px solid #999; text-align: right; + white-space: nowrap; width: 1%; } - .uiLine { - } - - .uiLabel { + .labelTo { white-space: nowrap; } - .uiLabelValue { + td + td { word-break: break-all; } } @@ -273,13 +264,9 @@ margin: 0; } - .checkboxAttachment { - display: none; - } - - &.selection-mode { + &:not(.selection-mode) { .checkboxAttachment { - display: inline-block; + display: none; } } diff --git a/dev/Styles/SettingsFolders.less b/dev/Styles/SettingsFolders.less index 558cade17..41b6b87c3 100644 --- a/dev/Styles/SettingsFolders.less +++ b/dev/Styles/SettingsFolders.less @@ -6,7 +6,7 @@ } .list-table { - margin-top: 40px; + margin-top: 1em; .folder-padding { display: inline-block; diff --git a/dev/Styles/TwoFactor.less b/dev/Styles/TwoFactor.less deleted file mode 100644 index b2954f915..000000000 --- a/dev/Styles/TwoFactor.less +++ /dev/null @@ -1,8 +0,0 @@ -.b-two-factor-content { - - width: 750px; - - .modal-body { - min-height: 100px; - } -} diff --git a/dev/View/Popup/FolderSystem.js b/dev/View/Popup/FolderSystem.js index 04a56def1..75f5612fa 100644 --- a/dev/View/Popup/FolderSystem.js +++ b/dev/View/Popup/FolderSystem.js @@ -64,8 +64,7 @@ class FolderSystemPopupView extends AbstractViewPopup { DraftFolder: FolderUserStore.draftFolder(), SpamFolder: FolderUserStore.spamFolder(), TrashFolder: FolderUserStore.trashFolder(), - ArchiveFolder: FolderUserStore.archiveFolder(), - NullFolder: 'NullFolder' + ArchiveFolder: FolderUserStore.archiveFolder() }); }).debounce(1000), fCallback = () => { diff --git a/dev/View/Popup/TwoFactorConfiguration.js b/dev/View/Popup/TwoFactorConfiguration.js deleted file mode 100644 index ab1a3d23e..000000000 --- a/dev/View/Popup/TwoFactorConfiguration.js +++ /dev/null @@ -1,193 +0,0 @@ -import { Capa } from 'Common/Enums'; -import { Settings } from 'Common/Globals'; -import { pString } from 'Common/Utils'; -import { i18n, trigger as translatorTrigger } from 'Common/Translator'; - -import Remote from 'Remote/User/Fetch'; - -import { showScreenPopup } from 'Knoin/Knoin'; -import { AbstractViewPopup } from 'Knoin/AbstractViews'; - -import { TwoFactorTestPopupView } from 'View/Popup/TwoFactorTest'; - -class TwoFactorConfigurationPopupView extends AbstractViewPopup { - constructor() { - super('TwoFactorConfiguration'); - - this.addObservables({ - lock: false, - - processing: false, - clearing: false, - secreting: false, - - viewUser: '', - twoFactorStatus: false, - - twoFactorTested: false, - - viewSecret: '', - viewBackupCodes: '', - viewUrlTitle: '', - viewUrl: '', - - viewEnable_: false - }); - - this.capaTwoFactor = Settings.capa(Capa.TwoFactor); - - const fn = iError => iError && this.viewEnable_(false); - this.addComputables({ - viewEnable: { - read: this.viewEnable_, - write: (value) => { - value = !!value; - if (value && this.twoFactorTested()) { - this.viewEnable_(value); - Remote.enableTwoFactor(fn, value); - } else { - if (!value) { - this.viewEnable_(value); - } - Remote.enableTwoFactor(fn, false); - } - } - }, - - viewTwoFactorEnableTooltip: () => { - translatorTrigger(); - return this.twoFactorTested() || this.viewEnable_() - ? '' - : i18n('POPUPS_TWO_FACTOR_CFG/TWO_FACTOR_SECRET_TEST_BEFORE_DESC'); - }, - - viewTwoFactorStatus: () => { - translatorTrigger(); - return i18n( - this.twoFactorStatus() - ? 'POPUPS_TWO_FACTOR_CFG/TWO_FACTOR_SECRET_CONFIGURED_DESC' - : 'POPUPS_TWO_FACTOR_CFG/TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC' - ); - }, - - twoFactorAllowedEnable: () => this.viewEnable() || this.twoFactorTested() - }); - - this.onResult = this.onResult.bind(this); - this.onShowSecretResult = this.onShowSecretResult.bind(this); - } - - showSecret() { - this.secreting(true); - Remote.showTwoFactorSecret(this.onShowSecretResult); - } - - hideSecret() { - this.viewSecret(''); - this.viewBackupCodes(''); - this.viewUrlTitle(''); - this.viewUrl(''); - } - - createTwoFactor() { - this.processing(true); - Remote.createTwoFactor(this.onResult); - } - - logout() { - rl.app.logout(); - } - - testTwoFactor() { - showScreenPopup(TwoFactorTestPopupView, [this.twoFactorTested]); - } - - clearTwoFactor() { - this.viewSecret(''); - this.viewBackupCodes(''); - this.viewUrlTitle(''); - this.viewUrl(''); - - this.twoFactorTested(false); - - this.clearing(true); - Remote.clearTwoFactor(this.onResult); - } - - onShow(bLock) { - this.lock(!!bLock); - - this.viewSecret(''); - this.viewBackupCodes(''); - this.viewUrlTitle(''); - this.viewUrl(''); - } - - onHide() { - if (this.lock()) { - location.reload(); - } - } - - getQr() { - return ( - 'otpauth://totp/' + - encodeURIComponent(this.viewUser()) + - '?secret=' + - encodeURIComponent(this.viewSecret()) + - '&issuer=' + - encodeURIComponent('') - ); - } - - onResult(iError, oData) { - this.processing(false); - this.clearing(false); - - if (iError) { - this.viewUser(''); - this.viewEnable_(false); - this.twoFactorStatus(false); - this.twoFactorTested(false); - - this.viewSecret(''); - this.viewBackupCodes(''); - this.viewUrlTitle(''); - this.viewUrl(''); - } else { - this.viewUser(pString(oData.Result.User)); - this.viewEnable_(!!oData.Result.Enable); - this.twoFactorStatus(!!oData.Result.IsSet); - this.twoFactorTested(!!oData.Result.Tested); - - this.viewSecret(pString(oData.Result.Secret)); - this.viewBackupCodes(pString(oData.Result.BackupCodes).replace(/[\s]+/g, ' ')); - - this.viewUrlTitle(pString(oData.Result.UrlTitle)); - this.viewUrl(qr.toDataURL({ level: 'M', size: 8, value: this.getQr() })); - } - } - - onShowSecretResult(iError, data) { - this.secreting(false); - - if (iError) { - this.viewSecret(''); - this.viewUrlTitle(''); - this.viewUrl(''); - } else { - this.viewSecret(pString(data.Result.Secret)); - this.viewUrlTitle(pString(data.Result.UrlTitle)); - this.viewUrl(qr.toDataURL({ level: 'M', size: 6, value: this.getQr() })); - } - } - - onBuild() { - if (this.capaTwoFactor) { - this.processing(true); - Remote.getTwoFactor(this.onResult); - } - } -} - -export { TwoFactorConfigurationPopupView, TwoFactorConfigurationPopupView as default }; diff --git a/dev/View/Popup/TwoFactorTest.js b/dev/View/Popup/TwoFactorTest.js deleted file mode 100644 index 5977a6e26..000000000 --- a/dev/View/Popup/TwoFactorTest.js +++ /dev/null @@ -1,51 +0,0 @@ -import Remote from 'Remote/User/Fetch'; - -import { decorateKoCommands } from 'Knoin/Knoin'; -import { AbstractViewPopup } from 'Knoin/AbstractViews'; - -class TwoFactorTestPopupView extends AbstractViewPopup { - constructor() { - super('TwoFactorTest'); - - this.addObservables({ - code: '', - codeStatus: null, - - testing: false - }); - - this.koTestedTrigger = null; - - decorateKoCommands(this, { - testCodeCommand: self => self.code() && !self.testing() - }); - } - - testCodeCommand() { - this.testing(true); - Remote.testTwoFactor(iError => { - this.testing(false); - this.codeStatus(!iError); - - if (this.koTestedTrigger && this.codeStatus()) { - this.koTestedTrigger(true); - } - }, this.code()); - } - - clearPopup() { - this.code(''); - this.codeStatus(null); - this.testing(false); - - this.koTestedTrigger = null; - } - - onShow(koTestedTrigger) { - this.clearPopup(); - - this.koTestedTrigger = koTestedTrigger; - } -} - -export { TwoFactorTestPopupView, TwoFactorTestPopupView as default }; diff --git a/dev/View/User/Login.js b/dev/View/User/Login.js index f5c15c149..2ab453b05 100644 --- a/dev/View/User/Login.js +++ b/dev/View/User/Login.js @@ -43,7 +43,6 @@ class LoginUserView extends AbstractViewCenter { email: SettingsGet('DevEmail'), password: SettingsGet('DevPassword'), signMe: false, - additionalCode: '', emailError: false, passwordError: false, @@ -56,9 +55,6 @@ class LoginUserView extends AbstractViewCenter { langRequest: false, - additionalCodeError: false, - additionalCodeSignMe: false, - additionalCodeVisibility: false, signMeType: LoginSignMeType.Unused }); @@ -84,15 +80,10 @@ class LoginUserView extends AbstractViewCenter { this.addSubscribables({ email: () => { this.emailError(false); - this.additionalCode(''); - this.additionalCodeVisibility(false); }, password: () => this.passwordError(false), - additionalCode: () => this.additionalCodeError(false), - additionalCodeVisibility: () => this.additionalCodeError(false), - submitError: value => value || this.submitErrorAddidional(''), signMeType: iValue => this.signMe(LoginSignMeType.DefaultOn === iValue), @@ -121,16 +112,13 @@ class LoginUserView extends AbstractViewCenter { submitCommand(self, event) { let email = this.email().trim(), valid = event.target.form.reportValidity() && email, - pass = this.password(), - totp = this.additionalCodeVisibility(), - code = totp ? this.additionalCode() : ''; + pass = this.password(); this.emailError(!email); this.passwordError(!pass); - this.additionalCodeError(totp && !code); let pluginResultCode = 0, pluginResultMessage = ''; - Plugins.runHook('user-login-submit', [(iResultCode, sResultMessage) => { + runHook('user-login-submit', [(iResultCode, sResultMessage) => { pluginResultCode = iResultCode; pluginResultMessage = sResultMessage; }]); @@ -156,13 +144,6 @@ class LoginUserView extends AbstractViewCenter { } this.submitError(getNotification(iError, oData.ErrorMessage, Notification.UnknownNotification)); this.submitErrorAddidional((oData && oData.ErrorMessageAdditional) || ''); - } else if (oData.TwoFactorAuth) { - this.submitRequest(false); - this.additionalCode(''); - this.additionalCodeVisibility(true); - let input = this.querySelector('.inputAdditionalCode'); - input.required = true; - setTimeout(() => input.focus(), 100); } else { rl.route.reload(); } @@ -170,9 +151,7 @@ class LoginUserView extends AbstractViewCenter { email, pass, !!this.signMe(), - this.bSendLanguage ? this.language() : '', - code, - !!(totp && this.additionalCodeSignMe()) + this.bSendLanguage ? this.language() : '' ); Local.set(ClientSideKeyName.LastSignMe, this.signMe() ? '-1-' : '-0-'); diff --git a/dev/View/User/MailBox/FolderList.js b/dev/View/User/MailBox/FolderList.js index 4acbe3cfb..63f286d3b 100644 --- a/dev/View/User/MailBox/FolderList.js +++ b/dev/View/User/MailBox/FolderList.js @@ -26,7 +26,6 @@ export class FolderListMailBoxUserView extends AbstractViewLeft { this.composeInEdit = AppUserStore.composeInEdit; - this.messageList = MessageUserStore.list; this.folderList = FolderUserStore.folderList; this.folderListSystem = FolderUserStore.folderListSystem; this.foldersChanging = FolderUserStore.foldersChanging; diff --git a/dev/View/User/MailBox/MessageList.js b/dev/View/User/MailBox/MessageList.js index b1b48ba62..27459d8bb 100644 --- a/dev/View/User/MailBox/MessageList.js +++ b/dev/View/User/MailBox/MessageList.js @@ -52,7 +52,6 @@ export class MessageListMailBoxUserView extends AbstractViewRight { constructor() { super('User/MailBox/MessageList', 'MailMessageList'); - this.sLastUid = null; this.bPrefetch = false; this.emptySubjectValue = ''; @@ -69,43 +68,34 @@ export class MessageListMailBoxUserView extends AbstractViewRight { this.popupVisibility = ko.computed(() => 0 < popupVisibilityNames().length); - this.message = MessageUserStore.message; this.messageList = MessageUserStore.list; - this.messageListDisableAutoSelect = MessageUserStore.listDisableAutoSelect; - this.folderList = FolderUserStore.folderList; + this.sortSupported = FolderUserStore.sortSupported; this.composeInEdit = AppUserStore.composeInEdit; this.leftPanelDisabled = leftPanelDisabled; - this.selectorMessageSelected = MessageUserStore.selectorMessageSelected; - this.selectorMessageFocused = MessageUserStore.selectorMessageFocused; this.isMessageSelected = MessageUserStore.isMessageSelected; this.messageListSearch = MessageUserStore.listSearch; - this.messageListThreadUid = MessageUserStore.listThreadUid; this.messageListError = MessageUserStore.listError; this.folderMenuForMove = FolderUserStore.folderMenuForMove; this.useCheckboxesInList = SettingsUserStore.useCheckboxesInList; - this.mainMessageListSearch = MessageUserStore.mainMessageListSearch; - this.messageListEndFolder = MessageUserStore.listEndFolder; this.messageListEndThreadUid = MessageUserStore.listEndThreadUid; this.messageListCheckedOrSelected = MessageUserStore.listCheckedOrSelected; - this.messageListCheckedOrSelectedUidsWithSubMails = MessageUserStore.listCheckedOrSelectedUidsWithSubMails; this.messageListCompleteLoadingThrottle = MessageUserStore.listCompleteLoading; this.messageListCompleteLoadingThrottleForAnimation = MessageUserStore.listLoadingAnimation; initOnStartOrLangChange(() => this.emptySubjectValue = i18n('MESSAGE_LIST/EMPTY_SUBJECT_TEXT')); - this.userQuota = QuotaUserStore.quota; - this.userUsageSize = QuotaUserStore.usage; this.userUsageProc = QuotaUserStore.percentage; this.addObservables({ moveDropdownTrigger: false, moreDropdownTrigger: false, + sortDropdownTrigger: false, dragOverArea: null, dragOverBodyArea: null, @@ -137,7 +127,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight { }, inputProxyMessageListSearch: { - read: this.mainMessageListSearch, + read: MessageUserStore.mainMessageListSearch, write: value => this.sLastSearchValue = value }, @@ -146,19 +136,19 @@ export class MessageListMailBoxUserView extends AbstractViewRight { return c && MessageUserStore.list.length > c; }, - hasMessages: () => 0 < this.messageList.length, + hasMessages: () => 0 < MessageUserStore.list.length, - isSpamFolder: () => (FolderUserStore.spamFolder() || 0) === this.messageListEndFolder(), + isSpamFolder: () => (FolderUserStore.spamFolder() || 0) === MessageUserStore.listEndFolder(), isSpamDisabled: () => UNUSED_OPTION_VALUE === FolderUserStore.spamFolder(), - isTrashFolder: () => (FolderUserStore.trashFolder() || 0) === this.messageListEndFolder(), + isTrashFolder: () => (FolderUserStore.trashFolder() || 0) === MessageUserStore.listEndFolder(), - isDraftFolder: () => (FolderUserStore.draftFolder() || 0) === this.messageListEndFolder(), + isDraftFolder: () => (FolderUserStore.draftFolder() || 0) === MessageUserStore.listEndFolder(), - isSentFolder: () => (FolderUserStore.sentFolder() || 0) === this.messageListEndFolder(), + isSentFolder: () => (FolderUserStore.sentFolder() || 0) === MessageUserStore.listEndFolder(), - isArchiveFolder: () => (FolderUserStore.archiveFolder() || 0) === this.messageListEndFolder(), + isArchiveFolder: () => (FolderUserStore.archiveFolder() || 0) === MessageUserStore.listEndFolder(), isArchiveDisabled: () => UNUSED_OPTION_VALUE === FolderUserStore.archiveFolder(), @@ -174,17 +164,28 @@ export class MessageListMailBoxUserView extends AbstractViewRight { mobileCheckedStateHide: () => ThemeStore.isMobile() ? !MessageUserStore.listChecked().length : true, - messageListFocused: () => Scope.MessageList === AppUserStore.focusedState() + messageListFocused: () => Scope.MessageList === AppUserStore.focusedState(), + + sortText: () => { + let mode = FolderUserStore.sortMode(), + desc = '' === mode || mode.includes('REVERSE'); + mode = mode.split(/\s+/); + if (mode.includes('FROM')) { + return '@' + (desc ? '⬆' : '⬇'); + } + if (mode.includes('SUBJECT')) { + return '𝐒' + (desc ? '⬆' : '⬇'); + } + return (mode.includes('SIZE') ? '✉' : '📅') + (desc ? '⬇' : '⬆'); + } }); this.hasCheckedOrSelectedLines = MessageUserStore.hasCheckedOrSelected, - this.quotaTooltip = this.quotaTooltip.bind(this); - this.selector = new Selector( - this.messageList, - this.selectorMessageSelected, - this.selectorMessageFocused, + MessageUserStore.list, + MessageUserStore.selectorMessageSelected, + MessageUserStore.selectorMessageFocused, '.messageListItem .actionHandle', '.messageListItem .checkboxMessage', '.messageListItem.focused' @@ -209,7 +210,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight { addEventListener('mailbox.message.show', e => { const sFolder = e.detail.Folder, sUid = e.detail.Uid; - const message = this.messageList.find( + const message = MessageUserStore.list.find( item => item && sFolder === item.folder && sUid === item.uid ); @@ -246,6 +247,11 @@ export class MessageListMailBoxUserView extends AbstractViewRight { }); } + changeSort(self, event) { + FolderUserStore.sortMode(event.target.closest('li').dataset.sort); + this.reloadCommand(); + } + clearCommand() { if (Settings.capa(Capa.DangerousActions)) { showScreenPopup(FolderClearPopupView, [FolderUserStore.currentFolder()]); @@ -375,7 +381,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight { return false; }); - if (!SettingsUserStore.usePreviewPane() && !this.message()) { + if (!SettingsUserStore.usePreviewPane() && !MessageUserStore.message()) { this.selector.iFocusedNextHelper = up ? -1 : 1; } else { this.selector.iSelectNextHelper = up ? -1 : 1; @@ -391,18 +397,18 @@ export class MessageListMailBoxUserView extends AbstractViewRight { } useAutoSelect() { - return !this.messageListDisableAutoSelect() - && !/is:unseen/.test(this.mainMessageListSearch()) + return !MessageUserStore.listDisableAutoSelect() + && !/is:unseen/.test(MessageUserStore.mainMessageListSearch()) && SettingsUserStore.usePreviewPane(); } searchEnterAction() { - this.mainMessageListSearch(this.sLastSearchValue); + MessageUserStore.mainMessageListSearch(this.sLastSearchValue); this.inputMessageListSearchFocus(false); } cancelSearch() { - this.mainMessageListSearch(''); + MessageUserStore.mainMessageListSearch(''); this.inputMessageListSearchFocus(false); } @@ -571,7 +577,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight { } flagMessages(currentMessage) { - const checked = this.messageListCheckedOrSelected(); + const checked = MessageUserStore.listCheckedOrSelected(); if (currentMessage) { const checkedUids = checked.map(message => message.uid); if (checkedUids.includes(currentMessage.uid)) { @@ -591,7 +597,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight { } flagMessagesFast(bFlag) { - const checked = this.messageListCheckedOrSelected(); + const checked = MessageUserStore.listCheckedOrSelected(); if (checked.length) { if (undefined === bFlag) { const flagged = checked.filter(message => message.isFlagged()); @@ -611,7 +617,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight { } seenMessagesFast(seen) { - const checked = this.messageListCheckedOrSelected(); + const checked = MessageUserStore.listCheckedOrSelected(); if (checked.length) { if (undefined === seen) { const unseen = checked.filter(message => message.isUnseen()); @@ -656,7 +662,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight { !this.messageListSearchDesc() && !this.messageListError() && !this.messageListEndThreadUid() && - this.messageList.length && + MessageUserStore.list.length && (this.isSpamFolder() || this.isTrashFolder()) ); } @@ -700,7 +706,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight { initShortcuts() { shortcuts.add('enter,open', '', Scope.MessageList, () => { - if (this.message() && this.useAutoSelect()) { + if (MessageUserStore.message() && this.useAutoSelect()) { dispatchEvent(new CustomEvent('mailbox.message-view.toggle-full-screen')); return false; } @@ -756,9 +762,9 @@ export class MessageListMailBoxUserView extends AbstractViewRight { } shortcuts.add('t', '', [Scope.MessageList], () => { - let message = this.selectorMessageSelected(); + let message = MessageUserStore.selectorMessageSelected(); if (!message) { - message = this.selectorMessageFocused(); + message = MessageUserStore.selectorMessageFocused(); } if (message && 0 < message.threadsLen()) { @@ -831,7 +837,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight { return false; }); shortcuts.add('tab,arrowright', '', Scope.MessageList, () => { - this.message() && AppUserStore.focusedState(Scope.MessageView); + MessageUserStore.message() && AppUserStore.focusedState(Scope.MessageView); return false; }); @@ -841,7 +847,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight { prefetchNextTick() { if (!this.bPrefetch && !ifvisible.now() && this.viewModelVisible) { - const message = this.messageList.find( + const message = MessageUserStore.list.find( item => item && !hasRequestedMessage(item.folder, item.uid) ); if (message) { @@ -866,15 +872,15 @@ export class MessageListMailBoxUserView extends AbstractViewRight { advancedSearchClick() { Settings.capa(Capa.SearchAdv) - && showScreenPopup(AdvancedSearchPopupView, [this.mainMessageListSearch()]); + && showScreenPopup(AdvancedSearchPopupView, [MessageUserStore.mainMessageListSearch()]); } quotaTooltip() { return i18n('MESSAGE_LIST/QUOTA_SIZE', { - SIZE: FileInfo.friendlySize(this.userUsageSize()), - PROC: this.userUsageProc(), - LIMIT: FileInfo.friendlySize(this.userQuota()) - }); + SIZE: FileInfo.friendlySize(QuotaUserStore.usage()), + PROC: QuotaUserStore.percentage(), + LIMIT: FileInfo.friendlySize(QuotaUserStore.quota()) + }).replace(/<[^>]+>/g, ''); } initUploaderForAppend() { diff --git a/dev/View/User/MailBox/MessageView.js b/dev/View/User/MailBox/MessageView.js index 939e0526b..c3301dced 100644 --- a/dev/View/User/MailBox/MessageView.js +++ b/dev/View/User/MailBox/MessageView.js @@ -71,8 +71,6 @@ class MessageViewMailBoxUserView extends AbstractViewRight { moreDropdownTrigger: false }); - this.pswp = null; - this.moveAction = moveAction; this.allowComposer = Settings.capa(Capa.Composer); @@ -84,7 +82,6 @@ class MessageViewMailBoxUserView extends AbstractViewRight { this.message = MessageUserStore.message; this.hasCheckedMessages = MessageUserStore.hasCheckedMessages; - this.messageListCheckedOrSelectedUidsWithSubMails = MessageUserStore.listCheckedOrSelectedUidsWithSubMails; this.messageLoadingThrottle = MessageUserStore.messageLoading; this.messagesBodiesDom = MessageUserStore.messagesBodiesDom; this.useThreads = SettingsUserStore.useThreads; @@ -136,6 +133,8 @@ class MessageViewMailBoxUserView extends AbstractViewRight { viewReplyTo: '', viewTimeStamp: 0, viewSize: '', + viewSpamScore: 0, + viewSpamStatus: '', viewLineAsCss: '', viewViewLink: '', viewUnsubscribeLink: '', @@ -220,13 +219,15 @@ class MessageViewMailBoxUserView extends AbstractViewRight { this.viewFromShort(message.fromToLine(true, true)); this.viewFromDkimData(message.fromDkimData()); this.viewToShort(message.toToLine(true, true)); - this.viewFrom(message.fromToLine(false)); - this.viewTo(message.toToLine(false)); - this.viewCc(message.ccToLine(false)); - this.viewBcc(message.bccToLine(false)); - this.viewReplyTo(message.replyToToLine(false)); + this.viewFrom(message.fromToLine()); + this.viewTo(message.toToLine()); + this.viewCc(message.ccToLine()); + this.viewBcc(message.bccToLine()); + this.viewReplyTo(message.replyToToLine()); this.viewTimeStamp(message.dateTimeStampInUTC()); this.viewSize(message.friendlySize()); + this.viewSpamScore(message.spamScore()); + this.viewSpamStatus(i18n(message.isSpam() ? 'GLOBAL/SPAM' : 'GLOBAL/NOT_SPAM') + ': ' + message.spamResult()); this.viewLineAsCss(message.lineAsCss()); this.viewViewLink(message.viewLink()); this.viewUnsubscribeLink(message.getFirstUnsubsribeLink()); @@ -717,7 +718,7 @@ class MessageViewMailBoxUserView extends AbstractViewRight { * @returns {string} */ printableCheckedMessageCount() { - const cnt = this.messageListCheckedOrSelectedUidsWithSubMails().length; + const cnt = MessageUserStore.listCheckedOrSelectedUidsWithSubMails().length; return 0 < cnt ? (100 > cnt ? cnt : '99+') : ''; } diff --git a/package.json b/package.json index 3e89b199b..6e9a3f43e 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "title": "SnappyMail", "description": "Simple, modern & fast web-based email client", "private": true, - "version": "2.4.2", + "version": "2.5.0-rc.4", "homepage": "https://snappymail.eu", "author": { "name": "DJ Maze", @@ -42,11 +42,6 @@ ], "readmeFilename": "README.md", "devDependencies": { - "@babel/core": "7.8.7", - "@babel/plugin-proposal-class-properties": "7.8.3", - "@babel/plugin-proposal-decorators": "7.8.3", - "@babel/preset-env": "7.8.7", - "@babel/runtime-corejs3": "^7.12.13", "babel-eslint": "10.1.0", "core-js": "^3.8.3", "eslint": "6.8.0", @@ -75,7 +70,6 @@ "dependencies": { "gulp-rollup-2": "^1.2.1", "rollup": "^2.38.0", - "rollup-plugin-babel": "^4.4.0", "rollup-plugin-external-globals": "^0.6.1", "rollup-plugin-html": "^0.2.1", "rollup-plugin-includepaths": "^0.2.4", diff --git a/plugins/README.md b/plugins/README.md new file mode 100644 index 000000000..177139cba --- /dev/null +++ b/plugins/README.md @@ -0,0 +1,345 @@ + +class Plugin extends \RainLoop\Plugins\AbstractPlugin + +# Hooks + +$Plugin->addHook('hook.name', 'functionName'); + +## Login + +### login.credentials.step-1 + params: + string &$sEmail + +### login.credentials.step-2 + params: + string &$sEmail + string &$sPassword + +### login.credentials + params: + string &$sEmail + string &$sLogin + string &$sPassword + +### login.success + params: + \RainLoop\Model\Account $oAccount + +## IMAP + +### imap.credentials + params: + \RainLoop\Model\Account $oAccount + array &$aCredentials + +### imap.before-connect + params: + \RainLoop\Model\Account $oAccount + \MailSo\Mail\MailClient $oMailClient + array $aCredentials + +### imap.after-connect + params: + \RainLoop\Model\Account $oAccount + \MailSo\Mail\MailClient $oMailClient + array $aCredentials + +### imap.before-login + params: + \RainLoop\Model\Account $oAccount + \MailSo\Mail\MailClient $oMailClient + array $aCredentials + +### imap.after-login + params: + \RainLoop\Model\Account $oAccount + \MailSo\Mail\MailClient $oMailClient + bool $bSuccess + array $aCredentials + +## Sieve + +### sieve.credentials + params: + \RainLoop\Model\Account $oAccount + array &$aCredentials + +### sieve.before-connect + params: + \RainLoop\Model\Account $oAccount + \MailSo\Sieve\ManageSieveClient $oSieveClient + array $aCredentials + +### sieve.after-connect + params: + \RainLoop\Model\Account $oAccount + \MailSo\Sieve\ManageSieveClient $oSieveClient + array $aCredentials + +### sieve.before-login + params: + \RainLoop\Model\Account $oAccount + \MailSo\Sieve\ManageSieveClient $oSieveClient + bool $bSuccess + array $aCredentials + +### sieve.after-login + params: + \RainLoop\Model\Account $oAccount + \MailSo\Sieve\ManageSieveClient $oSieveClient + array $aCredentials + +## SMTP + +### smtp.credentials + params: + \RainLoop\Model\Account $oAccount + array &$aCredentials + +### smtp.before-connect + params: + \RainLoop\Model\Account $oAccount + \MailSo\Smtp\SmtpClient $oSmtpClient + array $aCredentials + +### smtp.after-connect + params: + \RainLoop\Model\Account $oAccount + \MailSo\Smtp\SmtpClient $oSmtpClient + array $aCredentials + +### smtp.before-login + params: + \RainLoop\Model\Account $oAccount + \MailSo\Smtp\SmtpClient $oSmtpClient + array $aCredentials + +### smtp.after-login + params: + \RainLoop\Model\Account $oAccount + \MailSo\Smtp\SmtpClient $oSmtpClient + bool $bSuccess + array $aCredentials + +## Folders + +### filter.folders-post + params: + \RainLoop\Model\Account $oAccount + \MailSo\Mail\FolderCollection $oFolderCollection + +### filter.folders-complete + params: + \RainLoop\Model\Account $oAccount + \MailSo\Mail\FolderCollection $oFolderCollection + +### filter.folders-system-types + params: + \RainLoop\Model\Account $oAccount + array &$aList + +### filter.system-folders-names + params: + \RainLoop\Model\Account $oAccount + array &$aCache + +## Others + +### filter.account + params: + \RainLoop\Model\Account $oAccount + +### filter.action-params + params: + string $sMethodName + array &$aCurrentActionParams + +### filter.app-data + params: + bool $bAdmin + array &$aAppData + +### filter.application-config + params: + \RainLoop\Config\Application $oConfig + +### filter.build-message + params: + \MailSo\Mime\Message $oMessage + +### filter.build-read-receipt-message + params: + \MailSo\Mime\Message $oMessage + \RainLoop\Model\Account $oAccount + +### filter.domain + params: + \RainLoop\Model\Domain &$oDomain + +### filter.fabrica + params: + string $sName + mixed &$mResult + \RainLoop\Model\Account $oAccount + +### filter.http-paths + params: + array &$aPaths + +### filter.http-query + params: + string &$sQuery + +### filter.json-response + params: + string $sAction + array &$aResponseItem + +### filter.message-html' +### filter.message-plain + params: + \RainLoop\Model\Account $oAccount + \MailSo\Mime\Message $oMessage + string &$sTextConverted + +### filter.message-rcpt + params: + \RainLoop\Model\Account $oAccount + \MailSo\Mime\EmailCollection $oRcpt + +### filter.read-receipt-message-plain + params: + \RainLoop\Model\Account $oAccount + \MailSo\Mime\Message $oMessage + string &$sText + +### filter.result-message + params: + \MailSo\Mime\Message $oMessage + +### filter.save-message + params: + \MailSo\Mime\Message $oMessage + +### filter.send-message + params: + \MailSo\Mime\Message $oMessage + +### filter.send-message-stream + params: + \RainLoop\Model\Account $oAccount + resource &$rMessageStream + int &$iMessageStreamSize + +### filter.send-read-receipt-message + params: + \MailSo\Mime\Message $oMessage + \RainLoop\Model\Account $oAccount + +### filter.smtp-from + params: + \RainLoop\Model\Account $oAccount + \MailSo\Mime\Message $oMessage + string &$sFrom + +### filter.smtp-hidden-rcpt + params: + \RainLoop\Model\Account $oAccount + \MailSo\Mime\Message $oMessage + array &$aHiddenRcpt + +### filter.smtp-message-stream + params: + \RainLoop\Model\Account $oAccount + resource &$rMessageStream + int &$iMessageStreamSize + +### filter.upload-response + params: + array &$aResponseItem + +### json.action-post-call + params: + string $sAction + array &$aResponseItem + +### json.action-post-call + params: + string $sAction + array &$aResponseItem + +### json.action-pre-call + params: + string $sAction + +### json.action-pre-call + params: + string $sAction + +### json.suggestions-input-parameters + params: + string &$sQuery + int &$iLimit + \RainLoop\Model\Account $oAccount + +### json.suggestions-post + params: + array &$aResult + string $sQuery + \RainLoop\Model\Account $oAccount + int $iLimit + +### json.suggestions-pre + params: + array &$aResult + string $sQuery + \RainLoop\Model\Account $oAccount + int $iLimit + +### main.default-response + params: + string $sActionName + array &$aResponseItem + +### main.default-response + params: + string $sActionName + array &$aResponseItem + +### main.default-response + params: + string $sActionName + array &$aResponseItem + +### main.default-response-data + params: + string $sActionName + mixed &$mResult + +### main.default-response-data + params: + string $sActionName + mixed &$mResult + +### main.default-response-data + params: + string $sActionName + mixed &$mResult + +### main.default-response-error-data + params: + string $sActionName + int &$iErrorCode + string &$sErrorMessage + +### main.fabrica + params: + string $sName + mixed &$mResult + +### service.app-delay-start-begin + no params + +### service.app-delay-start-end + no params diff --git a/plugins/auto-domain-grab/index.php b/plugins/auto-domain-grab/index.php index 1fe9307b5..64a5f0ec5 100644 --- a/plugins/auto-domain-grab/index.php +++ b/plugins/auto-domain-grab/index.php @@ -22,8 +22,8 @@ class AutoDomainGrabPlugin extends \RainLoop\Plugins\AbstractPlugin public function Init() : void { - $this->addHook('filter.smtp-credentials', 'FilterSmtpCredentials'); - $this->addHook('filter.imap-credentials', 'FilterImapCredentials'); + $this->addHook('smtp.credentials', 'FilterSmtpCredentials'); + $this->addHook('imap.credentials', 'FilterImapCredentials'); } /** diff --git a/plugins/black-list/index.php b/plugins/black-list/index.php index a820cabda..3b6aefd63 100644 --- a/plugins/black-list/index.php +++ b/plugins/black-list/index.php @@ -10,7 +10,7 @@ class BlackListPlugin extends \RainLoop\Plugins\AbstractPlugin public function Init() : void { - $this->addHook('filter.login-credentials', 'FilterLoginCredentials'); + $this->addHook('login.credentials', 'FilterLoginCredentials'); } /** diff --git a/plugins/change-smtp-ehlo-message/index.php b/plugins/change-smtp-ehlo-message/index.php index 8860653da..ad1b1d280 100644 --- a/plugins/change-smtp-ehlo-message/index.php +++ b/plugins/change-smtp-ehlo-message/index.php @@ -9,7 +9,7 @@ class ChangeSmtpEhloMessagePlugin extends \RainLoop\Plugins\AbstractPlugin public function Init() : void { - $this->addHook('filter.smtp-credentials', 'FilterSmtpCredentials'); + $this->addHook('smtp.credentials', 'FilterSmtpCredentials'); } /** diff --git a/plugins/ckeditor/ckeditor.less b/plugins/ckeditor/ckeditor.less new file mode 100644 index 000000000..3a1349013 --- /dev/null +++ b/plugins/ckeditor/ckeditor.less @@ -0,0 +1,213 @@ +/*.cke_button__sourcedialog_label { + display: none !important; +}*/ + +.cke_chrome { + border: 1px solid #ccc !important; +} + +.cke_toolgroup { + padding-right: 0 !important; + background: #FBFBFB !important; +} + +.cke_toolgroup, .cke_combo_button { + border: 1px solid #A6A6A6 !important; +} + +.cke_top { + padding: 2px; + box-shadow: none !important; + border-bottom: 1px solid #b6b6b6 !important; + background: #F0F0F0 !important; +} + +.cke_combo_on a.cke_combo_button, +.cke_combo_off a.cke_combo_button:hover, +.cke_combo_off a.cke_combo_button:focus, +.cke_combo_off a.cke_combo_button:active { + padding: 1px !important; + margin-left: 0 !important; +} + +.cke_toolgroup a.cke_button:last-child:after, +.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after { + border: none !important; + height: 0 !important; + width: 0 !important; + margin: 0 !important; + padding: 0 !important; +} + +.cke_button_on { + background: #ddd !important; +} + +.cke_combo { + margin-top: 1px !important; +} + +.cke_combo__fontsize { + margin-left: 3px !important; + .cke_combo_text { + width: 40px !important; + } +} + +.cke_combo_text { + line-height: 24px !important; + padding-left: 8px !important; +} + +.cke_combo_button { + background: #FBFBFB !important; +} + +.cke_source { + font-family: var(--fontMono) !important; + padding: 10px !important; + padding-right: 0 !important; + box-shadow: none !important; +} + +.cke_plain { + + background-color: #fff; + outline: none; + overflow: auto; + z-index: 1; + margin: 0; + border: 0; + + padding: 10px; + padding-right: 0; + white-space: pre-wrap; + font-family: var(--fontMono), monospace; + font-size: 13px; + line-height: 16px; + color: #333; + resize: none; + + border-radius: 0; + box-shadow: none; + box-sizing: border-box; +} + +.cke_plain:focus, .cke_source:focus { + border: 0; +} + +.b-compose .cke_chrome { + border-right: 0; + border-left: 0; + border-bottom: 0; + box-shadow: none; +} + +.cke_wysiwyg_div { + + padding: 10px !important; + font-family: var(--fontSans); + font-size: 13px; + line-height: 16px; + color: #333; + + ul { + padding-left: 40px; + li { + list-style-type: disc !important; + } + } + + ol { + padding-left: 40px; + li { + list-style-type: decimal !important; + } + } + + pre, code { + margin: 0; + padding: 0; + background: #fff; + border: none; + border-radius: 0; + font-family: var(--fontMono); + display: block; + word-break: normal; + word-wrap: break-word; + background-color: #f9f9f9; + } + + code { + display: inline; + padding: 2px 5px; + } + + pre { + padding: 5px 10px; + border-radius: 5px; + background-color: #f9f9f9; + } + + pre > code { + padding: 0; + } + + blockquote { + border: 0; + border-left: solid 2px #444; + margin: 5px 0 5px 5px; + padding-left: 5px; + } + + blockquote p { + margin: 0 0 10px; + font-size: 14px; + line-height: 20px; + } + + img { + vertical-align: bottom; + } + + a { + color: blue; + text-decoration: underline; + + &:visited { + color: #609; + } + &:active { + color: red; + } + } +} + +.cke_dialog { + + a:hover { + text-decoration: none; + } + + .cke_dialog_ui_labeled_content { + margin-top: 5px; + margin-bottom: 5px; + } + + .cke_dialog_ui_input_select, .cke_dialog_ui_input_text, .cke_dialog_ui_input_textarea { + + box-shadow: none; + border-radius: 2px; + + &:focus { + outline: 0; + border: 1px solid #999; + } + } + + .cke_dialog_ui_input_select, .cke_dialog_ui_input_text { + height: 25px; + line-height: 25px; + } +} diff --git a/plugins/ckeditor/index.php b/plugins/ckeditor/index.php index 8659d7efc..d1973d66d 100644 --- a/plugins/ckeditor/index.php +++ b/plugins/ckeditor/index.php @@ -4,9 +4,9 @@ class CKEditorPlugin extends \RainLoop\Plugins\AbstractPlugin { const NAME = 'CKEditor', - VERSION = '2.0', - RELEASE = '2021-03-25', - REQUIRED = '2.4.2', + VERSION = '2.1', + RELEASE = '2021-04-01', + REQUIRED = '2.5.0', DESCRIPTION = 'Use CKEditor instead of Squire as WYSIWYG'; public function Init() : void @@ -32,6 +32,7 @@ class CKEditorPlugin extends \RainLoop\Plugins\AbstractPlugin } if (\is_file("{$path}/ckeditor.js")) { + $this->addCss('ckeditor.less'); $this->addJs('ckeditor.js'); } } diff --git a/plugins/custom-auth-example/index.php b/plugins/custom-auth-example/index.php index 59f2b0588..e68572c14 100644 --- a/plugins/custom-auth-example/index.php +++ b/plugins/custom-auth-example/index.php @@ -9,7 +9,7 @@ class CustomAuthExamplePlugin extends \RainLoop\Plugins\AbstractPlugin public function Init() : void { - $this->addHook('filter.login-credentials', 'FilterLoginСredentials'); + $this->addHook('login.credentials', 'FilterLoginCredentials'); } /** @@ -19,7 +19,7 @@ class CustomAuthExamplePlugin extends \RainLoop\Plugins\AbstractPlugin * * @throws \RainLoop\Exceptions\ClientException */ - public function FilterLoginСredentials(&$sEmail, &$sLogin, &$sPassword) + public function FilterLoginCredentials(&$sEmail, &$sLogin, &$sPassword) { // Your custom php logic // You may change login credentials diff --git a/plugins/custom-login-mapping/index.php b/plugins/custom-login-mapping/index.php index ac3d577da..3c78cd10f 100644 --- a/plugins/custom-login-mapping/index.php +++ b/plugins/custom-login-mapping/index.php @@ -10,7 +10,7 @@ class CustomLoginMappingPlugin extends \RainLoop\Plugins\AbstractPlugin public function Init() : void { - $this->addHook('filter.login-credentials', 'FilterLoginСredentials'); + $this->addHook('login.credentials', 'FilterLoginCredentials'); } /** @@ -20,7 +20,7 @@ class CustomLoginMappingPlugin extends \RainLoop\Plugins\AbstractPlugin * * @throws \RainLoop\Exceptions\ClientException */ - public function FilterLoginСredentials(&$sEmail, &$sLogin, &$sPassword) + public function FilterLoginCredentials(&$sEmail, &$sLogin, &$sPassword) { $sMapping = \trim($this->Config()->Get('plugin', 'mapping', '')); if (!empty($sMapping)) diff --git a/plugins/override-smtp-credentials/index.php b/plugins/override-smtp-credentials/index.php index 9b4732458..1b019e565 100644 --- a/plugins/override-smtp-credentials/index.php +++ b/plugins/override-smtp-credentials/index.php @@ -10,7 +10,7 @@ class OverrideSmtpCredentialsPlugin extends \RainLoop\Plugins\AbstractPlugin public function Init() : void { - $this->addHook('filter.smtp-credentials', 'FilterSmtpCredentials'); + $this->addHook('smtp.credentials', 'FilterSmtpCredentials'); } /** diff --git a/plugins/proxyauth-login-example/index.php b/plugins/proxyauth-login-example/index.php index caf010552..18c35ea33 100644 --- a/plugins/proxyauth-login-example/index.php +++ b/plugins/proxyauth-login-example/index.php @@ -9,7 +9,7 @@ class ProxyauthLoginExamplePlugin extends \RainLoop\Plugins\AbstractPlugin public function Init() : void { - $this->addHook('event.login-post-login-provide', 'EventLoginPostLoginProvide'); + $this->addHook('login.success', 'EventLoginPostLoginProvide'); } /** diff --git a/plugins/white-list/index.php b/plugins/white-list/index.php index fd01124ee..b2e4bebd8 100644 --- a/plugins/white-list/index.php +++ b/plugins/white-list/index.php @@ -10,7 +10,7 @@ class WhiteListPlugin extends \RainLoop\Plugins\AbstractPlugin public function Init() : void { - $this->addHook('filter.login-credentials', 'FilterLoginCredentials'); + $this->addHook('login.credentials', 'FilterLoginCredentials'); } /** diff --git a/snappymail/v/0.0.0/app/handle.php b/snappymail/v/0.0.0/app/handle.php index ccac1b8e1..8c4d2dffe 100644 --- a/snappymail/v/0.0.0/app/handle.php +++ b/snappymail/v/0.0.0/app/handle.php @@ -30,16 +30,6 @@ if (\class_exists('RainLoop\Api')) { \MailSo\Base\Loader::Init(); - if (!\function_exists('yaml_parse')) { - function yaml_parse(string $input) { - require_once RAINLOOP_APP_LIBRARIES_PATH.'spyc/Spyc.php'; - return \Spyc::YAMLLoadString(\str_replace(array(': >-', ': |-', ': |+'), array(': >', ': |', ': |'), $input)); - } - function yaml_parse_file(string $filename) { - return yaml_parse(\file_get_contents($filename)); - } - } - if (!empty($_ENV['RAINLOOP_INCLUDE_AS_API'])) { if (!\defined('APP_API_STARTED')) diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Draw/DrawerInterface.php b/snappymail/v/0.0.0/app/libraries/Imagine/Draw/DrawerInterface.php deleted file mode 100644 index c48dff876..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Draw/DrawerInterface.php +++ /dev/null @@ -1,149 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Draw; - -use Imagine\Image\AbstractFont; -use Imagine\Image\BoxInterface; -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Image\PointInterface; -use Imagine\Exception\RuntimeException; - -/** - * Interface for the drawer - */ -interface DrawerInterface -{ - /** - * Draws an arc on a starting at a given x, y coordinates under a given - * start and end angles - * - * @param PointInterface $center - * @param BoxInterface $size - * @param integer $start - * @param integer $end - * @param ColorInterface $color - * @param integer $thickness - * - * @throws RuntimeException - * - * @return DrawerInterface - */ - public function arc(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $thickness = 1); - - /** - * Same as arc, but also connects end points with a straight line - * - * @param PointInterface $center - * @param BoxInterface $size - * @param integer $start - * @param integer $end - * @param ColorInterface $color - * @param Boolean $fill - * @param integer $thickness - * - * @throws RuntimeException - * - * @return DrawerInterface - */ - public function chord(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1); - - /** - * Draws and ellipse with center at the given x, y coordinates, and given - * width and height - * - * @param PointInterface $center - * @param BoxInterface $size - * @param ColorInterface $color - * @param Boolean $fill - * @param integer $thickness - * - * @throws RuntimeException - * - * @return DrawerInterface - */ - public function ellipse(PointInterface $center, BoxInterface $size, ColorInterface $color, $fill = false, $thickness = 1); - - /** - * Draws a line from start(x, y) to end(x, y) coordinates - * - * @param PointInterface $start - * @param PointInterface $end - * @param ColorInterface $outline - * @param integer $thickness - * - * @return DrawerInterface - */ - public function line(PointInterface $start, PointInterface $end, ColorInterface $outline, $thickness = 1); - - /** - * Same as arc, but connects end points and the center - * - * @param PointInterface $center - * @param BoxInterface $size - * @param integer $start - * @param integer $end - * @param ColorInterface $color - * @param Boolean $fill - * @param integer $thickness - * - * @throws RuntimeException - * - * @return DrawerInterface - */ - public function pieSlice(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1); - - /** - * Places a one pixel point at specific coordinates and fills it with - * specified color - * - * @param PointInterface $position - * @param ColorInterface $color - * - * @throws RuntimeException - * - * @return DrawerInterface - */ - public function dot(PointInterface $position, ColorInterface $color); - - /** - * Draws a polygon using array of x, y coordinates. Must contain at least - * three coordinates - * - * @param array $coordinates - * @param ColorInterface $color - * @param Boolean $fill - * @param integer $thickness - * - * @throws RuntimeException - * - * @return DrawerInterface - */ - public function polygon(array $coordinates, ColorInterface $color, $fill = false, $thickness = 1); - - /** - * Annotates image with specified text at a given position starting on the - * top left of the final text box - * - * The rotation is done CW - * - * @param string $string - * @param AbstractFont $font - * @param PointInterface $position - * @param integer $angle - * @param integer $width - * - * @throws RuntimeException - * - * @return DrawerInterface - */ - public function text($string, AbstractFont $font, PointInterface $position, $angle = 0, $width = null); -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Effects/EffectsInterface.php b/snappymail/v/0.0.0/app/libraries/Imagine/Effects/EffectsInterface.php deleted file mode 100644 index 3593d75da..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Effects/EffectsInterface.php +++ /dev/null @@ -1,80 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Effects; - -use Imagine\Exception\RuntimeException; -use Imagine\Image\Palette\Color\ColorInterface; - -/** - * Interface for the effects - */ -interface EffectsInterface -{ - /** - * Apply gamma correction - * - * @param float $correction - * @return EffectsInterface - * - * @throws RuntimeException - */ - public function gamma($correction); - - /** - * Invert the colors of the image - * - * @return EffectsInterface - * - * @throws RuntimeException - */ - public function negative(); - - /** - * Grayscale the image - * - * @return EffectsInterface - * - * @throws RuntimeException - */ - public function grayscale(); - - /** - * Colorize the image - * - * @param ColorInterface $color - * - * @return EffectsInterface - * - * @throws RuntimeException - */ - public function colorize(ColorInterface $color); - - /** - * Sharpens the image - * - * @return EffectsInterface - * - * @throws RuntimeException - */ - public function sharpen(); - - /** - * Blur the image - * - * @param float|int $sigma - * - * @return EffectsInterface - * - * @throws RuntimeException - */ - public function blur($sigma); -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Exception/Exception.php b/snappymail/v/0.0.0/app/libraries/Imagine/Exception/Exception.php deleted file mode 100644 index 39a67afed..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Exception/Exception.php +++ /dev/null @@ -1,19 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Exception; - -/** - * Imagine-specific exception - */ -interface Exception -{ -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Exception/InvalidArgumentException.php b/snappymail/v/0.0.0/app/libraries/Imagine/Exception/InvalidArgumentException.php deleted file mode 100644 index 5ac139672..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Exception/InvalidArgumentException.php +++ /dev/null @@ -1,19 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Exception; - -/** - * Imagine-specific invalid argument exception - */ -class InvalidArgumentException extends \InvalidArgumentException implements Exception -{ -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Exception/NotSupportedException.php b/snappymail/v/0.0.0/app/libraries/Imagine/Exception/NotSupportedException.php deleted file mode 100644 index fd68ce7c0..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Exception/NotSupportedException.php +++ /dev/null @@ -1,19 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Exception; - -/** - * Should be used when a driver does not support an operation. - */ -class NotSupportedException extends RuntimeException implements Exception -{ -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Exception/OutOfBoundsException.php b/snappymail/v/0.0.0/app/libraries/Imagine/Exception/OutOfBoundsException.php deleted file mode 100644 index f51cc9b4f..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Exception/OutOfBoundsException.php +++ /dev/null @@ -1,19 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Exception; - -/** - * Imagine-specific out of bounds exception - */ -class OutOfBoundsException extends \OutOfBoundsException implements Exception -{ -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Exception/RuntimeException.php b/snappymail/v/0.0.0/app/libraries/Imagine/Exception/RuntimeException.php deleted file mode 100644 index 205ad85e8..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Exception/RuntimeException.php +++ /dev/null @@ -1,19 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Exception; - -/** - * Imagine-specific runtime exception - */ -class RuntimeException extends \RuntimeException implements Exception -{ -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Advanced/Border.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Advanced/Border.php deleted file mode 100644 index 47a3ceb1f..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Advanced/Border.php +++ /dev/null @@ -1,98 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter\Advanced; - -use Imagine\Filter\FilterInterface; -use Imagine\Image\ImageInterface; -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Image\Point; - -/** - * A border filter - */ -class Border implements FilterInterface -{ - /** - * @var ColorInterface - */ - private $color; - - /** - * @var integer - */ - private $width; - - /** - * @var integer - */ - private $height; - - /** - * Constructs Border filter with given color, width and height - * - * @param ColorInterface $color - * @param integer $width Width of the border on the left and right sides of the image - * @param integer $height Height of the border on the top and bottom sides of the image - */ - public function __construct(ColorInterface $color, $width = 1, $height = 1) - { - $this->color = $color; - $this->width = $width; - $this->height = $height; - } - - /** - * {@inheritdoc} - */ - public function apply(ImageInterface $image) - { - $size = $image->getSize(); - $width = $size->getWidth(); - $height = $size->getHeight(); - - $draw = $image->draw(); - - // Draw top and bottom lines - $draw - ->line( - new Point(0, 0), - new Point($width - 1, 0), - $this->color, - $this->height - ) - ->line( - new Point($width - 1, $height - 1), - new Point(0, $height - 1), - $this->color, - $this->height - ) - ; - - // Draw sides - $draw - ->line( - new Point(0, 0), - new Point(0, $height - 1), - $this->color, - $this->width - ) - ->line( - new Point($width - 1, 0), - new Point($width - 1, $height - 1), - $this->color, - $this->width - ) - ; - - return $image; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Advanced/Canvas.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Advanced/Canvas.php deleted file mode 100644 index 685b8ae73..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Advanced/Canvas.php +++ /dev/null @@ -1,74 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter\Advanced; - -use Imagine\Filter\FilterInterface; -use Imagine\Image\ImageInterface; -use Imagine\Image\BoxInterface; -use Imagine\Image\Point; -use Imagine\Image\PointInterface; -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Image\ImagineInterface; - -/** - * A canvas filter - */ -class Canvas implements FilterInterface -{ - /** - * @var BoxInterface - */ - private $size; - - /** - * @var PointInterface - */ - private $placement; - - /** - * @var ColorInterface - */ - private $background; - - /** - * @var ImagineInterface - */ - private $imagine; - - /** - * Constructs Canvas filter with given width and height and the placement of the current image - * inside the new canvas - * - * @param ImagineInterface $imagine - * @param BoxInterface $size - * @param PointInterface $placement - * @param ColorInterface $background - */ - public function __construct(ImagineInterface $imagine, BoxInterface $size, PointInterface $placement = null, ColorInterface $background = null) - { - $this->imagine = $imagine; - $this->size = $size; - $this->placement = $placement ?: new Point(0, 0); - $this->background = $background; - } - - /** - * {@inheritdoc} - */ - public function apply(ImageInterface $image) - { - $canvas = $this->imagine->create($this->size, $this->background); - $canvas->paste($image, $this->placement); - - return $canvas; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Advanced/Grayscale.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Advanced/Grayscale.php deleted file mode 100644 index b3a08b403..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Advanced/Grayscale.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter\Advanced; - -use Imagine\Filter\FilterInterface; -use Imagine\Image\ImageInterface; -use Imagine\Image\Point; - -/** - * The Grayscale filter calculates the gray-value based on RGB. - */ -class Grayscale extends OnPixelBased implements FilterInterface -{ - public function __construct() - { - parent::__construct(function (ImageInterface $image, Point $point) { - $color = $image->getColorAt($point); - $image->draw()->dot($point, $color->grayscale()); - }); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Advanced/OnPixelBased.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Advanced/OnPixelBased.php deleted file mode 100644 index ef297eaf6..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Advanced/OnPixelBased.php +++ /dev/null @@ -1,57 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter\Advanced; - -use Imagine\Exception\InvalidArgumentException; -use Imagine\Filter\FilterInterface; -use Imagine\Image\ImageInterface; -use Imagine\Image\Point; - -/** - * The OnPixelBased takes a callable, and for each pixel, this callable is called with the - * image (\Imagine\Image\ImageInterface) and the current point (\Imagine\Image\Point) - */ -class OnPixelBased implements FilterInterface -{ - protected $callback; - - public function __construct($callback) - { - if (!is_callable($callback)) { - throw new InvalidArgumentException('$callback has to be callable'); - } - - $this->callback = $callback; - } - - /** - * Applies scheduled transformation to ImageInterface instance - * Returns processed ImageInterface instance - * - * @param ImageInterface $image - * - * @return ImageInterface - */ - public function apply(ImageInterface $image) - { - $w = $image->getSize()->getWidth(); - $h = $image->getSize()->getHeight(); - - for ($x = 0; $x < $w; $x++) { - for ($y = 0; $y < $h; $y++) { - call_user_func($this->callback, $image, new Point($x, $y)); - } - } - - return $image; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Advanced/RelativeResize.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Advanced/RelativeResize.php deleted file mode 100644 index 954587ad2..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Advanced/RelativeResize.php +++ /dev/null @@ -1,50 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter\Advanced; - -use Imagine\Exception\InvalidArgumentException; -use Imagine\Filter\FilterInterface; -use Imagine\Image\ImageInterface; - -/** - * The RelativeResize filter allows images to be resized relative to their - * existing dimensions. - */ -class RelativeResize implements FilterInterface -{ - private $method; - private $parameter; - - /** - * Constructs a RelativeResize filter with the given method and argument. - * - * @param string $method BoxInterface method - * @param mixed $parameter Parameter for BoxInterface method - */ - public function __construct($method, $parameter) - { - if (!in_array($method, array('heighten', 'increase', 'scale', 'widen'))) { - throw new InvalidArgumentException(sprintf('Unsupported method: ', $method)); - } - - $this->method = $method; - $this->parameter = $parameter; - } - - /** - * {@inheritdoc} - */ - public function apply(ImageInterface $image) - { - return $image->resize(call_user_func(array($image->getSize(), $this->method), $this->parameter)); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/ApplyMask.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/ApplyMask.php deleted file mode 100644 index 2be2786f9..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/ApplyMask.php +++ /dev/null @@ -1,42 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter\Basic; - -use Imagine\Filter\FilterInterface; -use Imagine\Image\ImageInterface; - -/** - * An apply mask filter - */ -class ApplyMask implements FilterInterface -{ - /** - * @var ImageInterface - */ - private $mask; - - /** - * @param ImageInterface $mask - */ - public function __construct(ImageInterface $mask) - { - $this->mask = $mask; - } - - /** - * {@inheritdoc} - */ - public function apply(ImageInterface $image) - { - return $image->applyMask($this->mask); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Autorotate.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Autorotate.php deleted file mode 100644 index 3ef7cbec7..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Autorotate.php +++ /dev/null @@ -1,87 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter\Basic; - -use Imagine\Filter\FilterInterface; -use Imagine\Image\ImageInterface; -use Imagine\Image\Palette\Color\ColorInterface; - -/** - * Rotates an image automatically based on exif information. - * - * Your attention please: This filter requires the use of the - * ExifMetadataReader to work. - * - * @see https://imagine.readthedocs.org/en/latest/usage/metadata.html - */ -class Autorotate implements FilterInterface -{ - private $color; - - /** - * @param string|array|ColorInterface $color A color - */ - public function __construct($color = '000000') - { - $this->color = $color; - } - - /** - * {@inheritdoc} - */ - public function apply(ImageInterface $image) - { - $metadata = $image->metadata(); - - switch (isset($metadata['ifd0.Orientation']) ? $metadata['ifd0.Orientation'] : null) { - case 1: // top-left - break; - case 2: // top-right - $image->flipHorizontally(); - break; - case 3: // bottom-right - $image->rotate(180, $this->getColor($image)); - break; - case 4: // bottom-left - $image->flipHorizontally(); - $image->rotate(180, $this->getColor($image)); - break; - case 5: // left-top - $image->flipHorizontally(); - $image->rotate(-90, $this->getColor($image)); - break; - case 6: // right-top - $image->rotate(90, $this->getColor($image)); - break; - case 7: // right-bottom - $image->flipHorizontally(); - $image->rotate(90, $this->getColor($image)); - break; - case 8: // left-bottom - $image->rotate(-90, $this->getColor($image)); - break; - default: // Invalid orientation - break; - } - - return $image; - } - - private function getColor(ImageInterface $image) - { - if ($this->color instanceof ColorInterface) { - return $this->color; - } - - return $image->palette()->color($this->color); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Copy.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Copy.php deleted file mode 100644 index 781b23a7e..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Copy.php +++ /dev/null @@ -1,29 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter\Basic; - -use Imagine\Filter\FilterInterface; -use Imagine\Image\ImageInterface; - -/** - * A copy filter - */ -class Copy implements FilterInterface -{ - /** - * {@inheritdoc} - */ - public function apply(ImageInterface $image) - { - return $image->copy(); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Crop.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Crop.php deleted file mode 100644 index 6559e2298..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Crop.php +++ /dev/null @@ -1,54 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter\Basic; - -use Imagine\Image\ImageInterface; -use Imagine\Image\BoxInterface; -use Imagine\Image\PointInterface; -use Imagine\Filter\FilterInterface; - -/** - * A crop filter - */ -class Crop implements FilterInterface -{ - /** - * @var PointInterface - */ - private $start; - - /** - * @var BoxInterface - */ - private $size; - - /** - * Constructs a Crop filter with given x, y, coordinates and crop width and - * height values - * - * @param PointInterface $start - * @param BoxInterface $size - */ - public function __construct(PointInterface $start, BoxInterface $size) - { - $this->start = $start; - $this->size = $size; - } - - /** - * {@inheritdoc} - */ - public function apply(ImageInterface $image) - { - return $image->crop($this->start, $this->size); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Fill.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Fill.php deleted file mode 100644 index 4be0d0f2b..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Fill.php +++ /dev/null @@ -1,43 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter\Basic; - -use Imagine\Filter\FilterInterface; -use Imagine\Image\Fill\FillInterface; -use Imagine\Image\ImageInterface; - -/** - * A fill filter - */ -class Fill implements FilterInterface -{ - /** - * @var FillInterface - */ - private $fill; - - /** - * @param FillInterface $fill - */ - public function __construct(FillInterface $fill) - { - $this->fill = $fill; - } - - /** - * {@inheritdoc} - */ - public function apply(ImageInterface $image) - { - return $image->fill($this->fill); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/FlipHorizontally.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/FlipHorizontally.php deleted file mode 100644 index 50203748d..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/FlipHorizontally.php +++ /dev/null @@ -1,29 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter\Basic; - -use Imagine\Image\ImageInterface; -use Imagine\Filter\FilterInterface; - -/** - * A "flip horizontally" filter - */ -class FlipHorizontally implements FilterInterface -{ - /** - * {@inheritdoc} - */ - public function apply(ImageInterface $image) - { - return $image->flipHorizontally(); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/FlipVertically.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/FlipVertically.php deleted file mode 100644 index 684c31b3d..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/FlipVertically.php +++ /dev/null @@ -1,29 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter\Basic; - -use Imagine\Image\ImageInterface; -use Imagine\Filter\FilterInterface; - -/** - * A "flip vertically" filter - */ -class FlipVertically implements FilterInterface -{ - /** - * {@inheritdoc} - */ - public function apply(ImageInterface $image) - { - return $image->flipVertically(); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Paste.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Paste.php deleted file mode 100644 index bd274a179..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Paste.php +++ /dev/null @@ -1,53 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter\Basic; - -use Imagine\Image\ImageInterface; -use Imagine\Image\PointInterface; -use Imagine\Filter\FilterInterface; - -/** - * A paste filter - */ -class Paste implements FilterInterface -{ - /** - * @var ImageInterface - */ - private $image; - - /** - * @var PointInterface - */ - private $start; - - /** - * Constructs a Paste filter with given ImageInterface to paste and x, y - * coordinates of target position - * - * @param ImageInterface $image - * @param PointInterface $start - */ - public function __construct(ImageInterface $image, PointInterface $start) - { - $this->image = $image; - $this->start = $start; - } - - /** - * {@inheritdoc} - */ - public function apply(ImageInterface $image) - { - return $image->paste($this->image, $this->start); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Resize.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Resize.php deleted file mode 100644 index 934cfe2fd..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Resize.php +++ /dev/null @@ -1,48 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter\Basic; - -use Imagine\Filter\FilterInterface; -use Imagine\Image\ImageInterface; -use Imagine\Image\BoxInterface; - -/** - * A resize filter - */ -class Resize implements FilterInterface -{ - /** - * @var BoxInterface - */ - private $size; - private $filter; - - /** - * Constructs Resize filter with given width and height - * - * @param BoxInterface $size - * @param string $filter - */ - public function __construct(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED) - { - $this->size = $size; - $this->filter = $filter; - } - - /** - * {@inheritdoc} - */ - public function apply(ImageInterface $image) - { - return $image->resize($this->size, $this->filter); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Rotate.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Rotate.php deleted file mode 100644 index 7b5553ff9..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Rotate.php +++ /dev/null @@ -1,52 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter\Basic; - -use Imagine\Image\ImageInterface; -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Filter\FilterInterface; - -/** - * A rotate filter - */ -class Rotate implements FilterInterface -{ - /** - * @var integer - */ - private $angle; - - /** - * @var ColorInterface - */ - private $background; - - /** - * Constructs Rotate filter with given angle and background color - * - * @param integer $angle - * @param ColorInterface $background - */ - public function __construct($angle, ColorInterface $background = null) - { - $this->angle = $angle; - $this->background = $background; - } - - /** - * {@inheritdoc} - */ - public function apply(ImageInterface $image) - { - return $image->rotate($this->angle, $this->background); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Save.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Save.php deleted file mode 100644 index 0f76625a1..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Save.php +++ /dev/null @@ -1,51 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter\Basic; - -use Imagine\Image\ImageInterface; -use Imagine\Filter\FilterInterface; - -/** - * A save filter - */ -class Save implements FilterInterface -{ - /** - * @var string - */ - private $path; - - /** - * @var array - */ - private $options; - - /** - * Constructs Save filter with given path and options - * - * @param string $path - * @param array $options - */ - public function __construct($path = null, array $options = array()) - { - $this->path = $path; - $this->options = $options; - } - - /** - * {@inheritdoc} - */ - public function apply(ImageInterface $image) - { - return $image->save($this->path, $this->options); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Show.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Show.php deleted file mode 100644 index a7d4cbc44..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Show.php +++ /dev/null @@ -1,51 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter\Basic; - -use Imagine\Image\ImageInterface; -use Imagine\Filter\FilterInterface; - -/** - * A show filter - */ -class Show implements FilterInterface -{ - /** - * @var string - */ - private $format; - - /** - * @var array - */ - private $options; - - /** - * Constructs the Show filter with given format and options - * - * @param string $format - * @param array $options - */ - public function __construct($format, array $options = array()) - { - $this->format = $format; - $this->options = $options; - } - - /** - * {@inheritdoc} - */ - public function apply(ImageInterface $image) - { - return $image->show($this->format, $this->options); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Strip.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Strip.php deleted file mode 100644 index c096a51bc..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Strip.php +++ /dev/null @@ -1,29 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter\Basic; - -use Imagine\Image\ImageInterface; -use Imagine\Filter\FilterInterface; - -/** - * A strip filter - */ -class Strip implements FilterInterface -{ - /** - * {@inheritdoc} - */ - public function apply(ImageInterface $image) - { - return $image->strip(); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Thumbnail.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Thumbnail.php deleted file mode 100644 index 3176f1c39..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/Thumbnail.php +++ /dev/null @@ -1,59 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter\Basic; - -use Imagine\Image\ImageInterface; -use Imagine\Image\BoxInterface; -use Imagine\Filter\FilterInterface; - -/** - * A thumbnail filter - */ -class Thumbnail implements FilterInterface -{ - /** - * @var BoxInterface - */ - private $size; - - /** - * @var string - */ - private $mode; - - /** - * @var string - */ - private $filter; - - /** - * Constructs the Thumbnail filter with given width, height and mode - * - * @param BoxInterface $size - * @param string $mode - * @param string $filter - */ - public function __construct(BoxInterface $size, $mode = ImageInterface::THUMBNAIL_INSET, $filter = ImageInterface::FILTER_UNDEFINED) - { - $this->size = $size; - $this->mode = $mode; - $this->filter = $filter; - } - - /** - * {@inheritdoc} - */ - public function apply(ImageInterface $image) - { - return $image->thumbnail($this->size, $this->mode, $this->filter); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/WebOptimization.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/WebOptimization.php deleted file mode 100644 index 37f5f3f1a..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Basic/WebOptimization.php +++ /dev/null @@ -1,57 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter\Basic; - -use Imagine\Image\ImageInterface; -use Imagine\Image\Palette\RGB; -use Imagine\Filter\FilterInterface; - -/** - * A filter to render web-optimized images - */ -class WebOptimization implements FilterInterface -{ - private $palette; - private $path; - private $options; - - public function __construct($path = null, array $options = array()) - { - $this->path = $path; - $this->options = array_replace(array( - 'resolution-units' => ImageInterface::RESOLUTION_PIXELSPERINCH, - 'resolution-y' => 72, - 'resolution-x' => 72, - ), $options); - $this->palette = new RGB(); - } - - /** - * {@inheritdoc} - */ - public function apply(ImageInterface $image) - { - $image - ->usePalette($this->palette) - ->strip(); - - if (is_callable($this->path)) { - $path = call_user_func($this->path, $image); - } elseif (null !== $this->path) { - $path = $this->path; - } else { - return $image; - } - - return $image->save($path, $this->options); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/FilterInterface.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/FilterInterface.php deleted file mode 100644 index e23ab70e0..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/FilterInterface.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter; - -use Imagine\Image\ImageInterface; - -/** - * Interface for imagine filters - */ -interface FilterInterface -{ - /** - * Applies scheduled transformation to ImageInterface instance - * Returns processed ImageInterface instance - * - * @param ImageInterface $image - * - * @return ImageInterface - */ - public function apply(ImageInterface $image); -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/ImagineAware.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/ImagineAware.php deleted file mode 100644 index 606c5254c..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/ImagineAware.php +++ /dev/null @@ -1,54 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter; - -use Imagine\Exception\InvalidArgumentException; -use Imagine\Image\ImagineInterface; - -/** - * ImagineAware base class - */ -abstract class ImagineAware implements FilterInterface -{ - /** - * An ImagineInterface instance. - * - * @var ImagineInterface - */ - private $imagine; - - /** - * Set ImagineInterface instance. - * - * @param ImagineInterface $imagine An ImagineInterface instance - */ - public function setImagine(ImagineInterface $imagine) - { - $this->imagine = $imagine; - } - - /** - * Get ImagineInterface instance. - * - * @return ImagineInterface - * - * @throws InvalidArgumentException - */ - public function getImagine() - { - if (!$this->imagine instanceof ImagineInterface) { - throw new InvalidArgumentException(sprintf('In order to use %s pass an Imagine\Image\ImagineInterface instance to filter constructor', get_class($this))); - } - - return $this->imagine; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Transformation.php b/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Transformation.php deleted file mode 100644 index 26c023a0f..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Filter/Transformation.php +++ /dev/null @@ -1,240 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Filter; - -use Imagine\Exception\InvalidArgumentException; -use Imagine\Filter\Basic\ApplyMask; -use Imagine\Filter\Basic\Copy; -use Imagine\Filter\Basic\Crop; -use Imagine\Filter\Basic\Fill; -use Imagine\Filter\Basic\FlipVertically; -use Imagine\Filter\Basic\FlipHorizontally; -use Imagine\Filter\Basic\Paste; -use Imagine\Filter\Basic\Resize; -use Imagine\Filter\Basic\Rotate; -use Imagine\Filter\Basic\Save; -use Imagine\Filter\Basic\Show; -use Imagine\Filter\Basic\Strip; -use Imagine\Filter\Basic\Thumbnail; -use Imagine\Image\ImageInterface; -use Imagine\Image\ImagineInterface; -use Imagine\Image\BoxInterface; -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Image\Fill\FillInterface; -use Imagine\Image\ManipulatorInterface; -use Imagine\Image\PointInterface; - -/** - * A transformation filter - */ -final class Transformation implements FilterInterface, ManipulatorInterface -{ - /** - * @var array - */ - private $filters = array(); - - /** - * @var array - */ - private $sorted; - - /** - * An ImagineInterface instance. - * - * @var ImagineInterface - */ - private $imagine; - - /** - * Class constructor. - * - * @param ImagineInterface $imagine An ImagineInterface instance - */ - public function __construct(ImagineInterface $imagine = null) - { - $this->imagine = $imagine; - } - - /** - * Applies a given FilterInterface onto given ImageInterface and returns - * modified ImageInterface - * - * @param ImageInterface $image - * @param FilterInterface $filter - * - * @return ImageInterface - * @throws InvalidArgumentException - */ - public function applyFilter(ImageInterface $image, FilterInterface $filter) - { - if ($filter instanceof ImagineAware) { - if ($this->imagine === null) { - throw new InvalidArgumentException(sprintf('In order to use %s pass an Imagine\Image\ImagineInterface instance to Transformation constructor', get_class($filter))); - } - $filter->setImagine($this->imagine); - } - - return $filter->apply($image); - } - - /** - * Returns a list of filters sorted by their priority. Filters with same priority will be returned in the order they were added. - * - * @return array - */ - public function getFilters() - { - if (null === $this->sorted) { - if (!empty($this->filters)) { - ksort($this->filters); - $this->sorted = call_user_func_array('array_merge', $this->filters); - } else { - $this->sorted = array(); - } - } - - return $this->sorted; - } - - /** - * {@inheritdoc} - */ - public function apply(ImageInterface $image) - { - return array_reduce( - $this->getFilters(), - array($this, 'applyFilter'), - $image - ); - } - - /** - * {@inheritdoc} - */ - public function copy() - { - return $this->add(new Copy()); - } - - /** - * {@inheritdoc} - */ - public function crop(PointInterface $start, BoxInterface $size) - { - return $this->add(new Crop($start, $size)); - } - - /** - * {@inheritdoc} - */ - public function flipHorizontally() - { - return $this->add(new FlipHorizontally()); - } - - /** - * {@inheritdoc} - */ - public function flipVertically() - { - return $this->add(new FlipVertically()); - } - - /** - * {@inheritdoc} - */ - public function strip() - { - return $this->add(new Strip()); - } - - /** - * {@inheritdoc} - */ - public function paste(ImageInterface $image, PointInterface $start) - { - return $this->add(new Paste($image, $start)); - } - - /** - * {@inheritdoc} - */ - public function applyMask(ImageInterface $mask) - { - return $this->add(new ApplyMask($mask)); - } - - /** - * {@inheritdoc} - */ - public function fill(FillInterface $fill) - { - return $this->add(new Fill($fill)); - } - - /** - * {@inheritdoc} - */ - public function resize(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED) - { - return $this->add(new Resize($size, $filter)); - } - - /** - * {@inheritdoc} - */ - public function rotate($angle, ColorInterface $background = null) - { - return $this->add(new Rotate($angle, $background)); - } - - /** - * {@inheritdoc} - */ - public function save($path = null, array $options = array()) - { - return $this->add(new Save($path, $options)); - } - - /** - * {@inheritdoc} - */ - public function show($format, array $options = array()) - { - return $this->add(new Show($format, $options)); - } - - /** - * {@inheritdoc} - */ - public function thumbnail(BoxInterface $size, $mode = ImageInterface::THUMBNAIL_INSET, $filter = ImageInterface::FILTER_UNDEFINED) - { - return $this->add(new Thumbnail($size, $mode, $filter)); - } - - /** - * Registers a given FilterInterface in an internal array of filters for - * later application to an instance of ImageInterface - * - * @param FilterInterface $filter - * @param int $priority - * @return Transformation - */ - public function add(FilterInterface $filter, $priority = 0) - { - $this->filters[$priority][] = $filter; - $this->sorted = null; - - return $this; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Gd/Drawer.php b/snappymail/v/0.0.0/app/libraries/Imagine/Gd/Drawer.php deleted file mode 100644 index e5d74e0d9..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Gd/Drawer.php +++ /dev/null @@ -1,333 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Gd; - -use Imagine\Draw\DrawerInterface; -use Imagine\Exception\InvalidArgumentException; -use Imagine\Exception\RuntimeException; -use Imagine\Image\AbstractFont; -use Imagine\Image\BoxInterface; -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Image\Palette\Color\RGB as RGBColor; -use Imagine\Image\PointInterface; - -/** - * Drawer implementation using the GD library - */ -final class Drawer implements DrawerInterface -{ - /** - * @var resource - */ - private $resource; - - /** - * @var array - */ - private $info; - - /** - * Constructs Drawer with a given gd image resource - * - * @param resource $resource - */ - public function __construct($resource) - { - $this->loadGdInfo(); - $this->resource = $resource; - } - - /** - * {@inheritdoc} - */ - public function arc(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $thickness = 1) - { - imagesetthickness($this->resource, max(1, (int) $thickness)); - - if (false === imagealphablending($this->resource, true)) { - throw new RuntimeException('Draw arc operation failed'); - } - - if (false === imagearc($this->resource, $center->getX(), $center->getY(), $size->getWidth(), $size->getHeight(), $start, $end, $this->getColor($color))) { - imagealphablending($this->resource, false); - throw new RuntimeException('Draw arc operation failed'); - } - - if (false === imagealphablending($this->resource, false)) { - throw new RuntimeException('Draw arc operation failed'); - } - - return $this; - } - - /** - * This function does not work properly because of a bug in GD - * - * {@inheritdoc} - */ - public function chord(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1) - { - imagesetthickness($this->resource, max(1, (int) $thickness)); - - if ($fill) { - $style = IMG_ARC_CHORD; - } else { - $style = IMG_ARC_CHORD | IMG_ARC_NOFILL; - } - - if (false === imagealphablending($this->resource, true)) { - throw new RuntimeException('Draw chord operation failed'); - } - - if (false === imagefilledarc($this->resource, $center->getX(), $center->getY(), $size->getWidth(), $size->getHeight(), $start, $end, $this->getColor($color), $style)) { - imagealphablending($this->resource, false); - throw new RuntimeException('Draw chord operation failed'); - } - - if (false === imagealphablending($this->resource, false)) { - throw new RuntimeException('Draw chord operation failed'); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function ellipse(PointInterface $center, BoxInterface $size, ColorInterface $color, $fill = false, $thickness = 1) - { - imagesetthickness($this->resource, max(1, (int) $thickness)); - - if ($fill) { - $callback = 'imagefilledellipse'; - } else { - $callback = 'imageellipse'; - } - - if (false === imagealphablending($this->resource, true)) { - throw new RuntimeException('Draw ellipse operation failed'); - } - - if (false === $callback($this->resource, $center->getX(), $center->getY(), $size->getWidth(), $size->getHeight(), $this->getColor($color))) { - imagealphablending($this->resource, false); - throw new RuntimeException('Draw ellipse operation failed'); - } - - if (false === imagealphablending($this->resource, false)) { - throw new RuntimeException('Draw ellipse operation failed'); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function line(PointInterface $start, PointInterface $end, ColorInterface $color, $thickness = 1) - { - imagesetthickness($this->resource, max(1, (int) $thickness)); - - if (false === imagealphablending($this->resource, true)) { - throw new RuntimeException('Draw line operation failed'); - } - - if (false === imageline($this->resource, $start->getX(), $start->getY(), $end->getX(), $end->getY(), $this->getColor($color))) { - imagealphablending($this->resource, false); - throw new RuntimeException('Draw line operation failed'); - } - - if (false === imagealphablending($this->resource, false)) { - throw new RuntimeException('Draw line operation failed'); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function pieSlice(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1) - { - imagesetthickness($this->resource, max(1, (int) $thickness)); - - if ($fill) { - $style = IMG_ARC_EDGED; - } else { - $style = IMG_ARC_EDGED | IMG_ARC_NOFILL; - } - - if (false === imagealphablending($this->resource, true)) { - throw new RuntimeException('Draw chord operation failed'); - } - - if (false === imagefilledarc($this->resource, $center->getX(), $center->getY(), $size->getWidth(), $size->getHeight(), $start, $end, $this->getColor($color), $style)) { - imagealphablending($this->resource, false); - throw new RuntimeException('Draw chord operation failed'); - } - - if (false === imagealphablending($this->resource, false)) { - throw new RuntimeException('Draw chord operation failed'); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function dot(PointInterface $position, ColorInterface $color) - { - if (false === imagealphablending($this->resource, true)) { - throw new RuntimeException('Draw point operation failed'); - } - - if (false === imagesetpixel($this->resource, $position->getX(), $position->getY(), $this->getColor($color))) { - imagealphablending($this->resource, false); - throw new RuntimeException('Draw point operation failed'); - } - - if (false === imagealphablending($this->resource, false)) { - throw new RuntimeException('Draw point operation failed'); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function polygon(array $coordinates, ColorInterface $color, $fill = false, $thickness = 1) - { - imagesetthickness($this->resource, max(1, (int) $thickness)); - - if (count($coordinates) < 3) { - throw new InvalidArgumentException(sprintf('A polygon must consist of at least 3 points, %d given', count($coordinates))); - } - - $points = call_user_func_array('array_merge', array_map(function (PointInterface $p) { - return array($p->getX(), $p->getY()); - }, $coordinates)); - - if ($fill) { - $callback = 'imagefilledpolygon'; - } else { - $callback = 'imagepolygon'; - } - - if (false === imagealphablending($this->resource, true)) { - throw new RuntimeException('Draw polygon operation failed'); - } - - if (false === $callback($this->resource, $points, count($coordinates), $this->getColor($color))) { - imagealphablending($this->resource, false); - throw new RuntimeException('Draw polygon operation failed'); - } - - if (false === imagealphablending($this->resource, false)) { - throw new RuntimeException('Draw polygon operation failed'); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function text($string, AbstractFont $font, PointInterface $position, $angle = 0, $width = null) - { - if (!$this->info['FreeType Support']) { - throw new RuntimeException('GD is not compiled with FreeType support'); - } - - $angle = -1 * $angle; - $fontsize = $font->getSize(); - $fontfile = $font->getFile(); - $x = $position->getX(); - $y = $position->getY() + $fontsize; - - if ($width !== null) { - $string = $this->wrapText($string, $font, $angle, $width); - } - - if (false === imagealphablending($this->resource, true)) { - throw new RuntimeException('Font mask operation failed'); - } - - if (false === imagefttext($this->resource, $fontsize, $angle, $x, $y, $this->getColor($font->getColor()), $fontfile, $string)) { - imagealphablending($this->resource, false); - throw new RuntimeException('Font mask operation failed'); - } - - if (false === imagealphablending($this->resource, false)) { - throw new RuntimeException('Font mask operation failed'); - } - - return $this; - } - - /** - * Internal - * - * Generates a GD color from Color instance - * - * @param ColorInterface $color - * - * @return resource - * - * @throws RuntimeException - * @throws InvalidArgumentException - */ - private function getColor(ColorInterface $color) - { - if (!$color instanceof RGBColor) { - throw new InvalidArgumentException('GD driver only supports RGB colors'); - } - - $gdColor = imagecolorallocatealpha($this->resource, $color->getRed(), $color->getGreen(), $color->getBlue(), (100 - $color->getAlpha()) * 127 / 100); - if (false === $gdColor) { - throw new RuntimeException(sprintf('Unable to allocate color "RGB(%s, %s, %s)" with transparency of %d percent', $color->getRed(), $color->getGreen(), $color->getBlue(), $color->getAlpha())); - } - - return $gdColor; - } - - private function loadGdInfo() - { - if (!function_exists('gd_info')) { - throw new RuntimeException('Gd not installed'); - } - - $this->info = gd_info(); - } - - /** - * Internal - * - * Fits a string into box with given width - */ - private function wrapText($string, AbstractFont $font, $angle, $width) - { - $result = ''; - $words = explode(' ', $string); - foreach ($words as $word) { - $teststring = $result . ' ' . $word; - $testbox = imagettfbbox($font->getSize(), $angle, $font->getFile(), $teststring); - if ($testbox[2] > $width) { - $result .= ($result == '' ? '' : "\n") . $word; - } else { - $result .= ($result == '' ? '' : ' ') . $word; - } - } - - return $result; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Gd/Effects.php b/snappymail/v/0.0.0/app/libraries/Imagine/Gd/Effects.php deleted file mode 100644 index d86c4f8a2..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Gd/Effects.php +++ /dev/null @@ -1,109 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Gd; - -use Imagine\Effects\EffectsInterface; -use Imagine\Exception\RuntimeException; -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Image\Palette\Color\RGB as RGBColor; - -/** - * Effects implementation using the GD library - */ -class Effects implements EffectsInterface -{ - private $resource; - - public function __construct($resource) - { - $this->resource = $resource; - } - - /** - * {@inheritdoc} - */ - public function gamma($correction) - { - if (false === imagegammacorrect($this->resource, 1.0, $correction)) { - throw new RuntimeException('Failed to apply gamma correction to the image'); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function negative() - { - if (false === imagefilter($this->resource, IMG_FILTER_NEGATE)) { - throw new RuntimeException('Failed to negate the image'); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function grayscale() - { - if (false === imagefilter($this->resource, IMG_FILTER_GRAYSCALE)) { - throw new RuntimeException('Failed to grayscale the image'); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function colorize(ColorInterface $color) - { - if (!$color instanceof RGBColor) { - throw new RuntimeException('Colorize effects only accepts RGB color in GD context'); - } - - if (false === imagefilter($this->resource, IMG_FILTER_COLORIZE, $color->getRed(), $color->getGreen(), $color->getBlue())) { - throw new RuntimeException('Failed to colorize the image'); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function sharpen() - { - $sharpenMatrix = array(array(-1,-1,-1), array(-1,16,-1), array(-1,-1,-1)); - $divisor = array_sum(array_map('array_sum', $sharpenMatrix)); - - if (false === imageconvolution($this->resource, $sharpenMatrix, $divisor, 0)) { - throw new RuntimeException('Failed to sharpen the image'); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function blur($sigma = 1) - { - if (false === imagefilter($this->resource, IMG_FILTER_GAUSSIAN_BLUR)) { - throw new RuntimeException('Failed to blur the image'); - } - - return $this; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Gd/Font.php b/snappymail/v/0.0.0/app/libraries/Imagine/Gd/Font.php deleted file mode 100644 index 8bc2b04d4..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Gd/Font.php +++ /dev/null @@ -1,41 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Gd; - -use Imagine\Exception\RuntimeException; -use Imagine\Image\AbstractFont; -use Imagine\Image\Box; - -/** - * Font implementation using the GD library - */ -final class Font extends AbstractFont -{ - /** - * {@inheritdoc} - */ - public function box($string, $angle = 0) - { - if (!function_exists('imageftbbox')) { - throw new RuntimeException('GD must have been compiled with `--with-freetype-dir` option to use the Font feature.'); - } - - $angle = -1 * $angle; - $info = imageftbbox($this->size, $angle, $this->file, $string); - $xs = array($info[0], $info[2], $info[4], $info[6]); - $ys = array($info[1], $info[3], $info[5], $info[7]); - $width = abs(max($xs) - min($xs)); - $height = abs(max($ys) - min($ys)); - - return new Box($width, $height); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Gd/Image.php b/snappymail/v/0.0.0/app/libraries/Imagine/Gd/Image.php deleted file mode 100644 index 73d7b9506..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Gd/Image.php +++ /dev/null @@ -1,735 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Gd; - -use Imagine\Image\AbstractImage; -use Imagine\Image\ImageInterface; -use Imagine\Image\Box; -use Imagine\Image\BoxInterface; -use Imagine\Image\Metadata\MetadataBag; -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Image\Fill\FillInterface; -use Imagine\Image\Point; -use Imagine\Image\PointInterface; -use Imagine\Image\Palette\PaletteInterface; -use Imagine\Image\Palette\Color\RGB as RGBColor; -use Imagine\Image\ProfileInterface; -use Imagine\Image\Palette\RGB; -use Imagine\Exception\InvalidArgumentException; -use Imagine\Exception\OutOfBoundsException; -use Imagine\Exception\RuntimeException; - -/** - * Image implementation using the GD library - */ -final class Image extends AbstractImage -{ - /** - * @var resource - */ - private $resource; - - /** - * @var Layers|null - */ - private $layers; - - /** - * @var PaletteInterface - */ - private $palette; - - /** - * Constructs a new Image instance - * - * @param resource $resource - * @param PaletteInterface $palette - * @param MetadataBag $metadata - */ - public function __construct($resource, PaletteInterface $palette, MetadataBag $metadata) - { - $this->metadata = $metadata; - $this->palette = $palette; - $this->resource = $resource; - } - - /** - * Makes sure the current image resource is destroyed - */ - public function __destruct() - { - if (is_resource($this->resource) && 'gd' === get_resource_type($this->resource)) { - imagedestroy($this->resource); - } - } - - /** - * Returns Gd resource - * - * @return resource - */ - public function getGdResource() - { - return $this->resource; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - final public function copy() - { - $size = $this->getSize(); - $copy = $this->createImage($size, 'copy'); - - if (false === imagecopy($copy, $this->resource, 0, 0, 0, 0, $size->getWidth(), $size->getHeight())) { - throw new RuntimeException('Image copy operation failed'); - } - - return new Image($copy, $this->palette, $this->metadata); - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - final public function crop(PointInterface $start, BoxInterface $size) - { - if (!$start->in($this->getSize())) { - throw new OutOfBoundsException('Crop coordinates must start at minimum 0, 0 position from top left corner, crop height and width must be positive integers and must not exceed the current image borders'); - } - - $width = $size->getWidth(); - $height = $size->getHeight(); - - $dest = $this->createImage($size, 'crop'); - - if (false === imagecopy($dest, $this->resource, 0, 0, $start->getX(), $start->getY(), $width, $height)) { - throw new RuntimeException('Image crop operation failed'); - } - - imagedestroy($this->resource); - - $this->resource = $dest; - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - final public function paste(ImageInterface $image, PointInterface $start) - { - if (!$image instanceof self) { - throw new InvalidArgumentException(sprintf('Gd\Image can only paste() Gd\Image instances, %s given', get_class($image))); - } - - $size = $image->getSize(); - if (!$this->getSize()->contains($size, $start)) { - throw new OutOfBoundsException('Cannot paste image of the given size at the specified position, as it moves outside of the current image\'s box'); - } - - imagealphablending($this->resource, true); - imagealphablending($image->resource, true); - - if (false === imagecopy($this->resource, $image->resource, $start->getX(), $start->getY(), 0, 0, $size->getWidth(), $size->getHeight())) { - throw new RuntimeException('Image paste operation failed'); - } - - imagealphablending($this->resource, false); - imagealphablending($image->resource, false); - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - final public function resize(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED) - { - if (ImageInterface::FILTER_UNDEFINED !== $filter) { - throw new InvalidArgumentException('Unsupported filter type, GD only supports ImageInterface::FILTER_UNDEFINED filter'); - } - - $width = $size->getWidth(); - $height = $size->getHeight(); - - $dest = $this->createImage($size, 'resize'); - - imagealphablending($this->resource, true); - imagealphablending($dest, true); - - if (false === imagecopyresampled($dest, $this->resource, 0, 0, 0, 0, $width, $height, imagesx($this->resource), imagesy($this->resource))) { - throw new RuntimeException('Image resize operation failed'); - } - - imagealphablending($this->resource, false); - imagealphablending($dest, false); - - imagedestroy($this->resource); - - $this->resource = $dest; - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - final public function rotate($angle, ColorInterface $background = null) - { - $color = $background ? $background : $this->palette->color('fff'); - $resource = imagerotate($this->resource, -1 * $angle, $this->getColor($color)); - - if (false === $resource) { - throw new RuntimeException('Image rotate operation failed'); - } - - imagedestroy($this->resource); - $this->resource = $resource; - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - final public function save($path = null, array $options = array()) - { - $path = null === $path ? (isset($this->metadata['filepath']) ? $this->metadata['filepath'] : $path) : $path; - - if (null === $path) { - throw new RuntimeException('You can omit save path only if image has been open from a file'); - } - - if (isset($options['format'])) { - $format = $options['format']; - } elseif ('' !== $extension = pathinfo($path, \PATHINFO_EXTENSION)) { - $format = $extension; - } else { - $originalPath = isset($this->metadata['filepath']) ? $this->metadata['filepath'] : null; - $format = pathinfo($originalPath, \PATHINFO_EXTENSION); - } - - $this->saveOrOutput($format, $options, $path); - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function show($format, array $options = array()) - { - header('Content-type: '.$this->getMimeType($format)); - - $this->saveOrOutput($format, $options); - - return $this; - } - - /** - * {@inheritdoc} - */ - public function get($format, array $options = array()) - { - ob_start(); - $this->saveOrOutput($format, $options); - - return ob_get_clean(); - } - - /** - * {@inheritdoc} - */ - public function __toString() - { - return $this->get('png'); - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - final public function flipHorizontally() - { - $size = $this->getSize(); - $width = $size->getWidth(); - $height = $size->getHeight(); - $dest = $this->createImage($size, 'flip'); - - for ($i = 0; $i < $width; $i++) { - if (false === imagecopy($dest, $this->resource, $i, 0, ($width - 1) - $i, 0, 1, $height)) { - throw new RuntimeException('Horizontal flip operation failed'); - } - } - - imagedestroy($this->resource); - - $this->resource = $dest; - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - final public function flipVertically() - { - $size = $this->getSize(); - $width = $size->getWidth(); - $height = $size->getHeight(); - $dest = $this->createImage($size, 'flip'); - - for ($i = 0; $i < $height; $i++) { - if (false === imagecopy($dest, $this->resource, 0, $i, 0, ($height - 1) - $i, $width, 1)) { - throw new RuntimeException('Vertical flip operation failed'); - } - } - - imagedestroy($this->resource); - - $this->resource = $dest; - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - final public function strip() - { - // GD strips profiles and comment, so there's nothing to do here - return $this; - } - - /** - * {@inheritdoc} - */ - public function draw() - { - return new Drawer($this->resource); - } - - /** - * {@inheritdoc} - */ - public function effects() - { - return new Effects($this->resource); - } - - /** - * {@inheritdoc} - */ - public function getSize() - { - return new Box(imagesx($this->resource), imagesy($this->resource)); - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function applyMask(ImageInterface $mask) - { - if (!$mask instanceof self) { - throw new InvalidArgumentException('Cannot mask non-gd images'); - } - - $size = $this->getSize(); - $maskSize = $mask->getSize(); - - if ($size != $maskSize) { - throw new InvalidArgumentException(sprintf('The given mask doesn\'t match current image\'s size, Current mask\'s dimensions are %s, while image\'s dimensions are %s', $maskSize, $size)); - } - - for ($x = 0, $width = $size->getWidth(); $x < $width; $x++) { - for ($y = 0, $height = $size->getHeight(); $y < $height; $y++) { - $position = new Point($x, $y); - $color = $this->getColorAt($position); - $maskColor = $mask->getColorAt($position); - $round = (int) round(max($color->getAlpha(), (100 - $color->getAlpha()) * $maskColor->getRed() / 255)); - - if (false === imagesetpixel($this->resource, $x, $y, $this->getColor($color->dissolve($round - $color->getAlpha())))) { - throw new RuntimeException('Apply mask operation failed'); - } - } - } - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function fill(FillInterface $fill) - { - $size = $this->getSize(); - - for ($x = 0, $width = $size->getWidth(); $x < $width; $x++) { - for ($y = 0, $height = $size->getHeight(); $y < $height; $y++) { - if (false === imagesetpixel($this->resource, $x, $y, $this->getColor($fill->getColor(new Point($x, $y))))) { - throw new RuntimeException('Fill operation failed'); - } - } - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function mask() - { - $mask = $this->copy(); - - if (false === imagefilter($mask->resource, IMG_FILTER_GRAYSCALE)) { - throw new RuntimeException('Mask operation failed'); - } - - return $mask; - } - - /** - * {@inheritdoc} - */ - public function histogram() - { - $size = $this->getSize(); - $colors = array(); - - for ($x = 0, $width = $size->getWidth(); $x < $width; $x++) { - for ($y = 0, $height = $size->getHeight(); $y < $height; $y++) { - $colors[] = $this->getColorAt(new Point($x, $y)); - } - } - - return array_unique($colors); - } - - /** - * {@inheritdoc} - */ - public function getColorAt(PointInterface $point) - { - if (!$point->in($this->getSize())) { - throw new RuntimeException(sprintf('Error getting color at point [%s,%s]. The point must be inside the image of size [%s,%s]', $point->getX(), $point->getY(), $this->getSize()->getWidth(), $this->getSize()->getHeight())); - } - - $index = imagecolorat($this->resource, $point->getX(), $point->getY()); - $info = imagecolorsforindex($this->resource, $index); - - return $this->palette->color(array($info['red'], $info['green'], $info['blue']), max(min(100 - (int) round($info['alpha'] / 127 * 100), 100), 0)); - } - - /** - * {@inheritdoc} - */ - public function layers() - { - if (null === $this->layers) { - $this->layers = new Layers($this, $this->palette, $this->resource); - } - - return $this->layers; - } - - /** - * {@inheritdoc} - **/ - public function interlace($scheme) - { - static $supportedInterlaceSchemes = array( - ImageInterface::INTERLACE_NONE => 0, - ImageInterface::INTERLACE_LINE => 1, - ImageInterface::INTERLACE_PLANE => 1, - ImageInterface::INTERLACE_PARTITION => 1, - ); - - if (!array_key_exists($scheme, $supportedInterlaceSchemes)) { - throw new InvalidArgumentException('Unsupported interlace type'); - } - - imageinterlace($this->resource, $supportedInterlaceSchemes[$scheme]); - - return $this; - } - - /** - * {@inheritdoc} - */ - public function palette() - { - return $this->palette; - } - - /** - * {@inheritdoc} - */ - public function profile(ProfileInterface $profile) - { - throw new RuntimeException('GD driver does not support color profiles'); - } - - /** - * {@inheritdoc} - */ - public function usePalette(PaletteInterface $palette) - { - if (!$palette instanceof RGB) { - throw new RuntimeException('GD driver only supports RGB palette'); - } - - $this->palette = $palette; - - return $this; - } - - /** - * Internal - * - * Performs save or show operation using one of GD's image... functions - * - * @param string $format - * @param array $options - * @param string $filename - * - * @throws InvalidArgumentException - * @throws RuntimeException - */ - private function saveOrOutput($format, array $options, $filename = null) - { - $format = $this->normalizeFormat($format); - - if (!$this->supported($format)) { - throw new InvalidArgumentException(sprintf('Saving image in "%s" format is not supported, please use one of the following extensions: "%s"', $format, implode('", "', $this->supported()))); - } - - $save = 'image'.$format; - $args = array(&$this->resource, $filename); - - // Preserve BC until version 1.0 - if (isset($options['quality']) && !isset($options['png_compression_level'])) { - $options['png_compression_level'] = round((100 - $options['quality']) * 9 / 100); - } - if (isset($options['filters']) && !isset($options['png_compression_filter'])) { - $options['png_compression_filter'] = $options['filters']; - } - - $options = $this->updateSaveOptions($options); - - if ($format === 'jpeg' && isset($options['jpeg_quality'])) { - $args[] = $options['jpeg_quality']; - } - - if ($format === 'png') { - if (isset($options['png_compression_level'])) { - if ($options['png_compression_level'] < 0 || $options['png_compression_level'] > 9) { - throw new InvalidArgumentException('png_compression_level option should be an integer from 0 to 9'); - } - $args[] = $options['png_compression_level']; - } else { - $args[] = -1; // use default level - } - - if (isset($options['png_compression_filter'])) { - if (~PNG_ALL_FILTERS & $options['png_compression_filter']) { - throw new InvalidArgumentException('png_compression_filter option should be a combination of the PNG_FILTER_XXX constants'); - } - $args[] = $options['png_compression_filter']; - } - } - - if (($format === 'wbmp' || $format === 'xbm') && isset($options['foreground'])) { - $args[] = $options['foreground']; - } - - $this->setExceptionHandler(); - - if (false === call_user_func_array($save, $args)) { - throw new RuntimeException('Save operation failed'); - } - - $this->resetExceptionHandler(); - } - - /** - * Internal - * - * Generates a GD image - * - * @param BoxInterface $size - * @param string the operation initiating the creation - * - * @return resource - * - * @throws RuntimeException - * - */ - private function createImage(BoxInterface $size, $operation) - { - $resource = imagecreatetruecolor($size->getWidth(), $size->getHeight()); - - if (false === $resource) { - throw new RuntimeException('Image '.$operation.' failed'); - } - - if (false === imagealphablending($resource, false) || false === imagesavealpha($resource, true)) { - throw new RuntimeException('Image '.$operation.' failed'); - } - - if (function_exists('imageantialias')) { - imageantialias($resource, true); - } - - $transparent = imagecolorallocatealpha($resource, 255, 255, 255, 127); - imagefill($resource, 0, 0, $transparent); - imagecolortransparent($resource, $transparent); - - return $resource; - } - - /** - * Internal - * - * Generates a GD color from Color instance - * - * @param ColorInterface $color - * - * @return integer A color identifier - * - * @throws RuntimeException - * @throws InvalidArgumentException - */ - private function getColor(ColorInterface $color) - { - if (!$color instanceof RGBColor) { - throw new InvalidArgumentException('GD driver only supports RGB colors'); - } - - $index = imagecolorallocatealpha($this->resource, $color->getRed(), $color->getGreen(), $color->getBlue(), round(127 * (100 - $color->getAlpha()) / 100)); - - if (false === $index) { - throw new RuntimeException(sprintf('Unable to allocate color "RGB(%s, %s, %s)" with transparency of %d percent', $color->getRed(), $color->getGreen(), $color->getBlue(), $color->getAlpha())); - } - - return $index; - } - - /** - * Internal - * - * Normalizes a given format name - * - * @param string $format - * - * @return string - */ - private function normalizeFormat($format) - { - $format = strtolower($format); - - if ('jpg' === $format || 'pjpeg' === $format) { - $format = 'jpeg'; - } - - return $format; - } - - /** - * Internal - * - * Checks whether a given format is supported by GD library - * - * @param string $format - * - * @return Boolean - */ - private function supported($format = null) - { - $formats = array('gif', 'jpeg', 'png', 'wbmp', 'xbm'); - - if (null === $format) { - return $formats; - } - - return in_array($format, $formats); - } - - private function setExceptionHandler() - { - set_error_handler(function ($errno, $errstr, $errfile, $errline) { - if (0 === error_reporting()) { - return; - } - - throw new RuntimeException($errstr, $errno, new \ErrorException($errstr, 0, $errno, $errfile, $errline)); - }, E_WARNING | E_NOTICE); - } - - private function resetExceptionHandler() - { - restore_error_handler(); - } - - /** - * Internal - * - * Get the mime type based on format. - * - * @param string $format - * - * @return string mime-type - * - * @throws RuntimeException - */ - private function getMimeType($format) - { - $format = $this->normalizeFormat($format); - - if (!$this->supported($format)) { - throw new RuntimeException('Invalid format'); - } - - static $mimeTypes = array( - 'jpeg' => 'image/jpeg', - 'gif' => 'image/gif', - 'png' => 'image/png', - 'wbmp' => 'image/vnd.wap.wbmp', - 'xbm' => 'image/xbm', - ); - - return $mimeTypes[$format]; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Gd/Imagine.php b/snappymail/v/0.0.0/app/libraries/Imagine/Gd/Imagine.php deleted file mode 100644 index f9e950876..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Gd/Imagine.php +++ /dev/null @@ -1,195 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Gd; - -use Imagine\Image\AbstractImagine; -use Imagine\Image\Metadata\MetadataBag; -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Image\Palette\RGB; -use Imagine\Image\Palette\PaletteInterface; -use Imagine\Image\BoxInterface; -use Imagine\Image\Palette\Color\RGB as RGBColor; -use Imagine\Exception\InvalidArgumentException; -use Imagine\Exception\RuntimeException; - -/** - * Imagine implementation using the GD library - */ -final class Imagine extends AbstractImagine -{ - /** - * @var array - */ - private $info; - - /** - * @throws RuntimeException - */ - public function __construct() - { - $this->loadGdInfo(); - $this->requireGdVersion('2.0.1'); - } - - /** - * {@inheritdoc} - */ - public function create(BoxInterface $size, ColorInterface $color = null) - { - $width = $size->getWidth(); - $height = $size->getHeight(); - - $resource = imagecreatetruecolor($width, $height); - - if (false === $resource) { - throw new RuntimeException('Create operation failed'); - } - - $palette = null !== $color ? $color->getPalette() : new RGB(); - $color = $color ? $color : $palette->color('fff'); - - if (!$color instanceof RGBColor) { - throw new InvalidArgumentException('GD driver only supports RGB colors'); - } - - $index = imagecolorallocatealpha($resource, $color->getRed(), $color->getGreen(), $color->getBlue(), round(127 * (100 - $color->getAlpha()) / 100)); - - if (false === $index) { - throw new RuntimeException('Unable to allocate color'); - } - - if (false === imagefill($resource, 0, 0, $index)) { - throw new RuntimeException('Could not set background color fill'); - } - - if ($color->getAlpha() >= 95) { - imagecolortransparent($resource, $index); - } - - return $this->wrap($resource, $palette, new MetadataBag()); - } - - /** - * {@inheritdoc} - */ - public function open($path) - { - $path = $this->checkPath($path); - $data = @file_get_contents($path); - - if (false === $data) { - throw new RuntimeException(sprintf('Failed to open file %s', $path)); - } - - $resource = @imagecreatefromstring($data); - - if (!is_resource($resource)) { - throw new RuntimeException(sprintf('Unable to open image %s', $path)); - } - - return $this->wrap($resource, new RGB(), $this->getMetadataReader()->readFile($path)); - } - - /** - * {@inheritdoc} - */ - public function load($string) - { - return $this->doLoad($string, $this->getMetadataReader()->readData($string)); - } - - /** - * {@inheritdoc} - */ - public function read($resource) - { - if (!is_resource($resource)) { - throw new InvalidArgumentException('Variable does not contain a stream resource'); - } - - $content = stream_get_contents($resource); - - if (false === $content) { - throw new InvalidArgumentException('Cannot read resource content'); - } - - return $this->doLoad($content, $this->getMetadataReader()->readStream($resource)); - } - - /** - * {@inheritdoc} - */ - public function font($file, $size, ColorInterface $color) - { - if (!$this->info['FreeType Support']) { - throw new RuntimeException('GD is not compiled with FreeType support'); - } - - return new Font($file, $size, $color); - } - - private function wrap($resource, PaletteInterface $palette, MetadataBag $metadata) - { - if (!imageistruecolor($resource)) { - list($width, $height) = array(imagesx($resource), imagesy($resource)); - - // create transparent truecolor canvas - $truecolor = imagecreatetruecolor($width, $height); - $transparent = imagecolorallocatealpha($truecolor, 255, 255, 255, 127); - - imagefill($truecolor, 0, 0, $transparent); - imagecolortransparent($truecolor, $transparent); - - imagecopymerge($truecolor, $resource, 0, 0, 0, 0, $width, $height, 100); - - imagedestroy($resource); - $resource = $truecolor; - } - - if (false === imagealphablending($resource, false) || false === imagesavealpha($resource, true)) { - throw new RuntimeException('Could not set alphablending, savealpha and antialias values'); - } - - if (function_exists('imageantialias')) { - imageantialias($resource, true); - } - - return new Image($resource, $palette, $metadata); - } - - private function loadGdInfo() - { - if (!function_exists('gd_info')) { - throw new RuntimeException('Gd not installed'); - } - - $this->info = gd_info(); - } - - private function requireGdVersion($version) - { - if (version_compare(GD_VERSION, $version, '<')) { - throw new RuntimeException(sprintf('GD2 version %s or higher is required', $version)); - } - } - - private function doLoad($string, MetadataBag $metadata) - { - $resource = @imagecreatefromstring($string); - - if (!is_resource($resource)) { - throw new RuntimeException('An image could not be created from the given input'); - } - - return $this->wrap($resource, new RGB(), $metadata); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Gd/Layers.php b/snappymail/v/0.0.0/app/libraries/Imagine/Gd/Layers.php deleted file mode 100644 index 93c7a2695..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Gd/Layers.php +++ /dev/null @@ -1,144 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Gd; - -use Imagine\Image\AbstractLayers; -use Imagine\Exception\RuntimeException; -use Imagine\Image\Metadata\MetadataBag; -use Imagine\Image\Palette\PaletteInterface; -use Imagine\Exception\NotSupportedException; - -class Layers extends AbstractLayers -{ - private $image; - private $offset; - private $resource; - private $palette; - - public function __construct(Image $image, PaletteInterface $palette, $resource) - { - if (!is_resource($resource)) { - throw new RuntimeException('Invalid Gd resource provided'); - } - - $this->image = $image; - $this->resource = $resource; - $this->offset = 0; - $this->palette = $palette; - } - - /** - * {@inheritdoc} - */ - public function merge() - { - } - - /** - * {@inheritdoc} - */ - public function coalesce() - { - } - - /** - * {@inheritdoc} - */ - public function animate($format, $delay, $loops) - { - return $this; - } - - /** - * {@inheritdoc} - */ - public function current() - { - return new Image($this->resource, $this->palette, new MetadataBag()); - } - - /** - * {@inheritdoc} - */ - public function key() - { - return $this->offset; - } - - /** - * {@inheritdoc} - */ - public function next() - { - ++$this->offset; - } - - /** - * {@inheritdoc} - */ - public function rewind() - { - $this->offset = 0; - } - - /** - * {@inheritdoc} - */ - public function valid() - { - return $this->offset < 1; - } - - /** - * {@inheritdoc} - */ - public function count() - { - return 1; - } - - /** - * {@inheritdoc} - */ - public function offsetExists($offset) - { - return 0 === $offset; - } - - /** - * {@inheritdoc} - */ - public function offsetGet($offset) - { - if (0 === $offset) { - return new Image($this->resource, $this->palette, new MetadataBag()); - } - - throw new RuntimeException('GD only supports one layer at offset 0'); - } - - /** - * {@inheritdoc} - */ - public function offsetSet($offset, $value) - { - throw new NotSupportedException('GD does not support layer set'); - } - - /** - * {@inheritdoc} - */ - public function offsetUnset($offset) - { - throw new NotSupportedException('GD does not support layer unset'); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Gmagick/Drawer.php b/snappymail/v/0.0.0/app/libraries/Imagine/Gmagick/Drawer.php deleted file mode 100644 index de6cc9048..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Gmagick/Drawer.php +++ /dev/null @@ -1,356 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Gmagick; - -use Imagine\Draw\DrawerInterface; -use Imagine\Exception\InvalidArgumentException; -use Imagine\Exception\NotSupportedException; -use Imagine\Exception\RuntimeException; -use Imagine\Image\AbstractFont; -use Imagine\Image\BoxInterface; -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Image\Point; -use Imagine\Image\PointInterface; - -/** - * Drawer implementation using the Gmagick PHP extension - */ -final class Drawer implements DrawerInterface -{ - /** - * @var \Gmagick - */ - private $gmagick; - - /** - * @param \Gmagick $gmagick - */ - public function __construct(\Gmagick $gmagick) - { - $this->gmagick = $gmagick; - } - - /** - * {@inheritdoc} - */ - public function arc(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $thickness = 1) - { - $x = $center->getX(); - $y = $center->getY(); - $width = $size->getWidth(); - $height = $size->getHeight(); - - try { - $pixel = $this->getColor($color); - $arc = new \GmagickDraw(); - - $arc->setstrokecolor($pixel); - $arc->setstrokewidth(max(1, (int) $thickness)); - $arc->setfillcolor('transparent'); - $arc->arc( - $x - $width / 2, - $y - $height / 2, - $x + $width / 2, - $y + $height / 2, - $start, - $end - ); - - $this->gmagick->drawImage($arc); - - $pixel = null; - - $arc = null; - } catch (\GmagickException $e) { - throw new RuntimeException('Draw arc operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function chord(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1) - { - $x = $center->getX(); - $y = $center->getY(); - $width = $size->getWidth(); - $height = $size->getHeight(); - - try { - $pixel = $this->getColor($color); - $chord = new \GmagickDraw(); - - $chord->setstrokecolor($pixel); - $chord->setstrokewidth(max(1, (int) $thickness)); - - if ($fill) { - $chord->setfillcolor($pixel); - } else { - $x1 = round($x + $width / 2 * cos(deg2rad($start))); - $y1 = round($y + $height / 2 * sin(deg2rad($start))); - $x2 = round($x + $width / 2 * cos(deg2rad($end))); - $y2 = round($y + $height / 2 * sin(deg2rad($end))); - - $this->line(new Point($x1, $y1), new Point($x2, $y2), $color); - - $chord->setfillcolor('transparent'); - } - - $chord->arc($x - $width / 2, $y - $height / 2, $x + $width / 2, $y + $height / 2, $start, $end); - - $this->gmagick->drawImage($chord); - - $pixel = null; - - $chord = null; - } catch (\GmagickException $e) { - throw new RuntimeException('Draw chord operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function ellipse(PointInterface $center, BoxInterface $size, ColorInterface $color, $fill = false, $thickness = 1) - { - $width = $size->getWidth(); - $height = $size->getHeight(); - - try { - $pixel = $this->getColor($color); - $ellipse = new \GmagickDraw(); - - $ellipse->setstrokecolor($pixel); - $ellipse->setstrokewidth(max(1, (int) $thickness)); - - if ($fill) { - $ellipse->setfillcolor($pixel); - } else { - $ellipse->setfillcolor('transparent'); - } - - $ellipse->ellipse( - $center->getX(), - $center->getY(), - $width / 2, - $height / 2, - 0, 360 - ); - - $this->gmagick->drawImage($ellipse); - - $pixel = null; - - $ellipse = null; - } catch (\GmagickException $e) { - throw new RuntimeException('Draw ellipse operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function line(PointInterface $start, PointInterface $end, ColorInterface $color, $thickness = 1) - { - try { - $pixel = $this->getColor($color); - $line = new \GmagickDraw(); - - $line->setstrokecolor($pixel); - $line->setstrokewidth(max(1, (int) $thickness)); - $line->setfillcolor($pixel); - $line->line( - $start->getX(), - $start->getY(), - $end->getX(), - $end->getY() - ); - - $this->gmagick->drawImage($line); - - $pixel = null; - - $line = null; - } catch (\GmagickException $e) { - throw new RuntimeException('Draw line operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function pieSlice(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1) - { - $width = $size->getWidth(); - $height = $size->getHeight(); - - $x1 = round($center->getX() + $width / 2 * cos(deg2rad($start))); - $y1 = round($center->getY() + $height / 2 * sin(deg2rad($start))); - $x2 = round($center->getX() + $width / 2 * cos(deg2rad($end))); - $y2 = round($center->getY() + $height / 2 * sin(deg2rad($end))); - - if ($fill) { - $this->chord($center, $size, $start, $end, $color, true, $thickness); - $this->polygon( - array( - $center, - new Point($x1, $y1), - new Point($x2, $y2), - ), - $color, - true, - $thickness - ); - } else { - $this->arc($center, $size, $start, $end, $color, $thickness); - $this->line($center, new Point($x1, $y1), $color, $thickness); - $this->line($center, new Point($x2, $y2), $color, $thickness); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function dot(PointInterface $position, ColorInterface $color) - { - $x = $position->getX(); - $y = $position->getY(); - - try { - $pixel = $this->getColor($color); - $point = new \GmagickDraw(); - - $point->setfillcolor($pixel); - $point->point($x, $y); - - $this->gmagick->drawimage($point); - - $pixel = null; - $point = null; - } catch (\GmagickException $e) { - throw new RuntimeException('Draw point operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function polygon(array $coordinates, ColorInterface $color, $fill = false, $thickness = 1) - { - if (count($coordinates) < 3) { - throw new InvalidArgumentException(sprintf('Polygon must consist of at least 3 coordinates, %d given', count($coordinates))); - } - - $points = array_map(function (PointInterface $p) { - return array('x' => $p->getX(), 'y' => $p->getY()); - }, $coordinates); - - try { - $pixel = $this->getColor($color); - $polygon = new \GmagickDraw(); - - $polygon->setstrokecolor($pixel); - $polygon->setstrokewidth(max(1, (int) $thickness)); - - if ($fill) { - $polygon->setfillcolor($pixel); - } else { - $polygon->setfillcolor('transparent'); - } - - $polygon->polygon($points); - - $this->gmagick->drawImage($polygon); - - unset($pixel, $polygon); - } catch (\GmagickException $e) { - throw new RuntimeException('Draw polygon operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function text($string, AbstractFont $font, PointInterface $position, $angle = 0, $width = null) - { - try { - $pixel = $this->getColor($font->getColor()); - $text = new \GmagickDraw(); - - $text->setfont($font->getFile()); - /** - * @see http://www.php.net/manual/en/imagick.queryfontmetrics.php#101027 - * - * ensure font resolution is the same as GD's hard-coded 96 - */ - $text->setfontsize((int) ($font->getSize() * (96 / 72))); - $text->setfillcolor($pixel); - - $info = $this->gmagick->queryfontmetrics($text, $string); - $rad = deg2rad($angle); - $cos = cos($rad); - $sin = sin($rad); - - $x1 = round(0 * $cos - 0 * $sin); - $x2 = round($info['textWidth'] * $cos - $info['textHeight'] * $sin); - $y1 = round(0 * $sin + 0 * $cos); - $y2 = round($info['textWidth'] * $sin + $info['textHeight'] * $cos); - - $xdiff = 0 - min($x1, $x2); - $ydiff = 0 - min($y1, $y2); - - if ($width !== null) { - throw new NotSupportedException('Gmagick doesn\'t support queryfontmetrics function for multiline text', 1); - } - - $this->gmagick->annotateimage($text, $position->getX() + $x1 + $xdiff, $position->getY() + $y2 + $ydiff, $angle, $string); - - unset($pixel, $text); - } catch (\GmagickException $e) { - throw new RuntimeException('Draw text operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * Gets specifically formatted color string from Color instance - * - * @param ColorInterface $color - * - * @return \GmagickPixel - * - * @throws InvalidArgumentException In case a non-opaque color is passed - */ - private function getColor(ColorInterface $color) - { - if (!$color->isOpaque()) { - throw new InvalidArgumentException('Gmagick doesn\'t support transparency'); - } - - return new \GmagickPixel((string) $color); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Gmagick/Effects.php b/snappymail/v/0.0.0/app/libraries/Imagine/Gmagick/Effects.php deleted file mode 100644 index 3f9c5cd08..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Gmagick/Effects.php +++ /dev/null @@ -1,106 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Gmagick; - -use Imagine\Effects\EffectsInterface; -use Imagine\Exception\RuntimeException; -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Exception\NotSupportedException; - -/** - * Effects implementation using the Gmagick PHP extension - */ -class Effects implements EffectsInterface -{ - private $gmagick; - - public function __construct(\Gmagick $gmagick) - { - $this->gmagick = $gmagick; - } - - /** - * {@inheritdoc} - */ - public function gamma($correction) - { - try { - $this->gmagick->gammaimage($correction); - } catch (\GmagickException $e) { - throw new RuntimeException('Failed to apply gamma correction to the image'); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function negative() - { - if (!method_exists($this->gmagick, 'negateimage')) { - throw new NotSupportedException('Gmagick version 1.1.0 RC3 is required for negative effect'); - } - - try { - $this->gmagick->negateimage(false, \Gmagick::CHANNEL_ALL); - } catch (\GmagickException $e) { - throw new RuntimeException('Failed to negate the image'); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function grayscale() - { - try { - $this->gmagick->setImageType(2); - } catch (\GmagickException $e) { - throw new RuntimeException('Failed to grayscale the image'); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function colorize(ColorInterface $color) - { - throw new NotSupportedException('Gmagick does not support colorize'); - } - - /** - * {@inheritdoc} - */ - public function sharpen() - { - throw new NotSupportedException('Gmagick does not support sharpen yet'); - } - - /** - * {@inheritdoc} - */ - public function blur($sigma = 1) - { - try { - $this->gmagick->blurImage(0, $sigma); - } catch (\GmagickException $e) { - throw new RuntimeException('Failed to blur the image', $e->getCode(), $e); - } - - return $this; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Gmagick/Font.php b/snappymail/v/0.0.0/app/libraries/Imagine/Gmagick/Font.php deleted file mode 100644 index ad67c5647..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Gmagick/Font.php +++ /dev/null @@ -1,63 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Gmagick; - -use Imagine\Image\AbstractFont; -use Imagine\Image\Box; -use Imagine\Image\Palette\Color\ColorInterface; - -/** - * Font implementation using the Gmagick PHP extension - */ -final class Font extends AbstractFont -{ - /** - * @var \Gmagick - */ - private $gmagick; - - /** - * @param \Gmagick $gmagick - * @param string $file - * @param integer $size - * @param ColorInterface $color - */ - public function __construct(\Gmagick $gmagick, $file, $size, ColorInterface $color) - { - $this->gmagick = $gmagick; - - parent::__construct($file, $size, $color); - } - - /** - * {@inheritdoc} - */ - public function box($string, $angle = 0) - { - $text = new \GmagickDraw(); - - $text->setfont($this->file); - /** - * @see http://www.php.net/manual/en/imagick.queryfontmetrics.php#101027 - * - * ensure font resolution is the same as GD's hard-coded 96 - */ - $text->setfontsize((int) ($this->size * (96 / 72))); - $text->setfontstyle(\Gmagick::STYLE_OBLIQUE); - - $info = $this->gmagick->queryfontmetrics($text, $string); - - $box = new Box($info['textWidth'], $info['textHeight']); - - return $box; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Gmagick/Image.php b/snappymail/v/0.0.0/app/libraries/Imagine/Gmagick/Image.php deleted file mode 100644 index 61ef858c1..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Gmagick/Image.php +++ /dev/null @@ -1,786 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Gmagick; - -use Imagine\Exception\OutOfBoundsException; -use Imagine\Exception\InvalidArgumentException; -use Imagine\Exception\RuntimeException; -use Imagine\Image\AbstractImage; -use Imagine\Image\Metadata\MetadataBag; -use Imagine\Image\Palette\PaletteInterface; -use Imagine\Image\ImageInterface; -use Imagine\Image\Box; -use Imagine\Image\BoxInterface; -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Image\Fill\FillInterface; -use Imagine\Image\Point; -use Imagine\Image\PointInterface; -use Imagine\Image\ProfileInterface; - -/** - * Image implementation using the Gmagick PHP extension - */ -final class Image extends AbstractImage -{ - /** - * @var \Gmagick - */ - private $gmagick; - /** - * @var Layers - */ - private $layers; - - /** - * @var PaletteInterface - */ - private $palette; - - private static $colorspaceMapping = array( - PaletteInterface::PALETTE_CMYK => \Gmagick::COLORSPACE_CMYK, - PaletteInterface::PALETTE_RGB => \Gmagick::COLORSPACE_RGB, - ); - - /** - * Constructs a new Image instance - * - * @param \Gmagick $gmagick - * @param PaletteInterface $palette - * @param MetadataBag $metadata - */ - public function __construct(\Gmagick $gmagick, PaletteInterface $palette, MetadataBag $metadata) - { - $this->metadata = $metadata; - $this->gmagick = $gmagick; - $this->setColorspace($palette); - $this->layers = new Layers($this, $this->palette, $this->gmagick); - } - - /** - * Destroys allocated gmagick resources - */ - public function __destruct() - { - if ($this->gmagick instanceof \Gmagick) { - $this->gmagick->clear(); - $this->gmagick->destroy(); - } - } - - /** - * Returns gmagick instance - * - * @return Gmagick - */ - public function getGmagick() - { - return $this->gmagick; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function copy() - { - return new self(clone $this->gmagick, $this->palette, clone $this->metadata); - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function crop(PointInterface $start, BoxInterface $size) - { - if (!$start->in($this->getSize())) { - throw new OutOfBoundsException('Crop coordinates must start at minimum 0, 0 position from top left corner, crop height and width must be positive integers and must not exceed the current image borders'); - } - - try { - $this->gmagick->cropimage($size->getWidth(), $size->getHeight(), $start->getX(), $start->getY()); - } catch (\GmagickException $e) { - throw new RuntimeException('Crop operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function flipHorizontally() - { - try { - $this->gmagick->flopimage(); - } catch (\GmagickException $e) { - throw new RuntimeException('Horizontal flip operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function flipVertically() - { - try { - $this->gmagick->flipimage(); - } catch (\GmagickException $e) { - throw new RuntimeException('Vertical flip operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function strip() - { - try { - try { - $this->profile($this->palette->profile()); - } catch (\Exception $e) { - // here we discard setting the profile as the previous incorporated profile - // is corrupted, let's now strip the image - } - $this->gmagick->stripimage(); - } catch (\GmagickException $e) { - throw new RuntimeException('Strip operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function paste(ImageInterface $image, PointInterface $start) - { - if (!$image instanceof self) { - throw new InvalidArgumentException(sprintf('Gmagick\Image can only paste() Gmagick\Image instances, %s given', get_class($image))); - } - - if (!$this->getSize()->contains($image->getSize(), $start)) { - throw new OutOfBoundsException('Cannot paste image of the given size at the specified position, as it moves outside of the current image\'s box'); - } - - try { - $this->gmagick->compositeimage($image->gmagick, \Gmagick::COMPOSITE_DEFAULT, $start->getX(), $start->getY()); - } catch (\GmagickException $e) { - throw new RuntimeException('Paste operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function resize(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED) - { - static $supportedFilters = array( - ImageInterface::FILTER_UNDEFINED => \Gmagick::FILTER_UNDEFINED, - ImageInterface::FILTER_BESSEL => \Gmagick::FILTER_BESSEL, - ImageInterface::FILTER_BLACKMAN => \Gmagick::FILTER_BLACKMAN, - ImageInterface::FILTER_BOX => \Gmagick::FILTER_BOX, - ImageInterface::FILTER_CATROM => \Gmagick::FILTER_CATROM, - ImageInterface::FILTER_CUBIC => \Gmagick::FILTER_CUBIC, - ImageInterface::FILTER_GAUSSIAN => \Gmagick::FILTER_GAUSSIAN, - ImageInterface::FILTER_HANNING => \Gmagick::FILTER_HANNING, - ImageInterface::FILTER_HAMMING => \Gmagick::FILTER_HAMMING, - ImageInterface::FILTER_HERMITE => \Gmagick::FILTER_HERMITE, - ImageInterface::FILTER_LANCZOS => \Gmagick::FILTER_LANCZOS, - ImageInterface::FILTER_MITCHELL => \Gmagick::FILTER_MITCHELL, - ImageInterface::FILTER_POINT => \Gmagick::FILTER_POINT, - ImageInterface::FILTER_QUADRATIC => \Gmagick::FILTER_QUADRATIC, - ImageInterface::FILTER_SINC => \Gmagick::FILTER_SINC, - ImageInterface::FILTER_TRIANGLE => \Gmagick::FILTER_TRIANGLE - ); - - if (!array_key_exists($filter, $supportedFilters)) { - throw new InvalidArgumentException('Unsupported filter type'); - } - - try { - $this->gmagick->resizeimage($size->getWidth(), $size->getHeight(), $supportedFilters[$filter], 1); - } catch (\GmagickException $e) { - throw new RuntimeException('Resize operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function rotate($angle, ColorInterface $background = null) - { - try { - $background = $background ?: $this->palette->color('fff'); - $pixel = $this->getColor($background); - - $this->gmagick->rotateimage($pixel, $angle); - - unset($pixel); - } catch (\GmagickException $e) { - throw new RuntimeException('Rotate operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * Internal - * - * Applies options before save or output - * - * @param \Gmagick $image - * @param array $options - * @param string $path - * - * @throws InvalidArgumentException - */ - private function applyImageOptions(\Gmagick $image, array $options, $path) - { - if (isset($options['format'])) { - $format = $options['format']; - } elseif ('' !== $extension = pathinfo($path, \PATHINFO_EXTENSION)) { - $format = $extension; - } else { - $format = pathinfo($image->getImageFilename(), \PATHINFO_EXTENSION); - } - - $format = strtolower($format); - - $options = $this->updateSaveOptions($options); - - if (isset($options['jpeg_quality']) && in_array($format, array('jpeg', 'jpg', 'pjpeg'))) { - $image->setCompressionQuality($options['jpeg_quality']); - } - - if ((isset($options['png_compression_level']) || isset($options['png_compression_filter'])) && $format === 'png') { - // first digit: compression level (default: 7) - if (isset($options['png_compression_level'])) { - if ($options['png_compression_level'] < 0 || $options['png_compression_level'] > 9) { - throw new InvalidArgumentException('png_compression_level option should be an integer from 0 to 9'); - } - $compression = $options['png_compression_level'] * 10; - } else { - $compression = 70; - } - - // second digit: compression filter (default: 5) - if (isset($options['png_compression_filter'])) { - if ($options['png_compression_filter'] < 0 || $options['png_compression_filter'] > 9) { - throw new InvalidArgumentException('png_compression_filter option should be an integer from 0 to 9'); - } - $compression += $options['png_compression_filter']; - } else { - $compression += 5; - } - - $image->setCompressionQuality($compression); - } - - if (isset($options['resolution-units']) && isset($options['resolution-x']) && isset($options['resolution-y'])) { - if ($options['resolution-units'] == ImageInterface::RESOLUTION_PIXELSPERCENTIMETER) { - $image->setimageunits(\Gmagick::RESOLUTION_PIXELSPERCENTIMETER); - } elseif ($options['resolution-units'] == ImageInterface::RESOLUTION_PIXELSPERINCH) { - $image->setimageunits(\Gmagick::RESOLUTION_PIXELSPERINCH); - } else { - throw new InvalidArgumentException('Unsupported image unit format'); - } - - $image->setimageresolution($options['resolution-x'], $options['resolution-y']); - } - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function save($path = null, array $options = array()) - { - $path = null === $path ? $this->gmagick->getImageFilename() : $path; - - if ('' === trim($path)) { - throw new RuntimeException('You can omit save path only if image has been open from a file'); - } - - try { - $this->prepareOutput($options, $path); - $allFrames = !isset($options['animated']) || false === $options['animated']; - $this->gmagick->writeimage($path, $allFrames); - } catch (\GmagickException $e) { - throw new RuntimeException('Save operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function show($format, array $options = array()) - { - header('Content-type: '.$this->getMimeType($format)); - echo $this->get($format, $options); - - return $this; - } - - /** - * {@inheritdoc} - */ - public function get($format, array $options = array()) - { - try { - $options['format'] = $format; - $this->prepareOutput($options); - } catch (\GmagickException $e) { - throw new RuntimeException('Get operation failed', $e->getCode(), $e); - } - - return $this->gmagick->getimagesblob(); - } - - /** - * @param array $options - * @param string $path - */ - private function prepareOutput(array $options, $path = null) - { - if (isset($options['format'])) { - $this->gmagick->setimageformat($options['format']); - } - - if (isset($options['animated']) && true === $options['animated']) { - $format = isset($options['format']) ? $options['format'] : 'gif'; - $delay = isset($options['animated.delay']) ? $options['animated.delay'] : null; - $loops = isset($options['animated.loops']) ? $options['animated.loops'] : 0; - - $options['flatten'] = false; - - $this->layers->animate($format, $delay, $loops); - } else { - $this->layers->merge(); - } - $this->applyImageOptions($this->gmagick, $options, $path); - - // flatten only if image has multiple layers - if ((!isset($options['flatten']) || $options['flatten'] === true) && count($this->layers) > 1) { - $this->flatten(); - } - } - - /** - * {@inheritdoc} - */ - public function __toString() - { - return $this->get('png'); - } - - /** - * {@inheritdoc} - */ - public function draw() - { - return new Drawer($this->gmagick); - } - - /** - * {@inheritdoc} - */ - public function effects() - { - return new Effects($this->gmagick); - } - - /** - * {@inheritdoc} - */ - public function getSize() - { - try { - $i = $this->gmagick->getimageindex(); - $this->gmagick->setimageindex(0); //rewind - $width = $this->gmagick->getimagewidth(); - $height = $this->gmagick->getimageheight(); - $this->gmagick->setimageindex($i); - } catch (\GmagickException $e) { - throw new RuntimeException('Get size operation failed', $e->getCode(), $e); - } - - return new Box($width, $height); - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function applyMask(ImageInterface $mask) - { - if (!$mask instanceof self) { - throw new InvalidArgumentException('Can only apply instances of Imagine\Gmagick\Image as masks'); - } - - $size = $this->getSize(); - $maskSize = $mask->getSize(); - - if ($size != $maskSize) { - throw new InvalidArgumentException(sprintf('The given mask doesn\'t match current image\'s size, current mask\'s dimensions are %s, while image\'s dimensions are %s', $maskSize, $size)); - } - - try { - $mask = $mask->copy(); - $this->gmagick->compositeimage($mask->gmagick, \Gmagick::COMPOSITE_DEFAULT, 0, 0); - } catch (\GmagickException $e) { - throw new RuntimeException('Apply mask operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function mask() - { - $mask = $this->copy(); - - try { - $mask->gmagick->modulateimage(100, 0, 100); - } catch (\GmagickException $e) { - throw new RuntimeException('Mask operation failed', $e->getCode(), $e); - } - - return $mask; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function fill(FillInterface $fill) - { - try { - $draw = new \GmagickDraw(); - $size = $this->getSize(); - - $w = $size->getWidth(); - $h = $size->getHeight(); - - for ($x = 0; $x <= $w; $x++) { - for ($y = 0; $y <= $h; $y++) { - $pixel = $this->getColor($fill->getColor(new Point($x, $y))); - - $draw->setfillcolor($pixel); - $draw->point($x, $y); - - $pixel = null; - } - } - - $this->gmagick->drawimage($draw); - - $draw = null; - } catch (\GmagickException $e) { - throw new RuntimeException('Fill operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function histogram() - { - try { - $pixels = $this->gmagick->getimagehistogram(); - } catch (\GmagickException $e) { - throw new RuntimeException('Error while fetching histogram', $e->getCode(), $e); - } - - $image = $this; - - return array_map(function (\GmagickPixel $pixel) use ($image) { - return $image->pixelToColor($pixel); - }, $pixels); - } - - /** - * {@inheritdoc} - */ - public function getColorAt(PointInterface $point) - { - if (!$point->in($this->getSize())) { - throw new InvalidArgumentException(sprintf('Error getting color at point [%s,%s]. The point must be inside the image of size [%s,%s]', $point->getX(), $point->getY(), $this->getSize()->getWidth(), $this->getSize()->getHeight())); - } - - try { - $cropped = clone $this->gmagick; - $histogram = $cropped - ->cropImage(1, 1, $point->getX(), $point->getY()) - ->getImageHistogram(); - } catch (\GmagickException $e) { - throw new RuntimeException('Unable to get the pixel'); - } - - $pixel = array_shift($histogram); - - unset($histogram, $cropped); - - return $this->pixelToColor($pixel); - } - - /** - * Returns a color given a pixel, depending the Palette context - * - * Note : this method is public for PHP 5.3 compatibility - * - * @param \GmagickPixel $pixel - * - * @return ColorInterface - * - * @throws InvalidArgumentException In case a unknown color is requested - */ - public function pixelToColor(\GmagickPixel $pixel) - { - static $colorMapping = array( - ColorInterface::COLOR_RED => \Gmagick::COLOR_RED, - ColorInterface::COLOR_GREEN => \Gmagick::COLOR_GREEN, - ColorInterface::COLOR_BLUE => \Gmagick::COLOR_BLUE, - ColorInterface::COLOR_CYAN => \Gmagick::COLOR_CYAN, - ColorInterface::COLOR_MAGENTA => \Gmagick::COLOR_MAGENTA, - ColorInterface::COLOR_YELLOW => \Gmagick::COLOR_YELLOW, - ColorInterface::COLOR_KEYLINE => \Gmagick::COLOR_BLACK, - // There is no gray component in \Gmagick, let's use one of the RGB comp - ColorInterface::COLOR_GRAY => \Gmagick::COLOR_RED, - ); - - if ($this->palette->supportsAlpha()) { - try { - $alpha = (int) round($pixel->getcolorvalue(\Gmagick::COLOR_ALPHA) * 100); - } catch (\GmagickPixelException $e) { - $alpha = null; - } - } else { - $alpha = null; - } - - $palette = $this->palette(); - - return $this->palette->color(array_map(function ($color) use ($palette, $pixel, $colorMapping) { - if (!isset($colorMapping[$color])) { - throw new InvalidArgumentException(sprintf('Color %s is not mapped in Gmagick', $color)); - } - $multiplier = 255; - if ($palette->name() === PaletteInterface::PALETTE_CMYK) { - $multiplier = 100; - } - - return $pixel->getcolorvalue($colorMapping[$color]) * $multiplier; - }, $this->palette->pixelDefinition()), $alpha); - } - - /** - * {@inheritdoc} - */ - public function layers() - { - return $this->layers; - } - - /** - * {@inheritdoc} - */ - public function interlace($scheme) - { - static $supportedInterlaceSchemes = array( - ImageInterface::INTERLACE_NONE => \Gmagick::INTERLACE_NO, - ImageInterface::INTERLACE_LINE => \Gmagick::INTERLACE_LINE, - ImageInterface::INTERLACE_PLANE => \Gmagick::INTERLACE_PLANE, - ImageInterface::INTERLACE_PARTITION => \Gmagick::INTERLACE_PARTITION, - ); - - if (!array_key_exists($scheme, $supportedInterlaceSchemes)) { - throw new InvalidArgumentException('Unsupported interlace type'); - } - - $this->gmagick->setInterlaceScheme($supportedInterlaceSchemes[$scheme]); - - return $this; - } - - /** - * {@inheritdoc} - */ - public function usePalette(PaletteInterface $palette) - { - if (!isset(static::$colorspaceMapping[$palette->name()])) { - throw new InvalidArgumentException(sprintf('The palette %s is not supported by Gmagick driver',$palette->name())); - } - - if ($this->palette->name() === $palette->name()) { - return $this; - } - - try { - try { - $hasICCProfile = (Boolean) $this->gmagick->getimageprofile('ICM'); - } catch (\GmagickException $e) { - $hasICCProfile = false; - } - - if (!$hasICCProfile) { - $this->profile($this->palette->profile()); - } - - $this->profile($palette->profile()); - - $this->setColorspace($palette); - $this->palette = $palette; - } catch (\GmagickException $e) { - throw new RuntimeException('Failed to set colorspace', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function palette() - { - return $this->palette; - } - - /** - * {@inheritdoc} - */ - public function profile(ProfileInterface $profile) - { - try { - $this->gmagick->profileimage('ICM', $profile->data()); - } catch (\GmagickException $e) { - throw new RuntimeException(sprintf('Unable to add profile %s to image', $profile->name()), $e->getCode(), $e); - } - - return $this; - } - - /** - * Internal - * - * Flatten the image. - */ - private function flatten() - { - /** - * @see http://pecl.php.net/bugs/bug.php?id=22435 - */ - if (method_exists($this->gmagick, 'flattenImages')) { - try { - $this->gmagick = $this->gmagick->flattenImages(); - } catch (\GmagickException $e) { - throw new RuntimeException('Flatten operation failed', $e->getCode(), $e); - } - } - } - - /** - * Gets specifically formatted color string from Color instance - * - * @param ColorInterface $color - * - * @return \GmagickPixel - * - * @throws InvalidArgumentException - */ - private function getColor(ColorInterface $color) - { - if (!$color->isOpaque()) { - throw new InvalidArgumentException('Gmagick doesn\'t support transparency'); - } - - return new \GmagickPixel((string) $color); - } - - /** - * Internal - * - * Get the mime type based on format. - * - * @param string $format - * - * @return string mime-type - * - * @throws InvalidArgumentException - */ - private function getMimeType($format) - { - static $mimeTypes = array( - 'jpeg' => 'image/jpeg', - 'jpg' => 'image/jpeg', - 'gif' => 'image/gif', - 'png' => 'image/png', - 'wbmp' => 'image/vnd.wap.wbmp', - 'xbm' => 'image/xbm', - ); - - if (!isset($mimeTypes[$format])) { - throw new InvalidArgumentException(sprintf('Unsupported format given. Only %s are supported, %s given', implode(", ", array_keys($mimeTypes)), $format)); - } - - return $mimeTypes[$format]; - } - - /** - * Sets colorspace and image type, assigns the palette. - * - * @param PaletteInterface $palette - * - * @throws InvalidArgumentException - */ - private function setColorspace(PaletteInterface $palette) - { - if (!isset(static::$colorspaceMapping[$palette->name()])) { - throw new InvalidArgumentException(sprintf('The palette %s is not supported by Gmagick driver', $palette->name())); - } - - $this->gmagick->setimagecolorspace(static::$colorspaceMapping[$palette->name()]); - $this->palette = $palette; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Gmagick/Imagine.php b/snappymail/v/0.0.0/app/libraries/Imagine/Gmagick/Imagine.php deleted file mode 100644 index ce4d4ed6c..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Gmagick/Imagine.php +++ /dev/null @@ -1,167 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Gmagick; - -use Imagine\Image\AbstractImagine; -use Imagine\Exception\NotSupportedException; -use Imagine\Image\BoxInterface; -use Imagine\Image\Metadata\MetadataBag; -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Image\Palette\Grayscale; -use Imagine\Image\Palette\CMYK; -use Imagine\Image\Palette\RGB; -use Imagine\Image\Palette\Color\CMYK as CMYKColor; -use Imagine\Exception\InvalidArgumentException; -use Imagine\Exception\RuntimeException; - -/** - * Imagine implementation using the Gmagick PHP extension - */ -class Imagine extends AbstractImagine -{ - /** - * @throws RuntimeException - */ - public function __construct() - { - if (!class_exists('Gmagick')) { - throw new RuntimeException('Gmagick not installed'); - } - } - - /** - * {@inheritdoc} - */ - public function open($path) - { - $path = $this->checkPath($path); - - try { - $gmagick = new \Gmagick($path); - $image = new Image($gmagick, $this->createPalette($gmagick), $this->getMetadataReader()->readFile($path)); - } catch (\GmagickException $e) { - throw new RuntimeException(sprintf('Unable to open image %s', $path), $e->getCode(), $e); - } - - return $image; - } - - /** - * {@inheritdoc} - */ - public function create(BoxInterface $size, ColorInterface $color = null) - { - $width = $size->getWidth(); - $height = $size->getHeight(); - - $palette = null !== $color ? $color->getPalette() : new RGB(); - $color = null !== $color ? $color : $palette->color('fff'); - - try { - $gmagick = new \Gmagick(); - // Gmagick does not support creation of CMYK GmagickPixel - // see https://bugs.php.net/bug.php?id=64466 - if ($color instanceof CMYKColor) { - $switchPalette = $palette; - $palette = new RGB(); - $pixel = new \GmagickPixel($palette->color((string) $color)); - } else { - $switchPalette = null; - $pixel = new \GmagickPixel((string) $color); - } - - if ($color->getPalette()->supportsAlpha() && $color->getAlpha() < 100) { - throw new NotSupportedException('alpha transparency is not supported'); - } - - $gmagick->newimage($width, $height, $pixel->getcolor(false)); - $gmagick->setimagecolorspace(\Gmagick::COLORSPACE_TRANSPARENT); - $gmagick->setimagebackgroundcolor($pixel); - - $image = new Image($gmagick, $palette, new MetadataBag()); - - if ($switchPalette) { - $image->usePalette($switchPalette); - } - - return $image; - } catch (\GmagickException $e) { - throw new RuntimeException('Could not create empty image', $e->getCode(), $e); - } - } - - /** - * {@inheritdoc} - */ - public function load($string) - { - return $this->doLoad($string, $this->getMetadataReader()->readData($string)); - } - - /** - * {@inheritdoc} - */ - public function read($resource) - { - if (!is_resource($resource)) { - throw new InvalidArgumentException('Variable does not contain a stream resource'); - } - - $content = stream_get_contents($resource); - - if (false === $content) { - throw new InvalidArgumentException('Couldn\'t read given resource'); - } - - return $this->doLoad($content, $this->getMetadataReader()->readStream($resource)); - } - - /** - * {@inheritdoc} - */ - public function font($file, $size, ColorInterface $color) - { - $gmagick = new \Gmagick(); - $gmagick->newimage(1, 1, 'transparent'); - - return new Font($gmagick, $file, $size, $color); - } - - private function createPalette(\Gmagick $gmagick) - { - switch ($gmagick->getimagecolorspace()) { - case \Gmagick::COLORSPACE_SRGB: - case \Gmagick::COLORSPACE_RGB: - return new RGB(); - case \Gmagick::COLORSPACE_CMYK: - return new CMYK(); - case \Gmagick::COLORSPACE_GRAY: - return new Grayscale(); - default: - throw new NotSupportedException('Only RGB and CMYK colorspace are currently supported'); - } - } - - private function doLoad($content, MetadataBag $metadata) - { - try { - $gmagick = new \Gmagick(); - $gmagick->readimageblob($content); - } catch (\GmagickException $e) { - throw new RuntimeException( - 'Could not load image from string', $e->getCode(), $e - ); - } - - return new Image($gmagick, $this->createPalette($gmagick), $metadata); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Gmagick/Layers.php b/snappymail/v/0.0.0/app/libraries/Imagine/Gmagick/Layers.php deleted file mode 100644 index d708812a1..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Gmagick/Layers.php +++ /dev/null @@ -1,272 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Gmagick; - -use Imagine\Image\AbstractLayers; -use Imagine\Exception\RuntimeException; -use Imagine\Exception\NotSupportedException; -use Imagine\Exception\OutOfBoundsException; -use Imagine\Exception\InvalidArgumentException; -use Imagine\Image\Metadata\MetadataBag; -use Imagine\Image\Palette\PaletteInterface; - -class Layers extends AbstractLayers -{ - /** - * @var Image - */ - private $image; - - /** - * @var \Gmagick - */ - private $resource; - - /** - * @var integer - */ - private $offset = 0; - - /** - * @var array - */ - private $layers = array(); - - /** - * @var PaletteInterface - */ - private $palette; - - public function __construct(Image $image, PaletteInterface $palette, \Gmagick $resource) - { - $this->image = $image; - $this->resource = $resource; - $this->palette = $palette; - } - - /** - * {@inheritdoc} - */ - public function merge() - { - foreach ($this->layers as $offset => $image) { - try { - $this->resource->setimageindex($offset); - $this->resource->setimage($image->getGmagick()); - } catch (\GmagickException $e) { - throw new RuntimeException('Failed to substitute layer', $e->getCode(), $e); - } - } - } - - /** - * {@inheritdoc} - */ - public function coalesce() - { - throw new NotSupportedException('Gmagick does not support coalescing'); - } - - /** - * {@inheritdoc} - */ - public function animate($format, $delay, $loops) - { - if ('gif' !== strtolower($format)) { - throw new NotSupportedException('Animated picture is currently only supported on gif'); - } - - if (!is_int($loops) || $loops < 0) { - throw new InvalidArgumentException('Loops must be a positive integer.'); - } - - if (null !== $delay && (!is_int($delay) || $delay < 0)) { - throw new InvalidArgumentException('Delay must be either null or a positive integer.'); - } - - try { - foreach ($this as $offset => $layer) { - $this->resource->setimageindex($offset); - $this->resource->setimageformat($format); - - if (null !== $delay) { - $this->resource->setimagedelay($delay / 10); - } - - $this->resource->setimageiterations($loops); - } - } catch (\GmagickException $e) { - throw new RuntimeException('Failed to animate layers', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function current() - { - return $this->extractAt($this->offset); - } - - /** - * Tries to extract layer at given offset - * - * @param integer $offset - * @return Image - * @throws RuntimeException - */ - private function extractAt($offset) - { - if (!isset($this->layers[$offset])) { - try { - $this->resource->setimageindex($offset); - $this->layers[$offset] = new Image($this->resource->getimage(), $this->palette, new MetadataBag()); - } catch (\GmagickException $e) { - throw new RuntimeException(sprintf('Failed to extract layer %d', $offset), $e->getCode(), $e); - } - } - - return $this->layers[$offset]; - } - - /** - * {@inheritdoc} - */ - public function key() - { - return $this->offset; - } - - /** - * {@inheritdoc} - */ - public function next() - { - ++$this->offset; - } - - /** - * {@inheritdoc} - */ - public function rewind() - { - $this->offset = 0; - } - - /** - * {@inheritdoc} - */ - public function valid() - { - return $this->offset < count($this); - } - - /** - * {@inheritdoc} - */ - public function count() - { - try { - return $this->resource->getnumberimages(); - } catch (\GmagickException $e) { - throw new RuntimeException('Failed to count the number of layers', $e->getCode(), $e); - } - } - - /** - * {@inheritdoc} - */ - public function offsetExists($offset) - { - return is_int($offset) && $offset >= 0 && $offset < count($this); - } - - /** - * {@inheritdoc} - */ - public function offsetGet($offset) - { - return $this->extractAt($offset); - } - - /** - * {@inheritdoc} - */ - public function offsetSet($offset, $image) - { - if (!$image instanceof Image) { - throw new InvalidArgumentException('Only a Gmagick Image can be used as layer'); - } - - if (null === $offset) { - $offset = count($this) - 1; - } else { - if (!is_int($offset)) { - throw new InvalidArgumentException('Invalid offset for layer, it must be an integer'); - } - - if (count($this) < $offset || 0 > $offset) { - throw new OutOfBoundsException(sprintf('Invalid offset for layer, it must be a value between 0 and %d, %d given', count($this), $offset)); - } - - if (isset($this[$offset])) { - unset($this[$offset]); - $offset = $offset - 1; - } - } - - $frame = $image->getGmagick(); - - try { - if (count($this) > 0) { - $this->resource->setimageindex($offset); - $this->resource->nextimage(); - } - $this->resource->addimage($frame); - - /** - * ugly hack to bypass issue https://bugs.php.net/bug.php?id=64623 - */ - if (count($this) == 2) { - $this->resource->setimageindex($offset+1); - $this->resource->nextimage(); - $this->resource->addimage($frame); - unset($this[0]); - } - } catch (\GmagickException $e) { - throw new RuntimeException('Unable to set the layer', $e->getCode(), $e); - } - - $this->layers = array(); - } - - /** - * {@inheritdoc} - */ - public function offsetUnset($offset) - { - try { - $this->extractAt($offset); - } catch (RuntimeException $e) { - return; - } - - try { - $this->resource->setimageindex($offset); - $this->resource->removeimage(); - } catch (\GmagickException $e) { - throw new RuntimeException('Unable to remove layer', $e->getCode(), $e); - } - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/AbstractFont.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/AbstractFont.php deleted file mode 100644 index 59e9a45ba..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/AbstractFont.php +++ /dev/null @@ -1,75 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image; - -use Imagine\Image\Palette\Color\ColorInterface; - -/** - * Abstract font base class - */ -abstract class AbstractFont implements FontInterface -{ - /** - * @var string - */ - protected $file; - - /** - * @var integer - */ - protected $size; - - /** - * @var ColorInterface - */ - protected $color; - - /** - * Constructs a font with specified $file, $size and $color - * - * The font size is to be specified in points (e.g. 10pt means 10) - * - * @param string $file - * @param integer $size - * @param ColorInterface $color - */ - public function __construct($file, $size, ColorInterface $color) - { - $this->file = $file; - $this->size = $size; - $this->color = $color; - } - - /** - * {@inheritdoc} - */ - final public function getFile() - { - return $this->file; - } - - /** - * {@inheritdoc} - */ - final public function getSize() - { - return $this->size; - } - - /** - * {@inheritdoc} - */ - final public function getColor() - { - return $this->color; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/AbstractImage.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/AbstractImage.php deleted file mode 100644 index 5c85769fd..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/AbstractImage.php +++ /dev/null @@ -1,120 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image; - -use Imagine\Exception\InvalidArgumentException; -use Imagine\Image\Metadata\MetadataBag; - -abstract class AbstractImage implements ImageInterface -{ - /** - * @var MetadataBag - */ - protected $metadata; - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function thumbnail(BoxInterface $size, $mode = ImageInterface::THUMBNAIL_INSET, $filter = ImageInterface::FILTER_UNDEFINED) - { - if ($mode !== ImageInterface::THUMBNAIL_INSET && - $mode !== ImageInterface::THUMBNAIL_OUTBOUND) { - throw new InvalidArgumentException('Invalid mode specified'); - } - - $imageSize = $this->getSize(); - $ratios = array( - $size->getWidth() / $imageSize->getWidth(), - $size->getHeight() / $imageSize->getHeight() - ); - - $thumbnail = $this->copy(); - - $thumbnail->usePalette($this->palette()); - $thumbnail->strip(); - // if target width is larger than image width - // AND target height is longer than image height - if ($size->contains($imageSize)) { - return $thumbnail; - } - - if ($mode === ImageInterface::THUMBNAIL_INSET) { - $ratio = min($ratios); - } else { - $ratio = max($ratios); - } - - if ($mode === ImageInterface::THUMBNAIL_OUTBOUND) { - if (!$imageSize->contains($size)) { - $size = new Box( - min($imageSize->getWidth(), $size->getWidth()), - min($imageSize->getHeight(), $size->getHeight()) - ); - } else { - $imageSize = $thumbnail->getSize()->scale($ratio); - $thumbnail->resize($imageSize, $filter); - } - $thumbnail->crop(new Point( - max(0, round(($imageSize->getWidth() - $size->getWidth()) / 2)), - max(0, round(($imageSize->getHeight() - $size->getHeight()) / 2)) - ), $size); - } else { - if (!$imageSize->contains($size)) { - $imageSize = $imageSize->scale($ratio); - $thumbnail->resize($imageSize, $filter); - } else { - $imageSize = $thumbnail->getSize()->scale($ratio); - $thumbnail->resize($imageSize, $filter); - } - } - - return $thumbnail; - } - - /** - * Updates a given array of save options for backward compatibility with legacy names - * - * @param array $options - * - * @return array - */ - protected function updateSaveOptions(array $options) - { - // Preserve BC until version 1.0 - if (isset($options['quality']) && !isset($options['jpeg_quality'])) { - $options['jpeg_quality'] = $options['quality']; - } - - return $options; - } - - /** - * {@inheritdoc} - */ - public function metadata() - { - return $this->metadata; - } - - /** - * Assures the metadata instance will be cloned, too - */ - public function __clone() - { - if ($this->metadata !== null) { - $this->metadata = clone $this->metadata; - } - } - -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/AbstractImagine.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/AbstractImagine.php deleted file mode 100644 index fcb1a3d67..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/AbstractImagine.php +++ /dev/null @@ -1,79 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image; - -use Imagine\Image\Metadata\DefaultMetadataReader; -use Imagine\Image\Metadata\ExifMetadataReader; -use Imagine\Image\Metadata\MetadataReaderInterface; -use Imagine\Exception\InvalidArgumentException; - -abstract class AbstractImagine implements ImagineInterface -{ - /** @var MetadataReaderInterface */ - private $metadataReader; - - /** - * @param MetadataReaderInterface $metadataReader - * - * @return ImagineInterface - */ - public function setMetadataReader(MetadataReaderInterface $metadataReader) - { - $this->metadataReader = $metadataReader; - - return $this; - } - - /** - * @return MetadataReaderInterface - */ - public function getMetadataReader() - { - if (null === $this->metadataReader) { - if (ExifMetadataReader::isSupported()) { - $this->metadataReader = new ExifMetadataReader(); - } else { - $this->metadataReader = new DefaultMetadataReader(); - } - } - - return $this->metadataReader; - } - - /** - * Checks a path that could be used with ImagineInterface::open and returns - * a proper string. - * - * @param string|object $path - * - * @return string - * - * @throws InvalidArgumentException In case the given path is invalid. - */ - protected function checkPath($path) - { - // provide compatibility with objects such as \SplFileInfo - if (is_object($path) && method_exists($path, '__toString')) { - $path = (string) $path; - } - - $handle = @fopen($path, 'r'); - - if (false === $handle) { - throw new InvalidArgumentException(sprintf('File %s does not exist.', $path)); - } - - fclose($handle); - - return $path; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/AbstractLayers.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/AbstractLayers.php deleted file mode 100644 index 486a72228..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/AbstractLayers.php +++ /dev/null @@ -1,61 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image; - -abstract class AbstractLayers implements LayersInterface -{ - /** - * {@inheritdoc} - */ - public function add(ImageInterface $image) - { - $this[] = $image; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function set($offset, ImageInterface $image) - { - $this[$offset] = $image; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function remove($offset) - { - unset($this[$offset]); - - return $this; - } - - /** - * {@inheritdoc} - */ - public function get($offset) - { - return $this[$offset]; - } - - /** - * {@inheritdoc} - */ - public function has($offset) - { - return isset($this[$offset]); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Box.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Box.php deleted file mode 100644 index 37b85135a..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Box.php +++ /dev/null @@ -1,122 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image; - -use Imagine\Exception\InvalidArgumentException; - -/** - * A box implementation - */ -final class Box implements BoxInterface -{ - /** - * @var integer - */ - private $width; - - /** - * @var integer - */ - private $height; - - /** - * Constructs the Size with given width and height - * - * @param integer $width - * @param integer $height - * - * @throws InvalidArgumentException - */ - public function __construct($width, $height) - { - if ($height < 1 || $width < 1) { - throw new InvalidArgumentException(sprintf('Length of either side cannot be 0 or negative, current size is %sx%s', $width, $height)); - } - - $this->width = (int) $width; - $this->height = (int) $height; - } - - /** - * {@inheritdoc} - */ - public function getWidth() - { - return $this->width; - } - - /** - * {@inheritdoc} - */ - public function getHeight() - { - return $this->height; - } - - /** - * {@inheritdoc} - */ - public function scale($ratio) - { - return new Box(round($ratio * $this->width), round($ratio * $this->height)); - } - - /** - * {@inheritdoc} - */ - public function increase($size) - { - return new Box((int) $size + $this->width, (int) $size + $this->height); - } - - /** - * {@inheritdoc} - */ - public function contains(BoxInterface $box, PointInterface $start = null) - { - $start = $start ? $start : new Point(0, 0); - - return $start->in($this) && $this->width >= $box->getWidth() + $start->getX() && $this->height >= $box->getHeight() + $start->getY(); - } - - /** - * {@inheritdoc} - */ - public function square() - { - return $this->width * $this->height; - } - - /** - * {@inheritdoc} - */ - public function __toString() - { - return sprintf('%dx%d px', $this->width, $this->height); - } - - /** - * {@inheritdoc} - */ - public function widen($width) - { - return $this->scale($width / $this->width); - } - - /** - * {@inheritdoc} - */ - public function heighten($height) - { - return $this->scale($height / $this->height); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/BoxInterface.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/BoxInterface.php deleted file mode 100644 index 4a086c39f..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/BoxInterface.php +++ /dev/null @@ -1,94 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image; - -/** - * Interface for a box - */ -interface BoxInterface -{ - /** - * Gets current image height - * - * @return integer - */ - public function getHeight(); - - /** - * Gets current image width - * - * @return integer - */ - public function getWidth(); - - /** - * Creates new BoxInterface instance with ratios applied to both sides - * - * @param float $ratio - * - * @return BoxInterface - */ - public function scale($ratio); - - /** - * Creates new BoxInterface, adding given size to both sides - * - * @param integer $size - * - * @return BoxInterface - */ - public function increase($size); - - /** - * Checks whether current box can fit given box at a given start position, - * start position defaults to top left corner xy(0,0) - * - * @param BoxInterface $box - * @param PointInterface $start - * - * @return Boolean - */ - public function contains(BoxInterface $box, PointInterface $start = null); - - /** - * Gets current box square, useful for getting total number of pixels in a - * given box - * - * @return integer - */ - public function square(); - - /** - * Returns a string representation of the current box - * - * @return string - */ - public function __toString(); - - /** - * Resizes box to given width, constraining proportions and returns the new box - * - * @param integer $width - * - * @return BoxInterface - */ - public function widen($width); - - /** - * Resizes box to given height, constraining proportions and returns the new box - * - * @param integer $height - * - * @return BoxInterface - */ - public function heighten($height); -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Fill/FillInterface.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Fill/FillInterface.php deleted file mode 100644 index c8d69e5d4..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Fill/FillInterface.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image\Fill; - -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Image\PointInterface; - -/** - * Interface for the fill - */ -interface FillInterface -{ - /** - * Gets color of the fill for the given position - * - * @param PointInterface $position - * - * @return ColorInterface - */ - public function getColor(PointInterface $position); -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Fill/Gradient/Horizontal.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Fill/Gradient/Horizontal.php deleted file mode 100644 index 4a4230671..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Fill/Gradient/Horizontal.php +++ /dev/null @@ -1,28 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image\Fill\Gradient; - -use Imagine\Image\PointInterface; - -/** - * Horizontal gradient fill - */ -final class Horizontal extends Linear -{ - /** - * {@inheritdoc} - */ - public function getDistance(PointInterface $position) - { - return $position->getX(); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Fill/Gradient/Linear.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Fill/Gradient/Linear.php deleted file mode 100644 index 9bf2cf6cc..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Fill/Gradient/Linear.php +++ /dev/null @@ -1,95 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image\Fill\Gradient; - -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Image\Fill\FillInterface; -use Imagine\Image\PointInterface; - -/** - * Linear gradient fill - */ -abstract class Linear implements FillInterface -{ - /** - * @var integer - */ - private $length; - - /** - * @var ColorInterface - */ - private $start; - - /** - * @var ColorInterface - */ - private $end; - - /** - * Constructs a linear gradient with overall gradient length, and start and - * end shades, which default to 0 and 255 accordingly - * - * @param integer $length - * @param ColorInterface $start - * @param ColorInterface $end - */ - final public function __construct($length, ColorInterface $start, ColorInterface $end) - { - $this->length = $length; - $this->start = $start; - $this->end = $end; - } - - /** - * {@inheritdoc} - */ - final public function getColor(PointInterface $position) - { - $l = $this->getDistance($position); - - if ($l >= $this->length) { - return $this->end; - } - - if ($l < 0) { - return $this->start; - } - - return $this->start->getPalette()->blend($this->start, $this->end, $l / $this->length); - } - - /** - * @return ColorInterface - */ - final public function getStart() - { - return $this->start; - } - - /** - * @return ColorInterface - */ - final public function getEnd() - { - return $this->end; - } - - /** - * Get the distance of the position relative to the beginning of the gradient - * - * @param PointInterface $position - * - * @return integer - */ - abstract protected function getDistance(PointInterface $position); -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Fill/Gradient/Vertical.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Fill/Gradient/Vertical.php deleted file mode 100644 index 9a26b7789..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Fill/Gradient/Vertical.php +++ /dev/null @@ -1,28 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image\Fill\Gradient; - -use Imagine\Image\PointInterface; - -/** - * Vertical gradient fill - */ -final class Vertical extends Linear -{ - /** - * {@inheritdoc} - */ - public function getDistance(PointInterface $position) - { - return $position->getY(); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/FontInterface.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/FontInterface.php deleted file mode 100644 index 59d4a265a..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/FontInterface.php +++ /dev/null @@ -1,51 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image; - -use Imagine\Image\Palette\Color\ColorInterface; - -/** - * The font interface - */ -interface FontInterface -{ - /** - * Gets the fontfile for current font - * - * @return string - */ - public function getFile(); - - /** - * Gets font's integer point size - * - * @return integer - */ - public function getSize(); - - /** - * Gets font's color - * - * @return ColorInterface - */ - public function getColor(); - - /** - * Gets BoxInterface of font size on the image based on string and angle - * - * @param string $string - * @param integer $angle - * - * @return BoxInterface - */ - public function box($string, $angle = 0); -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Histogram/Bucket.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Histogram/Bucket.php deleted file mode 100644 index 34dad5eed..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Histogram/Bucket.php +++ /dev/null @@ -1,56 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image\Histogram; - -/** - * Bucket histogram - */ -final class Bucket implements \Countable -{ - /** - * @var Range - */ - private $range; - - /** - * @var integer - */ - private $count; - - /** - * @param Range $range - * @param integer $count - */ - public function __construct(Range $range, $count = 0) - { - $this->range = $range; - $this->count = $count; - } - - /** - * @param integer $value - */ - public function add($value) - { - if ($this->range->contains($value)) { - $this->count++; - } - } - - /** - * @return integer The number of elements in the bucket. - */ - public function count() - { - return $this->count; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Histogram/Range.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Histogram/Range.php deleted file mode 100644 index 9dc9f9928..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Histogram/Range.php +++ /dev/null @@ -1,56 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image\Histogram; - -use Imagine\Exception\OutOfBoundsException; - -/** - * Range histogram - */ -final class Range -{ - /** - * @var integer - */ - private $start; - - /** - * @var integer - */ - private $end; - - /** - * @param integer $start - * @param integer $end - * - * @throws OutOfBoundsException - */ - public function __construct($start, $end) - { - if ($end <= $start) { - throw new OutOfBoundsException(sprintf('Range end cannot be bigger than start, %d %d given accordingly', $this->start, $this->end)); - } - - $this->start = $start; - $this->end = $end; - } - - /** - * @param integer $value - * - * @return Boolean - */ - public function contains($value) - { - return $value >= $this->start && $value < $this->end; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/ImageInterface.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/ImageInterface.php deleted file mode 100644 index 6cf1dd87d..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/ImageInterface.php +++ /dev/null @@ -1,173 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image; - -use Imagine\Draw\DrawerInterface; -use Imagine\Effects\EffectsInterface; -use Imagine\Image\Palette\PaletteInterface; -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Exception\RuntimeException; -use Imagine\Exception\OutOfBoundsException; - -/** - * The image interface - */ -interface ImageInterface extends ManipulatorInterface -{ - const RESOLUTION_PIXELSPERINCH = 'ppi'; - const RESOLUTION_PIXELSPERCENTIMETER = 'ppc'; - - const INTERLACE_NONE = 'none'; - const INTERLACE_LINE = 'line'; - const INTERLACE_PLANE = 'plane'; - const INTERLACE_PARTITION = 'partition'; - - const FILTER_UNDEFINED = 'undefined'; - const FILTER_POINT = 'point'; - const FILTER_BOX = 'box'; - const FILTER_TRIANGLE = 'triangle'; - const FILTER_HERMITE = 'hermite'; - const FILTER_HANNING = 'hanning'; - const FILTER_HAMMING = 'hamming'; - const FILTER_BLACKMAN = 'blackman'; - const FILTER_GAUSSIAN = 'gaussian'; - const FILTER_QUADRATIC = 'quadratic'; - const FILTER_CUBIC = 'cubic'; - const FILTER_CATROM = 'catrom'; - const FILTER_MITCHELL = 'mitchell'; - const FILTER_LANCZOS = 'lanczos'; - const FILTER_BESSEL = 'bessel'; - const FILTER_SINC = 'sinc'; - - /** - * Returns the image content as a binary string - * - * @param string $format - * @param array $options - * - * @throws RuntimeException - * - * @return string binary - */ - public function get($format, array $options = array()); - - /** - * Returns the image content as a PNG binary string - * - * @throws RuntimeException - * - * @return string binary - */ - public function __toString(); - - /** - * Instantiates and returns a DrawerInterface instance for image drawing - * - * @return DrawerInterface - */ - public function draw(); - - /** - * @return EffectsInterface - */ - public function effects(); - - /** - * Returns current image size - * - * @return BoxInterface - */ - public function getSize(); - - /** - * Transforms creates a grayscale mask from current image, returns a new - * image, while keeping the existing image unmodified - * - * @return ImageInterface - */ - public function mask(); - - /** - * Returns array of image colors as Imagine\Image\Palette\Color\ColorInterface instances - * - * @return array - */ - public function histogram(); - - /** - * Returns color at specified positions of current image - * - * @param PointInterface $point - * - * @throws RuntimeException - * - * @return ColorInterface - */ - public function getColorAt(PointInterface $point); - - /** - * Returns the image layers when applicable. - * - * @throws RuntimeException In case the layer can not be returned - * @throws OutOfBoundsException In case the index is not a valid value - * - * @return LayersInterface - */ - public function layers(); - - /** - * Enables or disables interlacing - * - * @param string $scheme - * - * @throws InvalidArgumentException When an unsupported Interface type is supplied - * - * @return ImageInterface - */ - public function interlace($scheme); - - /** - * Return the current color palette - * - * @return PaletteInterface - */ - public function palette(); - - /** - * Set a palette for the image. Useful to change colorspace. - * - * @param PaletteInterface $palette - * - * @return ImageInterface - * - * @throws RuntimeException - */ - public function usePalette(PaletteInterface $palette); - - /** - * Applies a color profile on the Image - * - * @param ProfileInterface $profile - * - * @return ImageInterface - * - * @throws RuntimeException - */ - public function profile(ProfileInterface $profile); - - /** - * Returns the Image's meta data - * - * @return Metadata\MetadataInterface - */ - public function metadata(); -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/ImagineInterface.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/ImagineInterface.php deleted file mode 100644 index b5c942c73..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/ImagineInterface.php +++ /dev/null @@ -1,83 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image; - -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Exception\InvalidArgumentException; -use Imagine\Exception\RuntimeException; - -/** - * The imagine interface - */ -interface ImagineInterface -{ - const VERSION = '0.7-dev'; - - /** - * Creates a new empty image with an optional background color - * - * @param BoxInterface $size - * @param ColorInterface $color - * - * @throws InvalidArgumentException - * @throws RuntimeException - * - * @return ImageInterface - */ - public function create(BoxInterface $size, ColorInterface $color = null); - - /** - * Opens an existing image from $path - * - * @param string $path - * - * @throws RuntimeException - * - * @return ImageInterface - */ - public function open($path); - - /** - * Loads an image from a binary $string - * - * @param string $string - * - * @throws RuntimeException - * - * @return ImageInterface - */ - public function load($string); - - /** - * Loads an image from a resource $resource - * - * @param resource $resource - * - * @throws RuntimeException - * - * @return ImageInterface - */ - public function read($resource); - - /** - * Constructs a font with specified $file, $size and $color - * - * The font size is to be specified in points (e.g. 10pt means 10) - * - * @param string $file - * @param integer $size - * @param ColorInterface $color - * - * @return FontInterface - */ - public function font($file, $size, ColorInterface $color); -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/LayersInterface.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/LayersInterface.php deleted file mode 100644 index 44df42369..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/LayersInterface.php +++ /dev/null @@ -1,107 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image; - -use Imagine\Exception\RuntimeException; -use Imagine\Exception\InvalidArgumentException; -use Imagine\Exception\OutOfBoundsException; - -/** - * The layers interface - */ -interface LayersInterface extends \Iterator, \Countable, \ArrayAccess -{ - /** - * Merge layers into the original objects - * - * @throws RuntimeException - */ - public function merge(); - - /** - * Animates layers - * - * @param string $format The output output format - * @param integer $delay The delay in milliseconds between two frames - * @param integer $loops The number of loops, 0 means infinite - * - * @return LayersInterface - * - * @throws InvalidArgumentException In case an invalid argument is provided - * @throws RuntimeException In case the driver fails to animate - */ - public function animate($format, $delay, $loops); - - /** - * Coalesce layers. Each layer in the sequence is the same size as the first and composited with the next layer in - * the sequence. - */ - public function coalesce(); - - /** - * Adds an image at the end of the layers stack - * - * @param ImageInterface $image - * - * @return LayersInterface - * - * @throws RuntimeException - */ - public function add(ImageInterface $image); - - /** - * Set an image at offset - * - * @param integer $offset - * @param ImageInterface $image - * - * @return LayersInterface - * - * @throws RuntimeException - * @throws InvalidArgumentException - * @throws OutOfBoundsException - */ - public function set($offset, ImageInterface $image); - - /** - * Removes the image at offset - * - * @param integer $offset - * - * @return LayersInterface - * - * @throws RuntimeException - * @throws InvalidArgumentException - */ - public function remove($offset); - - /** - * Returns the image at offset - * - * @param integer $offset - * - * @return ImageInterface - * - * @throws RuntimeException - * @throws InvalidArgumentException - */ - public function get($offset); - - /** - * Returns true if a layer at offset is preset - * - * @param integer $offset - * - * @return Boolean - */ - public function has($offset); -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/ManipulatorInterface.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/ManipulatorInterface.php deleted file mode 100644 index 392b90828..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/ManipulatorInterface.php +++ /dev/null @@ -1,181 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image; - -use Imagine\Exception\InvalidArgumentException; -use Imagine\Exception\OutOfBoundsException; -use Imagine\Exception\RuntimeException; -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Image\Fill\FillInterface; - -/** - * The manipulator interface - */ -interface ManipulatorInterface -{ - const THUMBNAIL_INSET = 'inset'; - const THUMBNAIL_OUTBOUND = 'outbound'; - - /** - * Copies current source image into a new ImageInterface instance - * - * @throws RuntimeException - * - * @return static - */ - public function copy(); - - /** - * Crops a specified box out of the source image (modifies the source image) - * Returns cropped self - * - * @param PointInterface $start - * @param BoxInterface $size - * - * @throws OutOfBoundsException - * @throws RuntimeException - * - * @return static - */ - public function crop(PointInterface $start, BoxInterface $size); - - /** - * Resizes current image and returns self - * - * @param BoxInterface $size - * @param string $filter - * - * @throws RuntimeException - * - * @return static - */ - public function resize(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED); - - /** - * Rotates an image at the given angle. - * Optional $background can be used to specify the fill color of the empty - * area of rotated image. - * - * @param integer $angle - * @param ColorInterface $background - * - * @throws RuntimeException - * - * @return static - */ - public function rotate($angle, ColorInterface $background = null); - - /** - * Pastes an image into a parent image - * Throws exceptions if image exceeds parent image borders or if paste - * operation fails - * - * Returns source image - * - * @param ImageInterface $image - * @param PointInterface $start - * - * @throws InvalidArgumentException - * @throws OutOfBoundsException - * @throws RuntimeException - * - * @return static - */ - public function paste(ImageInterface $image, PointInterface $start); - - /** - * Saves the image at a specified path, the target file extension is used - * to determine file format, only jpg, jpeg, gif, png, wbmp and xbm are - * supported - * - * @param string $path - * @param array $options - * - * @throws RuntimeException - * - * @return static - */ - public function save($path = null, array $options = array()); - - /** - * Outputs the image content - * - * @param string $format - * @param array $options - * - * @throws RuntimeException - * - * @return static - */ - public function show($format, array $options = array()); - - /** - * Flips current image using horizontal axis - * - * @throws RuntimeException - * - * @return static - */ - public function flipHorizontally(); - - /** - * Flips current image using vertical axis - * - * @throws RuntimeException - * - * @return static - */ - public function flipVertically(); - - /** - * Remove all profiles and comments - * - * @throws RuntimeException - * - * @return static - */ - public function strip(); - - /** - * Generates a thumbnail from a current image - * Returns it as a new image, doesn't modify the current image - * - * @param BoxInterface $size - * @param string $mode - * @param string $filter The filter to use for resizing, one of ImageInterface::FILTER_* - * - * @throws RuntimeException - * - * @return static - */ - public function thumbnail(BoxInterface $size, $mode = self::THUMBNAIL_INSET, $filter = ImageInterface::FILTER_UNDEFINED); - - /** - * Applies a given mask to current image's alpha channel - * - * @param ImageInterface $mask - * - * @return static - */ - public function applyMask(ImageInterface $mask); - - /** - * Fills image with provided filling, by replacing each pixel's color in - * the current image with corresponding color from FillInterface, and - * returns modified image - * - * @param FillInterface $fill - * - * @return static - */ - public function fill(FillInterface $fill); -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Metadata/AbstractMetadataReader.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Metadata/AbstractMetadataReader.php deleted file mode 100644 index a709655be..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Metadata/AbstractMetadataReader.php +++ /dev/null @@ -1,101 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image\Metadata; - -use Imagine\Exception\InvalidArgumentException; - -abstract class AbstractMetadataReader implements MetadataReaderInterface -{ - /** - * {@inheritdoc} - */ - public function readFile($file) - { - if (stream_is_local($file)) { - if (!is_file($file)) { - throw new InvalidArgumentException(sprintf('File %s does not exist.', $file)); - } - - return new MetadataBag(array_merge(array('filepath' => realpath($file), 'uri' => $file), $this->extractFromFile($file))); - } - - return new MetadataBag(array_merge(array('uri' => $file), $this->extractFromFile($file))); - } - - /** - * {@inheritdoc} - */ - public function readData($data) - { - return new MetadataBag($this->extractFromData($data)); - } - - /** - * {@inheritdoc} - */ - public function readStream($resource) - { - if (!is_resource($resource)) { - throw new InvalidArgumentException('Invalid resource provided.'); - } - - return new MetadataBag(array_merge($this->getStreamMetadata($resource), $this->extractFromStream($resource))); - } - - /** - * Gets the URI from a stream resource - * - * @param resource $resource - * - * @return string|null The URI f ava - */ - private function getStreamMetadata($resource) - { - $metadata = array(); - - if (false !== $data = @stream_get_meta_data($resource)) { - $metadata['uri'] = $data['uri']; - if (stream_is_local($resource)) { - $metadata['filepath'] = realpath($data['uri']); - } - } - - return $metadata; - } - - /** - * Extracts metadata from a file - * - * @param $file - * - * @return array An associative array of metadata - */ - abstract protected function extractFromFile($file); - - /** - * Extracts metadata from raw data - * - * @param $data - * - * @return array An associative array of metadata - */ - abstract protected function extractFromData($data); - - /** - * Extracts metadata from a stream - * - * @param $resource - * - * @return array An associative array of metadata - */ - abstract protected function extractFromStream($resource); -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Metadata/DefaultMetadataReader.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Metadata/DefaultMetadataReader.php deleted file mode 100644 index 349366e06..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Metadata/DefaultMetadataReader.php +++ /dev/null @@ -1,42 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image\Metadata; - -/** - * Default metadata reader - */ -class DefaultMetadataReader extends AbstractMetadataReader -{ - /** - * {@inheritdoc} - */ - protected function extractFromFile($file) - { - return array(); - } - - /** - * {@inheritdoc} - */ - protected function extractFromData($data) - { - return array(); - } - - /** - * {@inheritdoc} - */ - protected function extractFromStream($resource) - { - return array(); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Metadata/ExifMetadataReader.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Metadata/ExifMetadataReader.php deleted file mode 100644 index dd8e7d093..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Metadata/ExifMetadataReader.php +++ /dev/null @@ -1,114 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image\Metadata; - -use Imagine\Exception\InvalidArgumentException; -use Imagine\Exception\NotSupportedException; - -/** - * Metadata driven by Exif information - */ -class ExifMetadataReader extends AbstractMetadataReader -{ - public function __construct() - { - if (!self::isSupported()) { - throw new NotSupportedException('PHP exif extension is required to use the ExifMetadataReader'); - } - } - - public static function isSupported() - { - return function_exists('exif_read_data'); - } - - /** - * {@inheritdoc} - */ - protected function extractFromFile($file) - { - if (false === $data = @file_get_contents($file)) { - throw new InvalidArgumentException(sprintf('File %s is not readable.', $file)); - } - - return $this->doReadData($data); - } - - /** - * {@inheritdoc} - */ - protected function extractFromData($data) - { - return $this->doReadData($data); - } - - /** - * {@inheritdoc} - */ - protected function extractFromStream($resource) - { - if (0 < ftell($resource)) { - $metadata = stream_get_meta_data($resource); - if ($metadata['seekable']) { - rewind($resource); - } - } - - return $this->doReadData(stream_get_contents($resource)); - } - - /** - * Extracts metadata from raw data, merges with existing metadata - * - * @param string $data - * - * @return MetadataBag - */ - private function doReadData($data) - { - if (substr($data, 0, 2) === 'II') { - $mime = 'image/tiff'; - } else { - $mime = 'image/jpeg'; - } - - return $this->extract('data://' . $mime . ';base64,' . base64_encode($data)); - } - - /** - * Performs the exif data extraction given a path or data-URI representation. - * - * @param string $path The path to the file or the data-URI representation. - * - * @return MetadataBag - */ - private function extract($path) - { - if (false === $exifData = @exif_read_data($path, null, true, false)) { - return array(); - } - - $metadata = array(); - $sources = array('EXIF' => 'exif', 'IFD0' => 'ifd0'); - - foreach ($sources as $name => $prefix) { - if (!isset($exifData[$name])) { - continue; - } - foreach ($exifData[$name] as $prop => $value) { - $metadata[$prefix.'.'.$prop] = $value; - } - } - - return $metadata; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Metadata/MetadataBag.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Metadata/MetadataBag.php deleted file mode 100644 index b7e917a38..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Metadata/MetadataBag.php +++ /dev/null @@ -1,97 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image\Metadata; - -/** - * An interface for Image Metadata - */ -class MetadataBag implements \ArrayAccess, \IteratorAggregate, \Countable -{ - /** @var array */ - private $data; - - public function __construct(array $data = array()) - { - $this->data = $data; - } - - /** - * Returns the metadata key, default value if it does not exist - * - * @param string $key - * @param mixed|null $default - * - * @return mixed - */ - public function get($key, $default = null) - { - return array_key_exists($key, $this->data) ? $this->data[$key] : $default; - } - - /** - * {@inheritdoc} - */ - public function count() - { - return count($this->data); - } - - /** - * {@inheritdoc} - */ - public function getIterator() - { - return new \ArrayIterator($this->data); - } - - /** - * {@inheritdoc} - */ - public function offsetExists($offset) - { - return array_key_exists($offset, $this->data); - } - - /** - * {@inheritdoc} - */ - public function offsetSet($offset, $value) - { - $this->data[$offset] = $value; - } - - /** - * {@inheritdoc} - */ - public function offsetUnset($offset) - { - unset($this->data[$offset]); - } - - /** - * {@inheritdoc} - */ - public function offsetGet($offset) - { - return $this->get($offset); - } - - /** - * Returns metadata as an array - * - * @return array An associative array - */ - public function toArray() - { - return $this->data; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Metadata/MetadataReaderInterface.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Metadata/MetadataReaderInterface.php deleted file mode 100644 index 62fcc8817..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Metadata/MetadataReaderInterface.php +++ /dev/null @@ -1,48 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image\Metadata; - -use Imagine\Exception\InvalidArgumentException; - -interface MetadataReaderInterface -{ - /** - * Reads metadata from a file. - * - * @param $file The path to the file where to read metadata. - * - * @throws InvalidArgumentException In case the file does not exist. - * - * @return MetadataBag - */ - public function readFile($file); - - /** - * Reads metadata from a binary string. - * - * @param $data The binary string to read. - * - * @return MetadataBag - */ - public function readData($data); - - /** - * Reads metadata from a stream. - * - * @param $resource The stream to read. - * - * @throws InvalidArgumentException In case the resource is not valid. - * - * @return MetadataBag - */ - public function readStream($resource); -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/CMYK.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/CMYK.php deleted file mode 100644 index 2beecf28a..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/CMYK.php +++ /dev/null @@ -1,118 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image\Palette; - -use Imagine\Image\Palette\Color\CMYK as CMYKColor; -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Exception\RuntimeException; -use Imagine\Exception\InvalidArgumentException; -use Imagine\Image\Profile; -use Imagine\Image\ProfileInterface; - -class CMYK implements PaletteInterface -{ - private $parser; - private $profile; - private static $colors = array(); - - public function __construct() - { - $this->parser = new ColorParser(); - } - - /** - * {@inheritdoc} - */ - public function name() - { - return PaletteInterface::PALETTE_CMYK; - } - - /** - * {@inheritdoc} - */ - public function pixelDefinition() - { - return array( - ColorInterface::COLOR_CYAN, - ColorInterface::COLOR_MAGENTA, - ColorInterface::COLOR_YELLOW, - ColorInterface::COLOR_KEYLINE, - ); - } - - /** - * {@inheritdoc} - */ - public function supportsAlpha() - { - return false; - } - - /** - * {@inheritdoc} - */ - public function color($color, $alpha = null) - { - if (null !== $alpha) { - throw new InvalidArgumentException('CMYK palette does not support alpha'); - } - - $color = $this->parser->parseToCMYK($color); - $index = sprintf('cmyk(%d, %d, %d, %d)', $color[0], $color[1], $color[2], $color[3]); - - if (false === array_key_exists($index, self::$colors)) { - self::$colors[$index] = new CMYKColor($this, $color); - } - - return self::$colors[$index]; - } - - /** - * {@inheritdoc} - */ - public function blend(ColorInterface $color1, ColorInterface $color2, $amount) - { - if (!$color1 instanceof CMYKColor || ! $color2 instanceof CMYKColor) { - throw new RuntimeException('CMYK palette can only blend CMYK colors'); - } - - return $this->color(array( - min(100, $color1->getCyan() + $color2->getCyan() * $amount), - min(100, $color1->getMagenta() + $color2->getMagenta() * $amount), - min(100, $color1->getYellow() + $color2->getYellow() * $amount), - min(100, $color1->getKeyline() + $color2->getKeyline() * $amount), - )); - } - - /** - * {@inheritdoc} - */ - public function useProfile(ProfileInterface $profile) - { - $this->profile = $profile; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function profile() - { - if (!$this->profile) { - $this->profile = Profile::fromPath(__DIR__ . '/../../resources/Adobe/CMYK/USWebUncoated.icc'); - } - - return $this->profile; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/Color/CMYK.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/Color/CMYK.php deleted file mode 100644 index 316543355..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/Color/CMYK.php +++ /dev/null @@ -1,219 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image\Palette\Color; - -use Imagine\Image\Palette\CMYK as CMYKPalette; -use Imagine\Exception\RuntimeException; -use Imagine\Exception\InvalidArgumentException; - -final class CMYK implements ColorInterface -{ - /** - * @var integer - */ - private $c; - - /** - * @var integer - */ - private $m; - - /** - * @var integer - */ - private $y; - - /** - * @var integer - */ - private $k; - - /** - * - * @var CMYK - */ - private $palette; - - public function __construct(CMYKPalette $palette, array $color) - { - $this->palette = $palette; - $this->setColor($color); - } - - /** - * {@inheritdoc} - */ - public function getValue($component) - { - switch ($component) { - case ColorInterface::COLOR_CYAN: - return $this->getCyan(); - case ColorInterface::COLOR_MAGENTA: - return $this->getMagenta(); - case ColorInterface::COLOR_YELLOW: - return $this->getYellow(); - case ColorInterface::COLOR_KEYLINE: - return $this->getKeyline(); - default: - throw new InvalidArgumentException(sprintf('Color component %s is not valid', $component)); - } - } - - /** - * Returns Cyan value of the color - * - * @return integer - */ - public function getCyan() - { - return $this->c; - } - - /** - * Returns Magenta value of the color - * - * @return integer - */ - public function getMagenta() - { - return $this->m; - } - - /** - * Returns Yellow value of the color - * - * @return integer - */ - public function getYellow() - { - return $this->y; - } - - /** - * Returns Key value of the color - * - * @return integer - */ - public function getKeyline() - { - return $this->k; - } - - /** - * {@inheritdoc} - */ - public function getPalette() - { - return $this->palette; - } - - /** - * {@inheritdoc} - */ - public function getAlpha() - { - return null; - } - - /** - * {@inheritdoc} - */ - public function dissolve($alpha) - { - throw new RuntimeException('CMYK does not support dissolution'); - } - - /** - * {@inheritdoc} - */ - public function lighten($shade) - { - return $this->palette->color( - array( - $this->c, - $this->m, - $this->y, - max(0, $this->k - $shade), - ) - ); - } - - /** - * {@inheritdoc} - */ - public function darken($shade) - { - return $this->palette->color( - array( - $this->c, - $this->m, - $this->y, - min(100, $this->k + $shade), - ) - ); - } - - /** - * {@inheritdoc} - */ - public function grayscale() - { - $color = array( - $this->c * (1 - $this->k / 100) + $this->k, - $this->m * (1 - $this->k / 100) + $this->k, - $this->y * (1 - $this->k / 100) + $this->k, - ); - - $gray = min(100, round(0.299 * $color[0] + 0.587 * $color[1] + 0.114 * $color[2])); - - return $this->palette->color(array($gray, $gray, $gray, $this->k)); - } - - /** - * {@inheritdoc} - */ - public function isOpaque() - { - return true; - } - - /** - * Returns hex representation of the color - * - * @return string - */ - public function __toString() - { - return sprintf('cmyk(%d%%, %d%%, %d%%, %d%%)', $this->c, $this->m, $this->y, $this->k); - } - - /** - * Internal, Performs checks for color validity (an of array(C, M, Y, K)) - * - * @param array $color - * - * @throws InvalidArgumentException - */ - private function setColor(array $color) - { - if (count($color) !== 4) { - throw new InvalidArgumentException('Color argument must look like array(C, M, Y, K), where C, M, Y, K are the integer values between 0 and 255 for cyan, magenta, yellow and black color indexes accordingly'); - } - - $colors = array_values($color); - array_walk($colors, function ($color) { - return max(0, min(100, $color)); - }); - - list($this->c, $this->m, $this->y, $this->k) = $colors; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/Color/ColorInterface.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/Color/ColorInterface.php deleted file mode 100644 index 8784c4ed3..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/Color/ColorInterface.php +++ /dev/null @@ -1,95 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image\Palette\Color; - -use Imagine\Image\Palette\PaletteInterface; - -interface ColorInterface -{ - const COLOR_RED = 'red'; - const COLOR_GREEN = 'green'; - const COLOR_BLUE = 'blue'; - - const COLOR_CYAN = 'cyan'; - const COLOR_MAGENTA = 'magenta'; - const COLOR_YELLOW = 'yellow'; - const COLOR_KEYLINE = 'keyline'; - - const COLOR_GRAY = 'gray'; - - /** - * Return the value of one of the component. - * - * @param string $component One of the ColorInterface::COLOR_* component - * - * @return Integer - */ - public function getValue($component); - - /** - * Returns percentage of transparency of the color - * - * @return integer - */ - public function getAlpha(); - - /** - * Returns the palette attached to the current color - * - * @return PaletteInterface - */ - public function getPalette(); - - /** - * Returns a copy of current color, incrementing the alpha channel by the - * given amount - * - * @param integer $alpha - * - * @return ColorInterface - */ - public function dissolve($alpha); - - /** - * Returns a copy of the current color, lightened by the specified number - * of shades - * - * @param integer $shade - * - * @return ColorInterface - */ - public function lighten($shade); - - /** - * Returns a copy of the current color, darkened by the specified number of - * shades - * - * @param integer $shade - * - * @return ColorInterface - */ - public function darken($shade); - - /** - * Returns a gray related to the current color - * - * @return ColorInterface - */ - public function grayscale(); - - /** - * Checks if the current color is opaque - * - * @return Boolean - */ - public function isOpaque(); -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/Color/Gray.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/Color/Gray.php deleted file mode 100644 index c8096450f..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/Color/Gray.php +++ /dev/null @@ -1,164 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image\Palette\Color; - -use Imagine\Image\Palette\Grayscale; -use Imagine\Exception\InvalidArgumentException; - -final class Gray implements ColorInterface -{ - /** - * @var integer - */ - private $gray; - - /** - * @var integer - */ - private $alpha; - - /** - * - * @var Grayscale - */ - private $palette; - - public function __construct(Grayscale $palette, array $color, $alpha) - { - $this->palette = $palette; - $this->setColor($color); - $this->setAlpha($alpha); - } - - /** - * {@inheritdoc} - */ - public function getValue($component) - { - switch ($component) { - case ColorInterface::COLOR_GRAY: - return $this->getGray(); - default: - throw new InvalidArgumentException(sprintf('Color component %s is not valid', $component)); - } - } - - /** - * Returns Gray value of the color - * - * @return integer - */ - public function getGray() - { - return $this->gray; - } - - /** - * {@inheritdoc} - */ - public function getPalette() - { - return $this->palette; - } - - /** - * {@inheritdoc} - */ - public function getAlpha() - { - return $this->alpha; - } - - /** - * {@inheritdoc} - */ - public function dissolve($alpha) - { - return $this->palette->color( - array($this->gray), $this->alpha + $alpha - ); - } - - /** - * {@inheritdoc} - */ - public function lighten($shade) - { - return $this->palette->color(array(min(255, $this->gray + $shade)), $this->alpha); - } - - /** - * {@inheritdoc} - */ - public function darken($shade) - { - return $this->palette->color(array(max(0, $this->gray - $shade)), $this->alpha); - } - - /** - * {@inheritdoc} - */ - public function grayscale() - { - return $this; - } - - /** - * {@inheritdoc} - */ - public function isOpaque() - { - return 100 === $this->alpha; - } - - /** - * Returns hex representation of the color - * - * @return string - */ - public function __toString() - { - return sprintf('#%02x%02x%02x', $this->gray, $this->gray, $this->gray); - } - - /** - * Performs checks for validity of given alpha value and sets it - * - * @param integer $alpha - * - * @throws InvalidArgumentException - */ - private function setAlpha($alpha) - { - if (!is_int($alpha) || $alpha < 0 || $alpha > 100) { - throw new InvalidArgumentException(sprintf('Alpha must be an integer between 0 and 100, %s given', $alpha)); - } - - $this->alpha = $alpha; - } - - /** - * Performs checks for color validity (array of array(gray)) - * - * @param array $color - * - * @throws InvalidArgumentException - */ - private function setColor(array $color) - { - if (count($color) !== 1) { - throw new InvalidArgumentException('Color argument must look like array(gray), where gray is the integer value between 0 and 255 for the grayscale'); - } - - list($this->gray) = array_values($color); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/Color/RGB.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/Color/RGB.php deleted file mode 100644 index a0b4f0d01..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/Color/RGB.php +++ /dev/null @@ -1,214 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image\Palette\Color; - -use Imagine\Image\Palette\RGB as RGBPalette; -use Imagine\Exception\InvalidArgumentException; - -final class RGB implements ColorInterface -{ - /** - * @var integer - */ - private $r; - - /** - * @var integer - */ - private $g; - - /** - * @var integer - */ - private $b; - - /** - * @var integer - */ - private $alpha; - - /** - * - * @var RGBPalette - */ - private $palette; - - public function __construct(RGBPalette $palette, array $color, $alpha) - { - $this->palette = $palette; - $this->setColor($color); - $this->setAlpha($alpha); - } - - /** - * {@inheritdoc} - */ - public function getValue($component) - { - switch ($component) { - case ColorInterface::COLOR_RED: - return $this->getRed(); - case ColorInterface::COLOR_GREEN: - return $this->getGreen(); - case ColorInterface::COLOR_BLUE: - return $this->getBlue(); - default: - throw new InvalidArgumentException(sprintf('Color component %s is not valid', $component)); - } - } - - /** - * Returns RED value of the color - * - * @return integer - */ - public function getRed() - { - return $this->r; - } - - /** - * Returns GREEN value of the color - * - * @return integer - */ - public function getGreen() - { - return $this->g; - } - - /** - * Returns BLUE value of the color - * - * @return integer - */ - public function getBlue() - { - return $this->b; - } - - /** - * {@inheritdoc} - */ - public function getPalette() - { - return $this->palette; - } - - /** - * {@inheritdoc} - */ - public function getAlpha() - { - return $this->alpha; - } - - /** - * {@inheritdoc} - */ - public function dissolve($alpha) - { - return $this->palette->color(array($this->r, $this->g, $this->b), $this->alpha + $alpha); - } - - /** - * {@inheritdoc} - */ - public function lighten($shade) - { - return $this->palette->color( - array( - min(255, $this->r + $shade), - min(255, $this->g + $shade), - min(255, $this->b + $shade), - ), $this->alpha - ); - } - - /** - * {@inheritdoc} - */ - public function darken($shade) - { - return $this->palette->color( - array( - max(0, $this->r - $shade), - max(0, $this->g - $shade), - max(0, $this->b - $shade), - ), $this->alpha - ); - } - - /** - * {@inheritdoc} - */ - public function grayscale() - { - $gray = min(255, round(0.299 * $this->getRed() + 0.114 * $this->getBlue() + 0.587 * $this->getGreen())); - - return $this->palette->color(array($gray, $gray, $gray), $this->alpha); - } - - /** - * {@inheritdoc} - */ - public function isOpaque() - { - return 100 === $this->alpha; - } - - /** - * Returns hex representation of the color - * - * @return string - */ - public function __toString() - { - return sprintf('#%02x%02x%02x', $this->r, $this->g, $this->b); - } - - /** - * Internal - * - * Performs checks for validity of given alpha value and sets it - * - * @param integer $alpha - * - * @throws InvalidArgumentException - */ - private function setAlpha($alpha) - { - if (!is_int($alpha) || $alpha < 0 || $alpha > 100) { - throw new InvalidArgumentException(sprintf('Alpha must be an integer between 0 and 100, %s given', $alpha)); - } - - $this->alpha = $alpha; - } - - /** - * Internal - * - * Performs checks for color validity (array of array(R, G, B)) - * - * @param array $color - * - * @throws InvalidArgumentException - */ - private function setColor(array $color) - { - if (count($color) !== 3) { - throw new InvalidArgumentException('Color argument must look like array(R, G, B), where R, G, B are the integer values between 0 and 255 for red, green and blue color indexes accordingly'); - } - - list($this->r, $this->g, $this->b) = array_values($color); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/ColorParser.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/ColorParser.php deleted file mode 100644 index 35cf4e952..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/ColorParser.php +++ /dev/null @@ -1,153 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image\Palette; - -use Imagine\Exception\InvalidArgumentException; - -class ColorParser -{ - /** - * Parses a color to a RGB tuple - * - * @param string|array|integer $color - * - * @return array - * - * @throws InvalidArgumentException - */ - public function parseToRGB($color) - { - $color = $this->parse($color); - - if (4 === count($color)) { - $color = array( - 255 * (1 - $color[0] / 100) * (1 - $color[3] / 100), - 255 * (1 - $color[1] / 100) * (1 - $color[3] / 100), - 255 * (1 - $color[2] / 100) * (1 - $color[3] / 100), - ); - } - - return $color; - } - - /** - * Parses a color to a CMYK tuple - * - * @param string|array|integer $color - * - * @return array - * - * @throws InvalidArgumentException - */ - public function parseToCMYK($color) - { - $color = $this->parse($color); - - if (3 === count($color)) { - $r = $color[0] / 255; - $g = $color[1] / 255; - $b = $color[2] / 255; - - $k = 1 - max($r, $g, $b); - - $color = array( - 1 === $k ? 0 : round((1 - $r - $k) / (1- $k) * 100), - 1 === $k ? 0 : round((1 - $g - $k) / (1- $k) * 100), - 1 === $k ? 0 : round((1 - $b - $k) / (1- $k) * 100), - round($k * 100) - ); - } - - return $color; - } - - /** - * Parses a color to a grayscale value - * - * @param string|array|integer $color - * - * @return array - * - * @throws InvalidArgumentException - */ - public function parseToGrayscale($color) - { - if (is_array($color) && 1 === count($color)) { - return array_values($color); - } - - $color = array_unique($this->parse($color)); - - if (1 !== count($color)) { - throw new InvalidArgumentException('The provided color has different values of red, green and blue components. Grayscale colors must have the same values for these.'); - } - - return $color; - } - - /** - * Parses a color - * - * @param string|array|integer $color - * - * @return array - * - * @throws InvalidArgumentException - */ - private function parse($color) - { - if (!is_string($color) && !is_array($color) && !is_int($color)) { - throw new InvalidArgumentException(sprintf('Color must be specified as a hexadecimal string, array or integer, %s given', gettype($color))); - } - - if (is_array($color)) { - if (3 === count($color) || 4 === count($color)) { - return array_values($color); - } - throw new InvalidArgumentException('Color argument if array, must look like array(R, G, B), or array(C, M, Y, K) where R, G, B are the integer values between 0 and 255 for red, green and blue or cyan, magenta, yellow and black color indexes accordingly'); - } - - if (is_string($color)) { - if (0 === strpos($color, 'cmyk(')) { - $substrColor = substr($color, 5, strlen($color) - 6); - - $components = array_map(function ($component) { - return round(trim($component, ' %')); - }, explode(',', $substrColor)); - - if (count($components) !== 4) { - throw new InvalidArgumentException(sprintf('Unable to parse color %s', $color)); - } - - return $components; - } else { - $color = ltrim($color, '#'); - - if (strlen($color) !== 3 && strlen($color) !== 6) { - throw new InvalidArgumentException(sprintf('Color must be a hex value in regular (6 characters) or short (3 characters) notation, "%s" given', $color)); - } - - if (strlen($color) === 3) { - $color = $color[0] . $color[0] . $color[1] . $color[1] . $color[2] . $color[2]; - } - - $color = array_map('hexdec', str_split($color, 2)); - } - } - - if (is_int($color)) { - $color = array(255 & ($color >> 16), 255 & ($color >> 8), 255 & $color); - } - - return $color; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/Grayscale.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/Grayscale.php deleted file mode 100644 index 088b7909a..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/Grayscale.php +++ /dev/null @@ -1,123 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image\Palette; - -use Imagine\Image\Palette\Color\Gray as GrayColor; -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Image\ProfileInterface; -use Imagine\Image\Profile; -use Imagine\Exception\RuntimeException; - -class Grayscale implements PaletteInterface -{ - /** - * @var ColorParser - */ - private $parser; - - /** - * @var ProfileInterface - */ - private $profile; - - /** - * @var array - */ - protected static $colors = array(); - - public function __construct() - { - $this->parser = new ColorParser(); - } - - /** - * {@inheritdoc} - */ - public function name() - { - return PaletteInterface::PALETTE_GRAYSCALE; - } - - /** - * {@inheritdoc} - */ - public function pixelDefinition() - { - return array(ColorInterface::COLOR_GRAY); - } - - /** - * {@inheritdoc} - */ - public function supportsAlpha() - { - return true; - } - - /** - * {@inheritdoc} - */ - public function useProfile(ProfileInterface $profile) - { - $this->profile = $profile; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function profile() - { - if (!$this->profile) { - $this->profile = Profile::fromPath(__DIR__ . '/../../resources/colormanagement.org/ISOcoated_v2_grey1c_bas.ICC'); - } - - return $this->profile; - } - - /** - * {@inheritdoc} - */ - public function color($color, $alpha = null) - { - if (null === $alpha) { - $alpha = 0; - } - - $color = $this->parser->parseToGrayscale($color); - $index = sprintf('#%02x%02x%02x-%d', $color[0], $color[0], $color[0], $alpha); - - if (false === array_key_exists($index, static::$colors)) { - static::$colors[$index] = new GrayColor($this, $color, $alpha); - } - - return static::$colors[$index]; - } - - /** - * {@inheritdoc} - */ - public function blend(ColorInterface $color1, ColorInterface $color2, $amount) - { - if (!$color1 instanceof GrayColor || ! $color2 instanceof GrayColor) { - throw new RuntimeException('Grayscale palette can only blend Grayscale colors'); - } - - return $this->color( - array( - (int) min(255, min($color1->getGray(), $color2->getGray()) + round(abs($color2->getGray() - $color1->getGray()) * $amount)), - ), - (int) min(100, min($color1->getAlpha(), $color2->getAlpha()) + round(abs($color2->getAlpha() - $color1->getAlpha()) * $amount)) - ); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/PaletteInterface.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/PaletteInterface.php deleted file mode 100644 index 855c244c4..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/PaletteInterface.php +++ /dev/null @@ -1,87 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image\Palette; - -use Imagine\Image\ProfileInterface; -use Imagine\Image\Palette\Color\ColorInterface; - -interface PaletteInterface -{ - const PALETTE_GRAYSCALE = 'gray'; - const PALETTE_RGB = 'rgb'; - const PALETTE_CMYK = 'cmyk'; - - /** - * Returns a color given some values - * - * @param string|array|integer $color A color - * @param integer|null $alpha Set alpha to null to disable it - * - * @return ColorInterface - * - * @throws InvalidArgumentException In case you pass an alpha value to a - * Palette that does not support alpha - */ - public function color($color, $alpha = null); - - /** - * Blend two colors given an amount - * - * @param ColorInterface $color1 - * @param ColorInterface $color2 - * @param float $amount The amount of color2 in color1 - * - * @return ColorInterface - */ - public function blend(ColorInterface $color1, ColorInterface $color2, $amount); - - /** - * Attachs an ICC profile to this Palette. - * - * (A default profile is provided by default) - * - * @param ProfileInterface $profile - * - * @return PaletteInterface - */ - public function useProfile(ProfileInterface $profile); - - /** - * Returns the ICC profile attached to this Palette. - * - * @return ProfileInterface - */ - public function profile(); - - /** - * Returns the name of this Palette, one of PaletteInterface::PALETTE_* - * constants - * - * @return String - */ - public function name(); - - /** - * Returns an array containing ColorInterface::COLOR_* constants that - * define the structure of colors for a pixel. - * - * @return array - */ - public function pixelDefinition(); - - /** - * Tells if alpha channel is supported in this palette - * - * @return Boolean - */ - public function supportsAlpha(); -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/RGB.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/RGB.php deleted file mode 100644 index 0462ca4da..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Palette/RGB.php +++ /dev/null @@ -1,129 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image\Palette; - -use Imagine\Image\Palette\Color\RGB as RGBColor; -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Image\ProfileInterface; -use Imagine\Image\Profile; -use Imagine\Exception\RuntimeException; - -class RGB implements PaletteInterface -{ - /** - * @var ColorParser - */ - private $parser; - - /** - * @var ProfileInterface - */ - private $profile; - - /** - * @var array - */ - protected static $colors = array(); - - public function __construct() - { - $this->parser = new ColorParser(); - } - - /** - * {@inheritdoc} - */ - public function name() - { - return PaletteInterface::PALETTE_RGB; - } - - /** - * {@inheritdoc} - */ - public function pixelDefinition() - { - return array( - ColorInterface::COLOR_RED, - ColorInterface::COLOR_GREEN, - ColorInterface::COLOR_BLUE, - ); - } - - /** - * {@inheritdoc} - */ - public function supportsAlpha() - { - return true; - } - - /** - * {@inheritdoc} - */ - public function useProfile(ProfileInterface $profile) - { - $this->profile = $profile; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function profile() - { - if (!$this->profile) { - $this->profile = Profile::fromPath(__DIR__ . '/../../resources/color.org/sRGB_IEC61966-2-1_black_scaled.icc'); - } - - return $this->profile; - } - - /** - * {@inheritdoc} - */ - public function color($color, $alpha = null) - { - if (null === $alpha) { - $alpha = 100; - } - - $color = $this->parser->parseToRGB($color); - $index = sprintf('#%02x%02x%02x-%d', $color[0], $color[1], $color[2], $alpha); - - if (false === array_key_exists($index, static::$colors)) { - static::$colors[$index] = new RGBColor($this, $color, $alpha); - } - - return static::$colors[$index]; - } - - /** - * {@inheritdoc} - */ - public function blend(ColorInterface $color1, ColorInterface $color2, $amount) - { - if (!$color1 instanceof RGBColor || ! $color2 instanceof RGBColor) { - throw new RuntimeException('RGB palette can only blend RGB colors'); - } - - return $this->color( - array( - (int) min(255, min($color1->getRed(), $color2->getRed()) + round(abs($color2->getRed() - $color1->getRed()) * $amount)), - (int) min(255, min($color1->getGreen(), $color2->getGreen()) + round(abs($color2->getGreen() - $color1->getGreen()) * $amount)), - (int) min(255, min($color1->getBlue(), $color2->getBlue()) + round(abs($color2->getBlue() - $color1->getBlue()) * $amount)), - ), - (int) min(100, min($color1->getAlpha(), $color2->getAlpha()) + round(abs($color2->getAlpha() - $color1->getAlpha()) * $amount)) - ); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Point.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Point.php deleted file mode 100644 index abfc7c3a8..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Point.php +++ /dev/null @@ -1,88 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image; - -use Imagine\Exception\InvalidArgumentException; - -/** - * The point class - */ -final class Point implements PointInterface -{ - /** - * @var integer - */ - private $x; - - /** - * @var integer - */ - private $y; - - /** - * Constructs a point of coordinates - * - * @param integer $x - * @param integer $y - * - * @throws InvalidArgumentException - */ - public function __construct($x, $y) - { - if ($x < 0 || $y < 0) { - throw new InvalidArgumentException(sprintf('A coordinate cannot be positioned outside of a bounding box (x: %s, y: %s given)', $x, $y)); - } - - $this->x = $x; - $this->y = $y; - } - - /** - * {@inheritdoc} - */ - public function getX() - { - return $this->x; - } - - /** - * {@inheritdoc} - */ - public function getY() - { - return $this->y; - } - - /** - * {@inheritdoc} - */ - public function in(BoxInterface $box) - { - return $this->x < $box->getWidth() && $this->y < $box->getHeight(); - } - - /** - * {@inheritdoc} - */ - public function move($amount) - { - return new Point($this->x + $amount, $this->y + $amount); - } - - /** - * {@inheritdoc} - */ - public function __toString() - { - return sprintf('(%d, %d)', $this->x, $this->y); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Point/Center.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Point/Center.php deleted file mode 100644 index 0e60349e1..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Point/Center.php +++ /dev/null @@ -1,77 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image\Point; - -use Imagine\Image\BoxInterface; -use Imagine\Image\Point as OriginalPoint; -use Imagine\Image\PointInterface; - -/** - * Point center - */ -final class Center implements PointInterface -{ - /** - * @var BoxInterface - */ - private $box; - - /** - * Constructs coordinate with size instance, it needs to be relative to - * - * @param BoxInterface $box - */ - public function __construct(BoxInterface $box) - { - $this->box = $box; - } - - /** - * {@inheritdoc} - */ - public function getX() - { - return ceil($this->box->getWidth() / 2); - } - - /** - * {@inheritdoc} - */ - public function getY() - { - return ceil($this->box->getHeight() / 2); - } - - /** - * {@inheritdoc} - */ - public function in(BoxInterface $box) - { - return $this->getX() < $box->getWidth() && $this->getY() < $box->getHeight(); - } - - /** - * {@inheritdoc} - */ - public function move($amount) - { - return new OriginalPoint($this->getX() + $amount, $this->getY() + $amount); - } - - /** - * {@inheritdoc} - */ - public function __toString() - { - return sprintf('(%d, %d)', $this->getX(), $this->getY()); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/PointInterface.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/PointInterface.php deleted file mode 100644 index f35fa80da..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/PointInterface.php +++ /dev/null @@ -1,56 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image; - -/** - * The point interface - */ -interface PointInterface -{ - /** - * Gets points x coordinate - * - * @return integer - */ - public function getX(); - - /** - * Gets points y coordinate - * - * @return integer - */ - public function getY(); - - /** - * Checks if current coordinate is inside a given bo - * - * @param BoxInterface $box - * - * @return Boolean - */ - public function in(BoxInterface $box); - - /** - * Returns another point, moved by a given amount from current coordinates - * - * @param integer $amount - * @return ImageInterface - */ - public function move($amount); - - /** - * Gets a string representation for the current point - * - * @return string - */ - public function __toString(); -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Profile.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/Profile.php deleted file mode 100644 index fda5415a6..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/Profile.php +++ /dev/null @@ -1,60 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image; - -use Imagine\Exception\InvalidArgumentException; - -class Profile implements ProfileInterface -{ - private $data; - private $name; - - public function __construct($name, $data) - { - $this->name = $name; - $this->data = $data; - } - - /** - * {@inheritdoc} - */ - public function name() - { - return $this->name; - } - - /** - * {@inheritdoc} - */ - public function data() - { - return $this->data; - } - - /** - * Creates a profile from a path to a file - * - * @param String $path - * - * @return Profile - * - * @throws InvalidArgumentException In case the provided path is not valid - */ - public static function fromPath($path) - { - if (!file_exists($path) || !is_file($path) || !is_readable($path)) { - throw new InvalidArgumentException(sprintf('Path %s is an invalid profile file or is not readable', $path)); - } - - return new static(basename($path), file_get_contents($path)); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Image/ProfileInterface.php b/snappymail/v/0.0.0/app/libraries/Imagine/Image/ProfileInterface.php deleted file mode 100644 index b2caa9c9a..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Image/ProfileInterface.php +++ /dev/null @@ -1,29 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Image; - -interface ProfileInterface -{ - /** - * Returns the name of the profile - * - * @return String - */ - public function name(); - - /** - * Returns the profile data - * - * @return String - */ - public function data(); -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Imagick/Drawer.php b/snappymail/v/0.0.0/app/libraries/Imagine/Imagick/Drawer.php deleted file mode 100644 index 2f8636491..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Imagick/Drawer.php +++ /dev/null @@ -1,404 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Imagick; - -use Imagine\Draw\DrawerInterface; -use Imagine\Exception\InvalidArgumentException; -use Imagine\Exception\RuntimeException; -use Imagine\Image\AbstractFont; -use Imagine\Image\BoxInterface; -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Image\Point; -use Imagine\Image\PointInterface; - -/** - * Drawer implementation using the Imagick PHP extension - */ -final class Drawer implements DrawerInterface -{ - /** - * @var Imagick - */ - private $imagick; - - /** - * @param \Imagick $imagick - */ - public function __construct(\Imagick $imagick) - { - $this->imagick = $imagick; - } - - /** - * {@inheritdoc} - */ - public function arc(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $thickness = 1) - { - $x = $center->getX(); - $y = $center->getY(); - $width = $size->getWidth(); - $height = $size->getHeight(); - - try { - $pixel = $this->getColor($color); - $arc = new \ImagickDraw(); - - $arc->setStrokeColor($pixel); - $arc->setStrokeWidth(max(1, (int) $thickness)); - $arc->setFillColor('transparent'); - $arc->arc($x - $width / 2, $y - $height / 2, $x + $width / 2, $y + $height / 2, $start, $end); - - $this->imagick->drawImage($arc); - - $pixel->clear(); - $pixel->destroy(); - - $arc->clear(); - $arc->destroy(); - } catch (\ImagickException $e) { - throw new RuntimeException('Draw arc operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function chord(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1) - { - $x = $center->getX(); - $y = $center->getY(); - $width = $size->getWidth(); - $height = $size->getHeight(); - - try { - $pixel = $this->getColor($color); - $chord = new \ImagickDraw(); - - $chord->setStrokeColor($pixel); - $chord->setStrokeWidth(max(1, (int) $thickness)); - - if ($fill) { - $chord->setFillColor($pixel); - } else { - $this->line( - new Point(round($x + $width / 2 * cos(deg2rad($start))), round($y + $height / 2 * sin(deg2rad($start)))), - new Point(round($x + $width / 2 * cos(deg2rad($end))), round($y + $height / 2 * sin(deg2rad($end)))), - $color - ); - - $chord->setFillColor('transparent'); - } - - $chord->arc( - $x - $width / 2, - $y - $height / 2, - $x + $width / 2, - $y + $height / 2, - $start, - $end - ); - - $this->imagick->drawImage($chord); - - $pixel->clear(); - $pixel->destroy(); - - $chord->clear(); - $chord->destroy(); - } catch (\ImagickException $e) { - throw new RuntimeException('Draw chord operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function ellipse(PointInterface $center, BoxInterface $size, ColorInterface $color, $fill = false, $thickness = 1) - { - $width = $size->getWidth(); - $height = $size->getHeight(); - - try { - $pixel = $this->getColor($color); - $ellipse = new \ImagickDraw(); - - $ellipse->setStrokeColor($pixel); - $ellipse->setStrokeWidth(max(1, (int) $thickness)); - - if ($fill) { - $ellipse->setFillColor($pixel); - } else { - $ellipse->setFillColor('transparent'); - } - - $ellipse->ellipse( - $center->getX(), - $center->getY(), - $width / 2, - $height / 2, - 0, 360 - ); - - if (false === $this->imagick->drawImage($ellipse)) { - throw new RuntimeException('Ellipse operation failed'); - } - - $pixel->clear(); - $pixel->destroy(); - - $ellipse->clear(); - $ellipse->destroy(); - } catch (\ImagickException $e) { - throw new RuntimeException('Draw ellipse operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function line(PointInterface $start, PointInterface $end, ColorInterface $color, $thickness = 1) - { - try { - $pixel = $this->getColor($color); - $line = new \ImagickDraw(); - - $line->setStrokeColor($pixel); - $line->setStrokeWidth(max(1, (int) $thickness)); - $line->setFillColor($pixel); - $line->line( - $start->getX(), - $start->getY(), - $end->getX(), - $end->getY() - ); - - $this->imagick->drawImage($line); - - $pixel->clear(); - $pixel->destroy(); - - $line->clear(); - $line->destroy(); - } catch (\ImagickException $e) { - throw new RuntimeException('Draw line operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function pieSlice(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1) - { - $width = $size->getWidth(); - $height = $size->getHeight(); - - $x1 = round($center->getX() + $width / 2 * cos(deg2rad($start))); - $y1 = round($center->getY() + $height / 2 * sin(deg2rad($start))); - $x2 = round($center->getX() + $width / 2 * cos(deg2rad($end))); - $y2 = round($center->getY() + $height / 2 * sin(deg2rad($end))); - - if ($fill) { - $this->chord($center, $size, $start, $end, $color, true, $thickness); - $this->polygon( - array( - $center, - new Point($x1, $y1), - new Point($x2, $y2), - ), - $color, - true, - $thickness - ); - } else { - $this->arc($center, $size, $start, $end, $color, $thickness); - $this->line($center, new Point($x1, $y1), $color, $thickness); - $this->line($center, new Point($x2, $y2), $color, $thickness); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function dot(PointInterface $position, ColorInterface $color) - { - $x = $position->getX(); - $y = $position->getY(); - - try { - $pixel = $this->getColor($color); - $point = new \ImagickDraw(); - - $point->setFillColor($pixel); - $point->point($x, $y); - - $this->imagick->drawimage($point); - - $pixel->clear(); - $pixel->destroy(); - - $point->clear(); - $point->destroy(); - } catch (\ImagickException $e) { - throw new RuntimeException('Draw point operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function polygon(array $coordinates, ColorInterface $color, $fill = false, $thickness = 1) - { - if (count($coordinates) < 3) { - throw new InvalidArgumentException(sprintf('Polygon must consist of at least 3 coordinates, %d given', count($coordinates))); - } - - $points = array_map(function (PointInterface $p) { - return array('x' => $p->getX(), 'y' => $p->getY()); - }, $coordinates); - - try { - $pixel = $this->getColor($color); - $polygon = new \ImagickDraw(); - - $polygon->setStrokeColor($pixel); - $polygon->setStrokeWidth(max(1, (int) $thickness)); - - if ($fill) { - $polygon->setFillColor($pixel); - } else { - $polygon->setFillColor('transparent'); - } - - $polygon->polygon($points); - $this->imagick->drawImage($polygon); - - $pixel->clear(); - $pixel->destroy(); - - $polygon->clear(); - $polygon->destroy(); - } catch (\ImagickException $e) { - throw new RuntimeException('Draw polygon operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function text($string, AbstractFont $font, PointInterface $position, $angle = 0, $width = null) - { - try { - $pixel = $this->getColor($font->getColor()); - $text = new \ImagickDraw(); - - $text->setFont($font->getFile()); - /** - * @see http://www.php.net/manual/en/imagick.queryfontmetrics.php#101027 - * - * ensure font resolution is the same as GD's hard-coded 96 - */ - if (version_compare(phpversion("imagick"), "3.0.2", ">=")) { - $text->setResolution(96, 96); - $text->setFontSize($font->getSize()); - } else { - $text->setFontSize((int) ($font->getSize() * (96 / 72))); - } - $text->setFillColor($pixel); - $text->setTextAntialias(true); - - $info = $this->imagick->queryFontMetrics($text, $string); - $rad = deg2rad($angle); - $cos = cos($rad); - $sin = sin($rad); - - // round(0 * $cos - 0 * $sin) - $x1 = 0; - $x2 = round($info['characterWidth'] * $cos - $info['characterHeight'] * $sin); - // round(0 * $sin + 0 * $cos) - $y1 = 0; - $y2 = round($info['characterWidth'] * $sin + $info['characterHeight'] * $cos); - - $xdiff = 0 - min($x1, $x2); - $ydiff = 0 - min($y1, $y2); - - if ($width !== null) { - $string = $this->wrapText($string, $text, $angle, $width); - } - - $this->imagick->annotateImage( - $text, $position->getX() + $x1 + $xdiff, - $position->getY() + $y2 + $ydiff, $angle, $string - ); - - $pixel->clear(); - $pixel->destroy(); - - $text->clear(); - $text->destroy(); - } catch (\ImagickException $e) { - throw new RuntimeException('Draw text operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * Gets specifically formatted color string from ColorInterface instance - * - * @param ColorInterface $color - * - * @return string - */ - private function getColor(ColorInterface $color) - { - $pixel = new \ImagickPixel((string) $color); - $pixel->setColorValue(\Imagick::COLOR_ALPHA, $color->getAlpha() / 100); - - return $pixel; - } - - /** - * Internal - * - * Fits a string into box with given width - */ - private function wrapText($string, $text, $angle, $width) - { - $result = ''; - $words = explode(' ', $string); - foreach ($words as $word) { - $teststring = $result . ' ' . $word; - $testbox = $this->imagick->queryFontMetrics($text, $teststring, true); - if ($testbox['textWidth'] > $width) { - $result .= ($result == '' ? '' : "\n") . $word; - } else { - $result .= ($result == '' ? '' : ' ') . $word; - } - } - - return $result; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Imagick/Effects.php b/snappymail/v/0.0.0/app/libraries/Imagine/Imagick/Effects.php deleted file mode 100644 index debe32a60..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Imagick/Effects.php +++ /dev/null @@ -1,113 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Imagick; - -use Imagine\Effects\EffectsInterface; -use Imagine\Exception\RuntimeException; -use Imagine\Image\Palette\Color\ColorInterface; - -/** - * Effects implementation using the Imagick PHP extension - */ -class Effects implements EffectsInterface -{ - private $imagick; - - public function __construct(\Imagick $imagick) - { - $this->imagick = $imagick; - } - - /** - * {@inheritdoc} - */ - public function gamma($correction) - { - try { - $this->imagick->gammaImage($correction, \Imagick::CHANNEL_ALL); - } catch (\ImagickException $e) { - throw new RuntimeException('Failed to apply gamma correction to the image'); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function negative() - { - try { - $this->imagick->negateImage(false, \Imagick::CHANNEL_ALL); - } catch (\ImagickException $e) { - throw new RuntimeException('Failed to negate the image'); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function grayscale() - { - try { - $this->imagick->setImageType(\Imagick::IMGTYPE_GRAYSCALE); - } catch (\ImagickException $e) { - throw new RuntimeException('Failed to grayscale the image'); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function colorize(ColorInterface $color) - { - try { - $this->imagick->colorizeImage((string) $color, 1); - } catch (\ImagickException $e) { - throw new RuntimeException('Failed to colorize the image'); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function sharpen() - { - try { - $this->imagick->sharpenImage(2, 1); - } catch (\ImagickException $e) { - throw new RuntimeException('Failed to sharpen the image'); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function blur($sigma = 1) - { - try { - $this->imagick->gaussianBlurImage(0, $sigma); - } catch (\ImagickException $e) { - throw new RuntimeException('Failed to blur the image', $e->getCode(), $e); - } - - return $this; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Imagick/Font.php b/snappymail/v/0.0.0/app/libraries/Imagine/Imagick/Font.php deleted file mode 100644 index 3fc41dd2f..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Imagick/Font.php +++ /dev/null @@ -1,68 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Imagick; - -use Imagine\Image\AbstractFont; -use Imagine\Image\Box; -use Imagine\Image\Palette\Color\ColorInterface; - -/** - * Font implementation using the Imagick PHP extension - */ -final class Font extends AbstractFont -{ - /** - * @var \Imagick - */ - private $imagick; - - /** - * @param \Imagick $imagick - * @param string $file - * @param integer $size - * @param ColorInterface $color - */ - public function __construct(\Imagick $imagick, $file, $size, ColorInterface $color) - { - $this->imagick = $imagick; - - parent::__construct($file, $size, $color); - } - - /** - * {@inheritdoc} - */ - public function box($string, $angle = 0) - { - $text = new \ImagickDraw(); - - $text->setFont($this->file); - - /** - * @see http://www.php.net/manual/en/imagick.queryfontmetrics.php#101027 - * - * ensure font resolution is the same as GD's hard-coded 96 - */ - if (version_compare(phpversion("imagick"), "3.0.2", ">=")) { - $text->setResolution(96, 96); - $text->setFontSize($this->size); - } else { - $text->setFontSize((int) ($this->size * (96 / 72))); - } - - $info = $this->imagick->queryFontMetrics($text, $string); - - $box = new Box($info['textWidth'], $info['textHeight']); - - return $box; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Imagick/Image.php b/snappymail/v/0.0.0/app/libraries/Imagine/Imagick/Image.php deleted file mode 100644 index c94f605d5..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Imagick/Image.php +++ /dev/null @@ -1,880 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Imagick; - -use Imagine\Exception\OutOfBoundsException; -use Imagine\Exception\InvalidArgumentException; -use Imagine\Exception\RuntimeException; -use Imagine\Image\AbstractImage; -use Imagine\Image\Box; -use Imagine\Image\BoxInterface; -use Imagine\Image\Metadata\MetadataBag; -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Image\Fill\FillInterface; -use Imagine\Image\Fill\Gradient\Horizontal; -use Imagine\Image\Fill\Gradient\Linear; -use Imagine\Image\Point; -use Imagine\Image\PointInterface; -use Imagine\Image\ProfileInterface; -use Imagine\Image\ImageInterface; -use Imagine\Image\Palette\PaletteInterface; - -/** - * Image implementation using the Imagick PHP extension - */ -final class Image extends AbstractImage -{ - /** - * @var \Imagick - */ - private $imagick; - /** - * @var Layers - */ - private $layers; - /** - * @var PaletteInterface - */ - private $palette; - - /** - * @var Boolean - */ - private static $supportsColorspaceConversion; - - private static $colorspaceMapping = array( - PaletteInterface::PALETTE_CMYK => \Imagick::COLORSPACE_CMYK, - PaletteInterface::PALETTE_RGB => \Imagick::COLORSPACE_RGB, - PaletteInterface::PALETTE_GRAYSCALE => \Imagick::COLORSPACE_GRAY, - ); - - /** - * Constructs a new Image instance - * - * @param \Imagick $imagick - * @param PaletteInterface $palette - * @param MetadataBag $metadata - */ - public function __construct(\Imagick $imagick, PaletteInterface $palette, MetadataBag $metadata) - { - $this->metadata = $metadata; - $this->detectColorspaceConversionSupport(); - $this->imagick = $imagick; - if (static::$supportsColorspaceConversion) { - $this->setColorspace($palette); - } - $this->palette = $palette; - $this->layers = new Layers($this, $this->palette, $this->imagick); - } - - /** - * Destroys allocated imagick resources - */ - public function __destruct() - { - if ($this->imagick instanceof \Imagick) { - $this->imagick->clear(); - $this->imagick->destroy(); - } - } - - /** - * Returns the underlying \Imagick instance - * - * @return \Imagick - */ - public function getImagick() - { - return $this->imagick; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function copy() - { - try { - if (version_compare(phpversion("imagick"), "3.1.0b1", ">=") || defined("HHVM_VERSION")) { - $clone = clone $this->imagick; - } else { - $clone = $this->imagick->clone(); - } - } catch (\ImagickException $e) { - throw new RuntimeException('Copy operation failed', $e->getCode(), $e); - } - - return new self($clone, $this->palette, clone $this->metadata); - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function crop(PointInterface $start, BoxInterface $size) - { - if (!$start->in($this->getSize())) { - throw new OutOfBoundsException('Crop coordinates must start at minimum 0, 0 position from top left corner, crop height and width must be positive integers and must not exceed the current image borders'); - } - - try { - $this->imagick->cropImage($size->getWidth(), $size->getHeight(), $start->getX(), $start->getY()); - // Reset canvas for gif format - $this->imagick->setImagePage(0, 0, 0, 0); - } catch (\ImagickException $e) { - throw new RuntimeException('Crop operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function flipHorizontally() - { - try { - $this->imagick->flopImage(); - } catch (\ImagickException $e) { - throw new RuntimeException('Horizontal Flip operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function flipVertically() - { - try { - $this->imagick->flipImage(); - } catch (\ImagickException $e) { - throw new RuntimeException('Vertical flip operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function strip() - { - try { - try { - $this->profile($this->palette->profile()); - } catch (\Exception $e) { - // here we discard setting the profile as the previous incorporated profile - // is corrupted, let's now strip the image - } - $this->imagick->stripImage(); - } catch (\ImagickException $e) { - throw new RuntimeException('Strip operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function paste(ImageInterface $image, PointInterface $start) - { - if (!$image instanceof self) { - throw new InvalidArgumentException(sprintf('Imagick\Image can only paste() Imagick\Image instances, %s given', get_class($image))); - } - - if (!$this->getSize()->contains($image->getSize(), $start)) { - throw new OutOfBoundsException('Cannot paste image of the given size at the specified position, as it moves outside of the current image\'s box'); - } - - try { - $this->imagick->compositeImage($image->imagick, \Imagick::COMPOSITE_DEFAULT, $start->getX(), $start->getY()); - } catch (\ImagickException $e) { - throw new RuntimeException('Paste operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function resize(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED) - { - try { - $this->imagick->resizeImage($size->getWidth(), $size->getHeight(), $this->getFilter($filter), 1); - } catch (\ImagickException $e) { - throw new RuntimeException('Resize operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function rotate($angle, ColorInterface $background = null) - { - $color = $background ? $background : $this->palette->color('fff'); - - try { - $pixel = $this->getColor($color); - - $this->imagick->rotateimage($pixel, $angle); - - $pixel->clear(); - $pixel->destroy(); - } catch (\ImagickException $e) { - throw new RuntimeException('Rotate operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function save($path = null, array $options = array()) - { - $path = null === $path ? $this->imagick->getImageFilename() : $path; - if (null === $path) { - throw new RuntimeException('You can omit save path only if image has been open from a file'); - } - - try { - $this->prepareOutput($options, $path); - $this->imagick->writeImages($path, true); - } catch (\ImagickException $e) { - throw new RuntimeException('Save operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function show($format, array $options = array()) - { - header('Content-type: '.$this->getMimeType($format)); - echo $this->get($format, $options); - - return $this; - } - - /** - * {@inheritdoc} - */ - public function get($format, array $options = array()) - { - try { - $options['format'] = $format; - $this->prepareOutput($options); - } catch (\ImagickException $e) { - throw new RuntimeException('Get operation failed', $e->getCode(), $e); - } - - return $this->imagick->getImagesBlob(); - } - - /** - * {@inheritdoc} - */ - public function interlace($scheme) - { - static $supportedInterlaceSchemes = array( - ImageInterface::INTERLACE_NONE => \Imagick::INTERLACE_NO, - ImageInterface::INTERLACE_LINE => \Imagick::INTERLACE_LINE, - ImageInterface::INTERLACE_PLANE => \Imagick::INTERLACE_PLANE, - ImageInterface::INTERLACE_PARTITION => \Imagick::INTERLACE_PARTITION, - ); - - if (!array_key_exists($scheme, $supportedInterlaceSchemes)) { - throw new InvalidArgumentException('Unsupported interlace type'); - } - - $this->imagick->setInterlaceScheme($supportedInterlaceSchemes[$scheme]); - - return $this; - } - - /** - * @param array $options - * @param string $path - */ - private function prepareOutput(array $options, $path = null) - { - if (isset($options['format'])) { - $this->imagick->setImageFormat($options['format']); - } - - if (isset($options['animated']) && true === $options['animated']) { - $format = isset($options['format']) ? $options['format'] : 'gif'; - $delay = isset($options['animated.delay']) ? $options['animated.delay'] : null; - $loops = isset($options['animated.loops']) ? $options['animated.loops'] : 0; - - $options['flatten'] = false; - - $this->layers->animate($format, $delay, $loops); - } else { - $this->layers->merge(); - } - $this->applyImageOptions($this->imagick, $options, $path); - - // flatten only if image has multiple layers - if ((!isset($options['flatten']) || $options['flatten'] === true) && count($this->layers) > 1) { - $this->flatten(); - } - } - - /** - * {@inheritdoc} - */ - public function __toString() - { - return $this->get('png'); - } - - /** - * {@inheritdoc} - */ - public function draw() - { - return new Drawer($this->imagick); - } - - /** - * {@inheritdoc} - */ - public function effects() - { - return new Effects($this->imagick); - } - - /** - * {@inheritdoc} - */ - public function getSize() - { - try { - $i = $this->imagick->getIteratorIndex(); - $this->imagick->rewind(); - $width = $this->imagick->getImageWidth(); - $height = $this->imagick->getImageHeight(); - $this->imagick->setIteratorIndex($i); - } catch (\ImagickException $e) { - throw new RuntimeException('Could not get size', $e->getCode(), $e); - } - - return new Box($width, $height); - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function applyMask(ImageInterface $mask) - { - if (!$mask instanceof self) { - throw new InvalidArgumentException('Can only apply instances of Imagine\Imagick\Image as masks'); - } - - $size = $this->getSize(); - $maskSize = $mask->getSize(); - - if ($size != $maskSize) { - throw new InvalidArgumentException(sprintf('The given mask doesn\'t match current image\'s size, Current mask\'s dimensions are %s, while image\'s dimensions are %s', $maskSize, $size)); - } - - $mask = $mask->mask(); - $mask->imagick->negateImage(true); - - try { - // remove transparent areas of the original from the mask - $mask->imagick->compositeImage($this->imagick, \Imagick::COMPOSITE_DSTIN, 0, 0); - $this->imagick->compositeImage($mask->imagick, \Imagick::COMPOSITE_COPYOPACITY, 0, 0); - - $mask->imagick->clear(); - $mask->imagick->destroy(); - } catch (\ImagickException $e) { - throw new RuntimeException('Apply mask operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function mask() - { - $mask = $this->copy(); - - try { - $mask->imagick->modulateImage(100, 0, 100); - $mask->imagick->setImageMatte(false); - } catch (\ImagickException $e) { - throw new RuntimeException('Mask operation failed', $e->getCode(), $e); - } - - return $mask; - } - - /** - * {@inheritdoc} - * - * @return ImageInterface - */ - public function fill(FillInterface $fill) - { - try { - if ($this->isLinearOpaque($fill)) { - $this->applyFastLinear($fill); - } else { - $iterator = $this->imagick->getPixelIterator(); - - foreach ($iterator as $y => $pixels) { - foreach ($pixels as $x => $pixel) { - $color = $fill->getColor(new Point($x, $y)); - - $pixel->setColor((string) $color); - $pixel->setColorValue(\Imagick::COLOR_ALPHA, $color->getAlpha() / 100); - } - - $iterator->syncIterator(); - } - } - } catch (\ImagickException $e) { - throw new RuntimeException('Fill operation failed', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function histogram() - { - try { - $pixels = $this->imagick->getImageHistogram(); - } catch (\ImagickException $e) { - throw new RuntimeException('Error while fetching histogram', $e->getCode(), $e); - } - - $image = $this; - - return array_map(function (\ImagickPixel $pixel) use ($image) { - return $image->pixelToColor($pixel); - },$pixels); - } - - /** - * {@inheritdoc} - */ - public function getColorAt(PointInterface $point) - { - if (!$point->in($this->getSize())) { - throw new RuntimeException(sprintf('Error getting color at point [%s,%s]. The point must be inside the image of size [%s,%s]', $point->getX(), $point->getY(), $this->getSize()->getWidth(), $this->getSize()->getHeight())); - } - - try { - $pixel = $this->imagick->getImagePixelColor($point->getX(), $point->getY()); - } catch (\ImagickException $e) { - throw new RuntimeException('Error while getting image pixel color', $e->getCode(), $e); - } - - return $this->pixelToColor($pixel); - } - - /** - * Returns a color given a pixel, depending the Palette context - * - * Note : this method is public for PHP 5.3 compatibility - * - * @param \ImagickPixel $pixel - * - * @return ColorInterface - * - * @throws InvalidArgumentException In case a unknown color is requested - */ - public function pixelToColor(\ImagickPixel $pixel) - { - static $colorMapping = array( - ColorInterface::COLOR_RED => \Imagick::COLOR_RED, - ColorInterface::COLOR_GREEN => \Imagick::COLOR_GREEN, - ColorInterface::COLOR_BLUE => \Imagick::COLOR_BLUE, - ColorInterface::COLOR_CYAN => \Imagick::COLOR_CYAN, - ColorInterface::COLOR_MAGENTA => \Imagick::COLOR_MAGENTA, - ColorInterface::COLOR_YELLOW => \Imagick::COLOR_YELLOW, - ColorInterface::COLOR_KEYLINE => \Imagick::COLOR_BLACK, - // There is no gray component in \Imagick, let's use one of the RGB comp - ColorInterface::COLOR_GRAY => \Imagick::COLOR_RED, - ); - - $alpha = $this->palette->supportsAlpha() ? (int) round($pixel->getColorValue(\Imagick::COLOR_ALPHA) * 100) : null; - $palette = $this->palette(); - - return $this->palette->color(array_map(function ($color) use ($palette, $pixel, $colorMapping) { - if (!isset($colorMapping[$color])) { - throw new InvalidArgumentException(sprintf('Color %s is not mapped in Imagick', $color)); - } - $multiplier = 255; - if ($palette->name() === PaletteInterface::PALETTE_CMYK) { - $multiplier = 100; - } - - return $pixel->getColorValue($colorMapping[$color]) * $multiplier; - }, $this->palette->pixelDefinition()), $alpha); - } - - /** - * {@inheritdoc} - */ - public function layers() - { - return $this->layers; - } - - /** - * {@inheritdoc} - */ - public function usePalette(PaletteInterface $palette) - { - if (!isset(static::$colorspaceMapping[$palette->name()])) { - throw new InvalidArgumentException(sprintf('The palette %s is not supported by Imagick driver', $palette->name())); - } - - if ($this->palette->name() === $palette->name()) { - return $this; - } - - if (!static::$supportsColorspaceConversion) { - throw new RuntimeException('Your version of Imagick does not support colorspace conversions.'); - } - - try { - try { - $hasICCProfile = (Boolean) $this->imagick->getImageProfile('icc'); - } catch (\ImagickException $e) { - $hasICCProfile = false; - } - - if (!$hasICCProfile) { - $this->profile($this->palette->profile()); - } - - $this->profile($palette->profile()); - $this->setColorspace($palette); - } catch (\ImagickException $e) { - throw new RuntimeException('Failed to set colorspace', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function palette() - { - return $this->palette; - } - - /** - * {@inheritdoc} - */ - public function profile(ProfileInterface $profile) - { - try { - $this->imagick->profileImage('icc', $profile->data()); - } catch (\ImagickException $e) { - throw new RuntimeException(sprintf('Unable to add profile %s to image', $profile->name()), $e->getCode(), $e); - } - - return $this; - } - - /** - * Internal - * - * Flatten the image. - */ - private function flatten() - { - /** - * @see https://github.com/mkoppanen/imagick/issues/45 - */ - try { - if (method_exists($this->imagick, 'mergeImageLayers') && defined('Imagick::LAYERMETHOD_UNDEFINED')) { - $this->imagick = $this->imagick->mergeImageLayers(\Imagick::LAYERMETHOD_UNDEFINED); - } elseif (method_exists($this->imagick, 'flattenImages')) { - $this->imagick = $this->imagick->flattenImages(); - } - } catch (\ImagickException $e) { - throw new RuntimeException('Flatten operation failed', $e->getCode(), $e); - } - } - - /** - * Internal - * - * Applies options before save or output - * - * @param \Imagick $image - * @param array $options - * @param string $path - * - * @throws InvalidArgumentException - * @throws RuntimeException - */ - private function applyImageOptions(\Imagick $image, array $options, $path) - { - if (isset($options['format'])) { - $format = $options['format']; - } elseif ('' !== $extension = pathinfo($path, \PATHINFO_EXTENSION)) { - $format = $extension; - } else { - $format = pathinfo($image->getImageFilename(), \PATHINFO_EXTENSION); - } - - $format = strtolower($format); - - $options = $this->updateSaveOptions($options); - - if (isset($options['jpeg_quality']) && in_array($format, array('jpeg', 'jpg', 'pjpeg'))) { - $image->setImageCompressionQuality($options['jpeg_quality']); - } - - if ((isset($options['png_compression_level']) || isset($options['png_compression_filter'])) && $format === 'png') { - // first digit: compression level (default: 7) - if (isset($options['png_compression_level'])) { - if ($options['png_compression_level'] < 0 || $options['png_compression_level'] > 9) { - throw new InvalidArgumentException('png_compression_level option should be an integer from 0 to 9'); - } - $compression = $options['png_compression_level'] * 10; - } else { - $compression = 70; - } - - // second digit: compression filter (default: 5) - if (isset($options['png_compression_filter'])) { - if ($options['png_compression_filter'] < 0 || $options['png_compression_filter'] > 9) { - throw new InvalidArgumentException('png_compression_filter option should be an integer from 0 to 9'); - } - $compression += $options['png_compression_filter']; - } else { - $compression += 5; - } - - $image->setImageCompressionQuality($compression); - } - - if (isset($options['resolution-units']) && isset($options['resolution-x']) && isset($options['resolution-y'])) { - if ($options['resolution-units'] == ImageInterface::RESOLUTION_PIXELSPERCENTIMETER) { - $image->setImageUnits(\Imagick::RESOLUTION_PIXELSPERCENTIMETER); - } elseif ($options['resolution-units'] == ImageInterface::RESOLUTION_PIXELSPERINCH) { - $image->setImageUnits(\Imagick::RESOLUTION_PIXELSPERINCH); - } else { - throw new RuntimeException('Unsupported image unit format'); - } - - $filter = ImageInterface::FILTER_UNDEFINED; - if (!empty($options['resampling-filter'])) { - $filter = $options['resampling-filter']; - } - - $image->setImageResolution($options['resolution-x'], $options['resolution-y']); - $image->resampleImage($options['resolution-x'], $options['resolution-y'], $this->getFilter($filter), 0); - } - } - - /** - * Gets specifically formatted color string from Color instance - * - * @param ColorInterface $color - * - * @return \ImagickPixel - */ - private function getColor(ColorInterface $color) - { - $pixel = new \ImagickPixel((string) $color); - $pixel->setColorValue(\Imagick::COLOR_ALPHA, $color->getAlpha() / 100); - - return $pixel; - } - - /** - * Checks whether given $fill is linear and opaque - * - * @param FillInterface $fill - * - * @return Boolean - */ - private function isLinearOpaque(FillInterface $fill) - { - return $fill instanceof Linear && $fill->getStart()->isOpaque() && $fill->getEnd()->isOpaque(); - } - - /** - * Performs optimized gradient fill for non-opaque linear gradients - * - * @param Linear $fill - */ - private function applyFastLinear(Linear $fill) - { - $gradient = new \Imagick(); - $size = $this->getSize(); - $color = sprintf('gradient:%s-%s', (string) $fill->getStart(), (string) $fill->getEnd()); - - if ($fill instanceof Horizontal) { - $gradient->newPseudoImage($size->getHeight(), $size->getWidth(), $color); - $gradient->rotateImage(new \ImagickPixel(), 90); - } else { - $gradient->newPseudoImage($size->getWidth(), $size->getHeight(), $color); - } - - $this->imagick->compositeImage($gradient, \Imagick::COMPOSITE_OVER, 0, 0); - $gradient->clear(); - $gradient->destroy(); - } - - /** - * Internal - * - * Get the mime type based on format. - * - * @param string $format - * - * @return string mime-type - * - * @throws RuntimeException - */ - private function getMimeType($format) - { - static $mimeTypes = array( - 'jpeg' => 'image/jpeg', - 'jpg' => 'image/jpeg', - 'gif' => 'image/gif', - 'png' => 'image/png', - 'wbmp' => 'image/vnd.wap.wbmp', - 'xbm' => 'image/xbm', - ); - - if (!isset($mimeTypes[$format])) { - throw new RuntimeException(sprintf('Unsupported format given. Only %s are supported, %s given', implode(", ", array_keys($mimeTypes)), $format)); - } - - return $mimeTypes[$format]; - } - - /** - * Sets colorspace and image type, assigns the palette. - * - * @param PaletteInterface $palette - * - * @throws InvalidArgumentException - */ - private function setColorspace(PaletteInterface $palette) - { - static $typeMapping = array( - // We use Matte variants to preserve alpha - PaletteInterface::PALETTE_CMYK => \Imagick::IMGTYPE_TRUECOLORMATTE, - PaletteInterface::PALETTE_RGB => \Imagick::IMGTYPE_TRUECOLORMATTE, - PaletteInterface::PALETTE_GRAYSCALE => \Imagick::IMGTYPE_GRAYSCALEMATTE, - ); - - if (!isset(static::$colorspaceMapping[$palette->name()])) { - throw new InvalidArgumentException(sprintf('The palette %s is not supported by Imagick driver', $palette->name())); - } - - $this->imagick->setType($typeMapping[$palette->name()]); - $this->imagick->setColorspace(static::$colorspaceMapping[$palette->name()]); - $this->palette = $palette; - } - - /** - * Older imagemagick versions does not support colorspace conversions. - * Let's detect if it is supported. - * - * @return Boolean - */ - private function detectColorspaceConversionSupport() - { - if (null !== static::$supportsColorspaceConversion) { - return static::$supportsColorspaceConversion; - } - - return static::$supportsColorspaceConversion = method_exists('Imagick', 'setColorspace'); - } - - /** - * Returns the filter if it's supported. - * - * @param string $filter - * - * @return string - * - * @throws InvalidArgumentException If the filter is unsupported. - */ - private function getFilter($filter = ImageInterface::FILTER_UNDEFINED) - { - static $supportedFilters = array( - ImageInterface::FILTER_UNDEFINED => \Imagick::FILTER_UNDEFINED, - ImageInterface::FILTER_BESSEL => \Imagick::FILTER_BESSEL, - ImageInterface::FILTER_BLACKMAN => \Imagick::FILTER_BLACKMAN, - ImageInterface::FILTER_BOX => \Imagick::FILTER_BOX, - ImageInterface::FILTER_CATROM => \Imagick::FILTER_CATROM, - ImageInterface::FILTER_CUBIC => \Imagick::FILTER_CUBIC, - ImageInterface::FILTER_GAUSSIAN => \Imagick::FILTER_GAUSSIAN, - ImageInterface::FILTER_HANNING => \Imagick::FILTER_HANNING, - ImageInterface::FILTER_HAMMING => \Imagick::FILTER_HAMMING, - ImageInterface::FILTER_HERMITE => \Imagick::FILTER_HERMITE, - ImageInterface::FILTER_LANCZOS => \Imagick::FILTER_LANCZOS, - ImageInterface::FILTER_MITCHELL => \Imagick::FILTER_MITCHELL, - ImageInterface::FILTER_POINT => \Imagick::FILTER_POINT, - ImageInterface::FILTER_QUADRATIC => \Imagick::FILTER_QUADRATIC, - ImageInterface::FILTER_SINC => \Imagick::FILTER_SINC, - ImageInterface::FILTER_TRIANGLE => \Imagick::FILTER_TRIANGLE - ); - - if (!array_key_exists($filter, $supportedFilters)) { - throw new InvalidArgumentException(sprintf( - 'The resampling filter "%s" is not supported by Imagick driver.', - $filter - )); - } - - return $supportedFilters[$filter]; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Imagick/Imagine.php b/snappymail/v/0.0.0/app/libraries/Imagine/Imagick/Imagine.php deleted file mode 100644 index aa6e92646..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Imagick/Imagine.php +++ /dev/null @@ -1,176 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Imagick; - -use Imagine\Exception\NotSupportedException; -use Imagine\Image\AbstractImagine; -use Imagine\Image\BoxInterface; -use Imagine\Image\Metadata\MetadataBag; -use Imagine\Image\Palette\Color\ColorInterface; -use Imagine\Exception\InvalidArgumentException; -use Imagine\Exception\RuntimeException; -use Imagine\Image\Palette\CMYK; -use Imagine\Image\Palette\RGB; -use Imagine\Image\Palette\Grayscale; - -/** - * Imagine implementation using the Imagick PHP extension - */ -final class Imagine extends AbstractImagine -{ - /** - * @throws RuntimeException - */ - public function __construct() - { - if (!class_exists('Imagick')) { - throw new RuntimeException('Imagick not installed'); - } - - if (version_compare('6.2.9', $this->getVersion(new \Imagick())) > 0) { - throw new RuntimeException('ImageMagick version 6.2.9 or higher is required'); - } - } - - /** - * {@inheritdoc} - */ - public function open($path) - { - $path = $this->checkPath($path); - - try { - $imagick = new \Imagick($path); - $image = new Image($imagick, $this->createPalette($imagick), $this->getMetadataReader()->readFile($path)); - } catch (\Exception $e) { - throw new RuntimeException(sprintf('Unable to open image %s', $path), $e->getCode(), $e); - } - - return $image; - } - - /** - * {@inheritdoc} - */ - public function create(BoxInterface $size, ColorInterface $color = null) - { - $width = $size->getWidth(); - $height = $size->getHeight(); - - $palette = null !== $color ? $color->getPalette() : new RGB(); - $color = null !== $color ? $color : $palette->color('fff'); - - try { - $pixel = new \ImagickPixel((string) $color); - $pixel->setColorValue(\Imagick::COLOR_ALPHA, $color->getAlpha() / 100); - - $imagick = new \Imagick(); - $imagick->newImage($width, $height, $pixel); - $imagick->setImageMatte(true); - $imagick->setImageBackgroundColor($pixel); - - if (version_compare('6.3.1', $this->getVersion($imagick)) < 0) { - $imagick->setImageOpacity($pixel->getColorValue(\Imagick::COLOR_ALPHA)); - } - - $pixel->clear(); - $pixel->destroy(); - - return new Image($imagick, $palette, new MetadataBag()); - } catch (\ImagickException $e) { - throw new RuntimeException('Could not create empty image', $e->getCode(), $e); - } - } - - /** - * {@inheritdoc} - */ - public function load($string) - { - try { - $imagick = new \Imagick(); - - $imagick->readImageBlob($string); - $imagick->setImageMatte(true); - - return new Image($imagick, $this->createPalette($imagick), $this->getMetadataReader()->readData($string)); - } catch (\ImagickException $e) { - throw new RuntimeException('Could not load image from string', $e->getCode(), $e); - } - } - - /** - * {@inheritdoc} - */ - public function read($resource) - { - if (!is_resource($resource)) { - throw new InvalidArgumentException('Variable does not contain a stream resource'); - } - - try { - $imagick = new \Imagick(); - $imagick->readImageFile($resource); - } catch (\ImagickException $e) { - throw new RuntimeException('Could not read image from resource', $e->getCode(), $e); - } - - return new Image($imagick, $this->createPalette($imagick), $this->getMetadataReader()->readStream($resource)); - } - - /** - * {@inheritdoc} - */ - public function font($file, $size, ColorInterface $color) - { - return new Font(new \Imagick(), $file, $size, $color); - } - - /** - * Returns the palette corresponding to an \Imagick resource colorspace - * - * @param \Imagick $imagick - * - * @return CMYK|Grayscale|RGB - * - * @throws NotSupportedException - */ - private function createPalette(\Imagick $imagick) - { - switch ($imagick->getImageColorspace()) { - case \Imagick::COLORSPACE_RGB: - case \Imagick::COLORSPACE_SRGB: - return new RGB(); - case \Imagick::COLORSPACE_CMYK: - return new CMYK(); - case \Imagick::COLORSPACE_GRAY: - return new Grayscale(); - default: - throw new NotSupportedException('Only RGB and CMYK colorspace are currently supported'); - } - } - - /** - * Returns ImageMagick version - * - * @param \Imagick $imagick - * - * @return string - */ - private function getVersion(\Imagick $imagick) - { - $v = $imagick->getVersion(); - list($version) = sscanf($v['versionString'], 'ImageMagick %s %04d-%02d-%02d %s %s'); - - return $version; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/Imagine/Imagick/Layers.php b/snappymail/v/0.0.0/app/libraries/Imagine/Imagick/Layers.php deleted file mode 100644 index 7809447ad..000000000 --- a/snappymail/v/0.0.0/app/libraries/Imagine/Imagick/Layers.php +++ /dev/null @@ -1,271 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Imagine\Imagick; - -use Imagine\Image\AbstractLayers; -use Imagine\Image\Metadata\MetadataBag; -use Imagine\Exception\RuntimeException; -use Imagine\Exception\OutOfBoundsException; -use Imagine\Exception\InvalidArgumentException; -use Imagine\Image\Palette\PaletteInterface; - -class Layers extends AbstractLayers -{ - /** - * @var Image - */ - private $image; - /** - * @var \Imagick - */ - private $resource; - /** - * @var integer - */ - private $offset = 0; - /** - * @var array - */ - private $layers = array(); - - private $palette; - - public function __construct(Image $image, PaletteInterface $palette, \Imagick $resource) - { - $this->image = $image; - $this->resource = $resource; - $this->palette = $palette; - } - - /** - * {@inheritdoc} - */ - public function merge() - { - foreach ($this->layers as $offset => $image) { - try { - $this->resource->setIteratorIndex($offset); - $this->resource->setImage($image->getImagick()); - } catch (\ImagickException $e) { - throw new RuntimeException('Failed to substitute layer', $e->getCode(), $e); - } - } - } - - /** - * {@inheritdoc} - */ - public function animate($format, $delay, $loops) - { - if ('gif' !== strtolower($format)) { - throw new InvalidArgumentException('Animated picture is currently only supported on gif'); - } - - if (!is_int($loops) || $loops < 0) { - throw new InvalidArgumentException('Loops must be a positive integer.'); - } - - if (null !== $delay && (!is_int($delay) || $delay < 0)) { - throw new InvalidArgumentException('Delay must be either null or a positive integer.'); - } - - try { - foreach ($this as $offset => $layer) { - $this->resource->setIteratorIndex($offset); - $this->resource->setFormat($format); - - if (null !== $delay) { - $layer->getImagick()->setImageDelay($delay / 10); - $layer->getImagick()->setImageTicksPerSecond(100); - } - $layer->getImagick()->setImageIterations($loops); - - $this->resource->setImage($layer->getImagick()); - } - } catch (\ImagickException $e) { - throw new RuntimeException('Failed to animate layers', $e->getCode(), $e); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function coalesce() - { - try { - $coalescedResource = $this->resource->coalesceImages(); - } catch (\ImagickException $e) { - throw new RuntimeException('Failed to coalesce layers', $e->getCode(), $e); - } - - $count = $coalescedResource->getNumberImages(); - for ($offset = 0; $offset < $count; $offset++) { - try { - $coalescedResource->setIteratorIndex($offset); - $this->layers[$offset] = new Image($coalescedResource->getImage(), $this->palette, new MetadataBag()); - } catch (\ImagickException $e) { - throw new RuntimeException('Failed to retrieve layer', $e->getCode(), $e); - } - } - } - - /** - * {@inheritdoc} - */ - public function current() - { - return $this->extractAt($this->offset); - } - - /** - * Tries to extract layer at given offset - * - * @param integer $offset - * - * @return Image - * @throws RuntimeException - */ - private function extractAt($offset) - { - if (!isset($this->layers[$offset])) { - try { - $this->resource->setIteratorIndex($offset); - $this->layers[$offset] = new Image($this->resource->getImage(), $this->palette, new MetadataBag()); - } catch (\ImagickException $e) { - throw new RuntimeException(sprintf('Failed to extract layer %d', $offset), $e->getCode(), $e); - } - } - - return $this->layers[$offset]; - } - - /** - * {@inheritdoc} - */ - public function key() - { - return $this->offset; - } - - /** - * {@inheritdoc} - */ - public function next() - { - ++$this->offset; - } - - /** - * {@inheritdoc} - */ - public function rewind() - { - $this->offset = 0; - } - - /** - * {@inheritdoc} - */ - public function valid() - { - return $this->offset < count($this); - } - - /** - * {@inheritdoc} - */ - public function count() - { - try { - return $this->resource->getNumberImages(); - } catch (\ImagickException $e) { - throw new RuntimeException('Failed to count the number of layers', $e->getCode(), $e); - } - } - - /** - * {@inheritdoc} - */ - public function offsetExists($offset) - { - return is_int($offset) && $offset >= 0 && $offset < count($this); - } - - /** - * {@inheritdoc} - */ - public function offsetGet($offset) - { - return $this->extractAt($offset); - } - - /** - * {@inheritdoc} - */ - public function offsetSet($offset, $image) - { - if (!$image instanceof Image) { - throw new InvalidArgumentException('Only an Imagick Image can be used as layer'); - } - - if (null === $offset) { - $offset = count($this) - 1; - } else { - if (!is_int($offset)) { - throw new InvalidArgumentException('Invalid offset for layer, it must be an integer'); - } - - if (count($this) < $offset || 0 > $offset) { - throw new OutOfBoundsException(sprintf('Invalid offset for layer, it must be a value between 0 and %d, %d given', count($this), $offset)); - } - - if (isset($this[$offset])) { - unset($this[$offset]); - $offset = $offset - 1; - } - } - - $frame = $image->getImagick(); - - try { - if (count($this) > 0) { - $this->resource->setIteratorIndex($offset); - } - $this->resource->addImage($frame); - } catch (\ImagickException $e) { - throw new RuntimeException('Unable to set the layer', $e->getCode(), $e); - } - - $this->layers = array(); - } - - /** - * {@inheritdoc} - */ - public function offsetUnset($offset) - { - try { - $this->extractAt($offset); - } catch (RuntimeException $e) { - return; - } - - try { - $this->resource->setIteratorIndex($offset); - $this->resource->removeImage(); - } catch (\ImagickException $e) { - throw new RuntimeException('Unable to remove layer', $e->getCode(), $e); - } - } -} diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Base/DateTimeHelper.php b/snappymail/v/0.0.0/app/libraries/MailSo/Base/DateTimeHelper.php index 826b3bd26..ae34f5236 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Base/DateTimeHelper.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Base/DateTimeHelper.php @@ -43,7 +43,7 @@ abstract class DateTimeHelper } $sDateTime = \trim(\preg_replace('/ \([a-zA-Z0-9]+\)$/', '', $sDateTime)); - $oDateTime = \DateTime::createFromFormat('D, d M Y H:i:s O', $sDateTime, \MailSo\Base\DateTimeHelper::GetUtcTimeZoneObject()); + $oDateTime = \DateTime::createFromFormat(\DateTime::RFC2822, $sDateTime, static::GetUtcTimeZoneObject()); return $oDateTime ? $oDateTime->getTimestamp() : 0; } @@ -61,10 +61,10 @@ abstract class DateTimeHelper if (\preg_match('/^[a-z]{2,4}, /i', $sDateTime)) // RFC2822 ~ "Thu, 10 Jun 2010 08:58:33 -0700 (PDT)" { - return \MailSo\Base\DateTimeHelper::ParseRFC2822DateString($sDateTime); + return static::ParseRFC2822DateString($sDateTime); } - $oDateTime = \DateTime::createFromFormat('d-M-Y H:i:s O', $sDateTime, \MailSo\Base\DateTimeHelper::GetUtcTimeZoneObject()); + $oDateTime = \DateTime::createFromFormat('d-M-Y H:i:s O', $sDateTime, static::GetUtcTimeZoneObject()); return $oDateTime ? $oDateTime->getTimestamp() : 0; } @@ -79,7 +79,7 @@ abstract class DateTimeHelper return 0; } - $oDateTime = \DateTime::createFromFormat('Y-m-d H:i:s O', $sDateTime, \MailSo\Base\DateTimeHelper::GetUtcTimeZoneObject()); + $oDateTime = \DateTime::createFromFormat('Y-m-d H:i:s O', $sDateTime, static::GetUtcTimeZoneObject()); return $oDateTime ? $oDateTime->getTimestamp() : 0; } @@ -88,11 +88,16 @@ abstract class DateTimeHelper */ public static function TryToParseSpecEtagFormat(string $sDateTime) : int { - $sDateTime = \trim(\preg_replace('/ \([a-zA-Z0-9]+\)$/', '', \trim($sDateTime))); - $sDateTime = \trim(\preg_replace('/(:[\d]{2})\.[\d]{3}/', '$1', \trim($sDateTime))); - $sDateTime = \trim(\preg_replace('/(-[\d]{2})T([\d]{2}:)/', '$1 $2', \trim($sDateTime))); - $sDateTime = \trim(\preg_replace('/([\-+][\d]{2}):([\d]{2})$/', ' $1$2', \trim($sDateTime))); + $oDateTime = \DateTime::createFromFormat(\DateTime::RFC3339_EXTENDED, $sDateTime, static::GetUtcTimeZoneObject()); + if ($oDateTime) { + return $oDateTime->getTimestamp(); + } - return \MailSo\Base\DateTimeHelper::ParseDateStringType1($sDateTime); + $sDateTime = \preg_replace('/ \([a-zA-Z0-9]+\)$/', '', \trim($sDateTime)); + $sDateTime = \preg_replace('/(:[\d]{2})\.[\d]{3}/', '$1', \trim($sDateTime)); + $sDateTime = \preg_replace('/(-[\d]{2})T([\d]{2}:)/', '$1 $2', \trim($sDateTime)); + $sDateTime = \preg_replace('/([\-+][\d]{2}):([\d]{2})$/', ' $1$2', \trim($sDateTime)); + + return static::ParseDateStringType1($sDateTime); } } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Base/Utils.php b/snappymail/v/0.0.0/app/libraries/MailSo/Base/Utils.php index 9dc0fdb48..053a12f6b 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Base/Utils.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Base/Utils.php @@ -744,7 +744,6 @@ END; 'sql' => 'text/plain', 'cfg' => 'text/plain', 'conf' => 'text/plain', - 'asc' => 'text/plain', 'rtx' => 'text/richtext', 'vcard' => 'text/vcard', 'vcf' => 'text/vcard', @@ -759,6 +758,7 @@ END; 'hlp' => 'application/winhlp', 'wgt' => 'application/widget', 'chm' => 'application/vnd.ms-htmlhelp', + 'asc' => 'application/pgp-signature', 'p10' => 'application/pkcs10', 'p7c' => 'application/pkcs7-mime', 'p7m' => 'application/pkcs7-mime', @@ -770,11 +770,7 @@ END; 'pl' => 'text/perl', 'css' => 'text/css', 'asp' => 'text/asp', - 'php' => 'application/x-httpd-php', - 'php3' => 'application/x-httpd-php', - 'php4' => 'application/x-httpd-php', - 'php5' => 'application/x-httpd-php', - 'phtml' => 'application/x-httpd-php', + 'php' => 'application/x-php', // images 'png' => 'image/png', @@ -1826,26 +1822,13 @@ END; return !empty($sIp) && $sIp === \filter_var($sIp, FILTER_VALIDATE_IP); } - private static function idn() : \Net - { - static $oIdn = null; - if (null === $oIdn) - { - include_once dirname(__DIR__).'/Vendors/Net/IDNA2.php'; - $oIdn = new \Net_IDNA2; - $oIdn->setParams('utf8', true); - } - - return $oIdn; - } - public static function IdnToUtf8(string $sStr, bool $bLowerIfAscii = false) : string { if (0 < \strlen($sStr) && \preg_match('/(^|\.|@)xn--/i', $sStr)) { try { - $sStr = self::idn()->decode($sStr); + $sStr = \SnappyMail\IDN::anyToUtf8($sStr); } catch (\Throwable $oException) {} } @@ -1869,7 +1852,7 @@ END; { try { - $sDomain = self::idn()->encode($sDomain); + $sDomain = \SnappyMail\IDN::anyToAscii($sDomain); } catch (\Throwable $oException) {} } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Enumerations/MessageFlag.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Enumerations/MessageFlag.php index a539175aa..be19077ec 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Enumerations/MessageFlag.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Enumerations/MessageFlag.php @@ -18,10 +18,10 @@ namespace MailSo\Imap\Enumerations; */ abstract class MessageFlag { - const RECENT = '\Recent'; - const SEEN = '\Seen'; - const DELETED = '\Deleted'; - const FLAGGED = '\Flagged'; - const ANSWERED = '\Answered'; - const DRAFT = '\Draft'; + const RECENT = '\\Recent'; + const SEEN = '\\Seen'; + const DELETED = '\\Deleted'; + const FLAGGED = '\\Flagged'; + const ANSWERED = '\\Answered'; + const DRAFT = '\\Draft'; } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/InvalidResponseException.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/InvalidResponseException.php index fa9c82247..1a8b64086 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/InvalidResponseException.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/InvalidResponseException.php @@ -16,4 +16,4 @@ namespace MailSo\Imap\Exceptions; * @package Imap * @subpackage Exceptions */ -class InvalidResponseException extends \MailSo\Imap\Exceptions\ResponseException {} +class InvalidResponseException extends ResponseException {} diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/LoginBadCredentialsException.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/LoginBadCredentialsException.php index eb440089d..a8680c7ec 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/LoginBadCredentialsException.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/LoginBadCredentialsException.php @@ -16,4 +16,4 @@ namespace MailSo\Imap\Exceptions; * @package Imap * @subpackage Exceptions */ -class LoginBadCredentialsException extends \MailSo\Imap\Exceptions\LoginException {} \ No newline at end of file +class LoginBadCredentialsException extends LoginException {} diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/LoginBadMethodException.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/LoginBadMethodException.php index 358f06dc5..25b89768f 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/LoginBadMethodException.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/LoginBadMethodException.php @@ -16,4 +16,4 @@ namespace MailSo\Imap\Exceptions; * @package Imap * @subpackage Exceptions */ -class LoginBadMethodException extends \MailSo\Imap\Exceptions\LoginException {} \ No newline at end of file +class LoginBadMethodException extends LoginException {} diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/LoginException.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/LoginException.php index 4e5172a29..3c138d51a 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/LoginException.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/LoginException.php @@ -16,4 +16,4 @@ namespace MailSo\Imap\Exceptions; * @package Imap * @subpackage Exceptions */ -class LoginException extends \MailSo\Imap\Exceptions\NegativeResponseException {} +class LoginException extends NegativeResponseException {} diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/NegativeResponseException.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/NegativeResponseException.php index 43a277ece..14d8791b7 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/NegativeResponseException.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/NegativeResponseException.php @@ -16,7 +16,7 @@ namespace MailSo\Imap\Exceptions; * @package Imap * @subpackage Exceptions */ -class NegativeResponseException extends \MailSo\Imap\Exceptions\ResponseException +class NegativeResponseException extends ResponseException { public function getAlertFromStatus() : string diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/ResponseException.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/ResponseException.php index a6bb233f7..1eac5eaee 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/ResponseException.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Exceptions/ResponseException.php @@ -25,9 +25,11 @@ class ResponseException extends \MailSo\Imap\Exceptions\Exception public function __construct(?\MailSo\Imap\ResponseCollection $oResponses = null, string $sMessage = '', int $iCode = 0, ?\Throwable $oPrevious = null) { - parent::__construct($sMessage, $iCode, $oPrevious); - $this->oResponses = $oResponses; + if (!$sMessage && $response = $this->GetLastResponse()) { + $sMessage = $response->OptionalResponse[0] . ' ' . $response->HumanReadable; + } + parent::__construct($sMessage, $iCode, $oPrevious); } public function GetResponses() : ?\MailSo\Imap\ResponseCollection diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Folder.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Folder.php index 34f818594..0cd33b8d5 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Folder.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Folder.php @@ -116,12 +116,12 @@ class Folder public function IsSelectable() : bool { - return !\in_array('\noselect', $this->aFlagsLowerCase); + return !\in_array('\\noselect', $this->aFlagsLowerCase); } public function IsInbox() : bool { - return 'INBOX' === \strtoupper($this->sFullNameRaw) || \in_array('\inbox', $this->aFlagsLowerCase); + return 'INBOX' === \strtoupper($this->sFullNameRaw) || \in_array('\\inbox', $this->aFlagsLowerCase); } /** diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php index 9ea88e869..63af87e3d 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php @@ -158,63 +158,63 @@ class ImapClient extends \MailSo\Net\NetClient $sLogin = \MailSo\Base\Utils::IdnToAscii(\MailSo\Base\Utils::Trim($sLogin)); - $sPassword = $sPassword; - $this->sLogginedUser = $sLogin; +// $encrypted = !empty(\stream_get_meta_data($this->rConnect)['crypto']); + $type = $this->IsSupported('LOGINDISABLED') ? '' : 'LOGIN'; // RFC3501 6.2.3 + $types = [ +// 'SCRAM-SHA-256' => 1, // !$encrypted +// 'SCRAM-SHA-1' => 1, // !$encrypted + 'CRAM-MD5' => $bUseAuthCramMd5IfSupported, + 'PLAIN' => $bUseAuthPlainIfSupported, + 'LOGIN' => 1, + ]; + foreach ($types as $sasl_type => $active) { + if ($active && $this->IsSupported("AUTH={$sasl_type}") && \SnappyMail\SASL::isSupported($sasl_type)) { + $type = $sasl_type; + break; + } + } + + $SASL = \SnappyMail\SASL::factory($type); + $SASL->base64 = true; + try { - if ($bUseAuthCramMd5IfSupported && $this->IsSupported('AUTH=CRAM-MD5')) + if (0 === \strpos($type, 'SCRAM-SHA-')) { - $oContinuationResponse = $this->SendRequestGetResponse('AUTHENTICATE', array('CRAM-MD5'))->getLast(); - if ($oContinuationResponse && Enumerations\ResponseType::CONTINUATION === $oContinuationResponse->ResponseType) - { - $sTicket = $oContinuationResponse->ResponseList[1] ?? null; - if ($sTicket) - { - $sTicket = \base64_decode($sTicket); - $this->oLogger->Write('ticket: '.$sTicket); - - $sToken = \base64_encode($sLogin.' '.\hash_hmac('md5', $sTicket, $sPassword)); - - if ($this->oLogger) - { - $this->oLogger->AddSecret($sToken); - } - - $this->sendRaw($sToken, true, '*******'); - $this->getResponse(); - } - else - { - $this->writeLogException( - new Exceptions\LoginException, - \MailSo\Log\Enumerations\Type::NOTICE, true); - } - } - else - { - $this->writeLogException( - new Exceptions\LoginException, - \MailSo\Log\Enumerations\Type::NOTICE, true); + $sAuthzid = $this->getResponseValue($this->SendRequestGetResponse('AUTHENTICATE', array($type)), Enumerations\ResponseType::CONTINUATION); + $this->sendRaw($SASL->authenticate($sLogin, $sPassword/*, $sAuthzid*/)); + $sChallenge = $SASL->challenge($this->getResponseValue($this->getResponse(), Enumerations\ResponseType::CONTINUATION)); + if ($this->oLogger) { + $this->oLogger->AddSecret($sChallenge); } + $this->sendRaw($sChallenge, true, '*******'); + $sSignature = $this->getResponseValue($this->getResponse()); + $SASL->verify($sSignature); } - else if ($bUseAuthPlainIfSupported && $this->IsSupported('AUTH=PLAIN')) + else if ('CRAM-MD5' === $type) { - $sToken = \base64_encode("\0".$sLogin."\0".$sPassword); - if ($this->oLogger) - { - $this->oLogger->AddSecret($sToken); + $sChallenge = $this->getResponseValue($this->SendRequestGetResponse('AUTHENTICATE', array($type)), Enumerations\ResponseType::CONTINUATION); + $this->oLogger->Write('challenge: '.\base64_decode($sChallenge)); + $sAuth = $SASL->authenticate($sLogin, $sPassword, $sChallenge); + if ($this->oLogger) { + $this->oLogger->AddSecret($sAuth); } - - if ($this->IsSupported('AUTH=SASL-IR') && false) - { - $this->SendRequestGetResponse('AUTHENTICATE', array('PLAIN', $sToken)); + $this->sendRaw($sAuth, true, '*******'); + $this->getResponse(); + } + else if ('PLAIN' === $type) + { + $sAuth = $SASL->authenticate($sLogin, $sPassword); + if ($this->oLogger) { + $this->oLogger->AddSecret($sAuth); } - else - { + if ($this->IsSupported('SASL-IR')) { + $this->SendRequestGetResponse('AUTHENTICATE', array('PLAIN', $sAuth)); + } else { $this->SendRequestGetResponse('AUTHENTICATE', array('PLAIN')); - $this->sendRaw($sToken, true, '*******'); + $this->sendRaw($sAuth, true, '*******'); $this->getResponse(); } } @@ -231,12 +231,6 @@ class ImapClient extends \MailSo\Net\NetClient $this->EscapeString($sPassword) )); } -// else -// { -// $this->writeLogException( -// new Exceptions\LoginBadMethodException, -// \MailSo\Log\Enumerations\Type::NOTICE, true); -// } if (0 < \strlen($sProxyAuthUser)) { @@ -293,6 +287,13 @@ class ImapClient extends \MailSo\Net\NetClient } /** + * Test support for things like: + * IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY + * THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND + * URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED + * I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH + * LIST-STATUS BINARY MOVE SNIPPET=FUZZY PREVIEW=FUZZY STATUS=SIZE LITERAL+ NOTIFY SPECIAL-USE + * * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception */ @@ -596,6 +597,7 @@ class ImapClient extends \MailSo\Net\NetClient } /** + * See https://tools.ietf.org/html/rfc5256 * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception @@ -1008,6 +1010,23 @@ class ImapClient extends \MailSo\Net\NetClient return $this->getResponse(); } + private function getResponseValue(ResponseCollection $oResponseCollection, int $type = 0) : string + { + $oResponse = $oResponseCollection->getLast(); + if ($oResponse && (!$type || $type === $oResponse->ResponseType)) { + $sResult = $oResponse->ResponseList[1] ?? null; + if ($sResult) { + return $sResult; + } + $this->writeLogException( + new Exceptions\LoginException, + \MailSo\Log\Enumerations\Type::NOTICE, true); + } + $this->writeLogException( + new Exceptions\LoginException, + \MailSo\Log\Enumerations\Type::NOTICE, true); + } + public function GetLastResponse() : ResponseCollection { return $this->oLastResponse; diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ResponseCollection.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ResponseCollection.php index 43e46c489..a0aa4db52 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ResponseCollection.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ResponseCollection.php @@ -100,18 +100,26 @@ class ResponseCollection extends \MailSo\Base\Collection foreach ($this as $oResponse) { if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType && - $sStatus === $oResponse->StatusOrIndex && 5 === count($oResponse->ResponseList)) + $sStatus === $oResponse->StatusOrIndex && 5 <= count($oResponse->ResponseList)) { try { - $sFullNameRaw = $oResponse->ResponseList[4]; - if (\is_array($sFullNameRaw)) { - $sFullNameRaw = "[{$sFullNameRaw[0]}]"; - } - if (!\is_string($sFullNameRaw)) { - \error_log('ResponseCollection::getFoldersResult: invalid string ' . \var_export($sFullNameRaw, true)); - continue; + /** + * A bug in the parser converts folder names that start with '[' into arrays, + * and subfolders are in $oResponse->ResponseList[5+] + * https://github.com/the-djmaze/snappymail/issues/1 + * https://github.com/the-djmaze/snappymail/issues/70 + */ + $sFullNameRaw = \array_slice($oResponse->ResponseList, 4); + foreach ($sFullNameRaw as &$name) { + if (\is_array($name)) { + $name = "[{$name[0]}]"; + } else if (!\is_string($name)) { + $name = ''; + } } + $sFullNameRaw = \implode('', $sFullNameRaw); + $oFolder = new Folder($sFullNameRaw, $oResponse->ResponseList[3], $oResponse->ResponseList[2]); diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Folder.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Folder.php index 4c8864259..a86752760 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Folder.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Folder.php @@ -76,7 +76,7 @@ class Folder implements \JsonSerializable public static function NewNonExistenInstance(string $sFullNameRaw, string $sDelimiter) : self { return new self( - new \MailSo\Imap\Folder($sFullNameRaw, $sDelimiter, array('\NoSelect')), true, false); + new \MailSo\Imap\Folder($sFullNameRaw, $sDelimiter, array('\\Noselect')), true, false); } public function Name() : string @@ -188,43 +188,41 @@ class Folder implements \JsonSerializable public function GetFolderListType() : int { $aFlags = $this->oImapFolder->FlagsLowerCase(); - $iListType = \MailSo\Imap\Enumerations\FolderType::USER; switch (true) { - case \in_array('\inbox', $aFlags) || 'INBOX' === \strtoupper($this->FullNameRaw()): - $iListType = \MailSo\Imap\Enumerations\FolderType::INBOX; - break; - case \in_array('\sent', $aFlags): - case \in_array('\sentmail', $aFlags): - $iListType = \MailSo\Imap\Enumerations\FolderType::SENT; - break; - case \in_array('\drafts', $aFlags): - $iListType = \MailSo\Imap\Enumerations\FolderType::DRAFTS; - break; - case \in_array('\junk', $aFlags): - case \in_array('\spam', $aFlags): - $iListType = \MailSo\Imap\Enumerations\FolderType::JUNK; - break; - case \in_array('\trash', $aFlags): - case \in_array('\bin', $aFlags): - $iListType = \MailSo\Imap\Enumerations\FolderType::TRASH; - break; - case \in_array('\important', $aFlags): - $iListType = \MailSo\Imap\Enumerations\FolderType::IMPORTANT; - break; - case \in_array('\flagged', $aFlags): - case \in_array('\starred', $aFlags): - $iListType = \MailSo\Imap\Enumerations\FolderType::FLAGGED; - break; - case \in_array('\all', $aFlags): - case \in_array('\allmail', $aFlags): - case \in_array('\archive', $aFlags): - $iListType = \MailSo\Imap\Enumerations\FolderType::ALL; - break; + case \in_array('\\inbox', $aFlags) || 'INBOX' === \strtoupper($this->FullNameRaw()): + return \MailSo\Imap\Enumerations\FolderType::INBOX; + + case \in_array('\\sent', $aFlags): + case \in_array('\\sentmail', $aFlags): + return \MailSo\Imap\Enumerations\FolderType::SENT; + + case \in_array('\\drafts', $aFlags): + return \MailSo\Imap\Enumerations\FolderType::DRAFTS; + + case \in_array('\\junk', $aFlags): + case \in_array('\\spam', $aFlags): + return \MailSo\Imap\Enumerations\FolderType::JUNK; + + case \in_array('\\trash', $aFlags): + case \in_array('\\bin', $aFlags): + return \MailSo\Imap\Enumerations\FolderType::TRASH; + + case \in_array('\\important', $aFlags): + return \MailSo\Imap\Enumerations\FolderType::IMPORTANT; + + case \in_array('\\flagged', $aFlags): + case \in_array('\\starred', $aFlags): + return \MailSo\Imap\Enumerations\FolderType::FLAGGED; + + case \in_array('\\all', $aFlags): + case \in_array('\\allmail', $aFlags): + case \in_array('\\archive', $aFlags): + return \MailSo\Imap\Enumerations\FolderType::ALL; } - return $iListType; + return \MailSo\Imap\Enumerations\FolderType::USER; } public function jsonSerialize() diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/FolderCollection.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/FolderCollection.php index 8db19093f..a6e0a1044 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/FolderCollection.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/FolderCollection.php @@ -32,6 +32,11 @@ class FolderCollection extends \MailSo\Base\Collection */ public $IsThreadsSupported; + /** + * @var bool + */ + public $IsSortSupported; + /** * @var bool */ @@ -50,6 +55,7 @@ class FolderCollection extends \MailSo\Base\Collection $this->FoldersHash = ''; $this->SystemFolders = array(); $this->IsThreadsSupported = false; + $this->IsSortSupported = false; $this->Optimized = false; } @@ -239,6 +245,7 @@ class FolderCollection extends \MailSo\Base\Collection 'Namespace' => $this->GetNamespace(), 'FoldersHash' => $this->FoldersHash ?: '', 'IsThreadsSupported' => $this->IsThreadsSupported, + 'IsSortSupported' => $this->IsSortSupported, 'Optimized' => $this->Optimized, 'CountRec' => $this->CountRec(), 'SystemFolders' => isset($this->SystemFolders) && \is_array($this->SystemFolders) ? diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php index e7bad6d30..c32682293 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php @@ -153,6 +153,10 @@ class MailClient \MailSo\Mime\Enumerations\Header::AUTHENTICATION_RESULTS, \MailSo\Mime\Enumerations\Header::X_DKIM_AUTHENTICATION_RESULTS, \MailSo\Mime\Enumerations\Header::LIST_UNSUBSCRIBE, + // SPAM + \MailSo\Mime\Enumerations\Header::X_SPAM_STATUS, + \MailSo\Mime\Enumerations\Header::X_SPAMD_RESULT, + \MailSo\Mime\Enumerations\Header::X_BOGOSITY ), true); // // return \MailSo\Imap\Enumerations\FetchType::ENVELOPE; @@ -1473,8 +1477,47 @@ class MailClient * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception */ - public function GetUids(?\MailSo\Cache\CacheClient $oCacher, string $sSearch, string $sFilter, string $sFolderName, string $sFolderHash, bool $bUseSortIfSupported = false) : array + public function GetUids(?\MailSo\Cache\CacheClient $oCacher, string $sSearch, + string $sFilter, string $sFolderName, string $sFolderHash, + bool $bUseSortIfSupported = false, string $sSort = '') : array { + /* TODO: Validate $sSort + ARRIVAL + Internal date and time of the message. This differs from the + ON criteria in SEARCH, which uses just the internal date. + + CC + [IMAP] addr-mailbox of the first "cc" address. + + DATE + Sent date and time, as described in section 2.2. + + FROM + [IMAP] addr-mailbox of the first "From" address. + + REVERSE + Followed by another sort criterion, has the effect of that + criterion but in reverse (descending) order. + Note: REVERSE only reverses a single criterion, and does not + affect the implicit "sequence number" sort criterion if all + other criteria are identical. Consequently, a sort of + REVERSE SUBJECT is not the same as a reverse ordering of a + SUBJECT sort. This can be avoided by use of additional + criteria, e.g., SUBJECT DATE vs. REVERSE SUBJECT REVERSE + DATE. In general, however, it's better (and faster, if the + client has a "reverse current ordering" command) to reverse + the results in the client instead of issuing a new SORT. + + SIZE + Size of the message in octets. + + SUBJECT + Base subject text. + + TO + [IMAP] addr-mailbox of the first "To" address. + */ + $aResultUids = false; $bUidsFromCacher = false; $bUseCacheAfterSearch = true; @@ -1482,18 +1525,13 @@ class MailClient $sSerializedHash = ''; $sSerializedLog = ''; - $bUseSortIfSupported = $bUseSortIfSupported ? !!$this->oImapClient->IsSupported('SORT') : false; - - if (0 < \strlen($sSearch)) - { - $bUseSortIfSupported = false; - } + $bUseSortIfSupported = $bUseSortIfSupported && !\strlen($sSearch) && $this->oImapClient->IsSupported('SORT'); $sSearchCriterias = $this->getImapSearchCriterias($sSearch, $sFilter, 0, $bUseCacheAfterSearch); if ($bUseCacheAfterSearch && $oCacher && $oCacher->IsInited()) { $sSerializedHash = 'GetUids/'. - ($bUseSortIfSupported ? 'S': 'N').'/'. + ($bUseSortIfSupported ? 'S' . $sSort : 'N').'/'. $this->GenerateImapClientHash().'/'. $sFolderName.'/'.$sSearchCriterias; @@ -1522,7 +1560,7 @@ class MailClient if (!\is_array($aResultUids)) { $aResultUids = $bUseSortIfSupported ? - $this->oImapClient->MessageSimpleSort(array('REVERSE DATE'), $sSearchCriterias, true) : + $this->oImapClient->MessageSimpleSort(array($sSort ?: 'REVERSE DATE'), $sSearchCriterias, true) : $this->oImapClient->MessageSimpleSearch($sSearchCriterias, true, \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? '' : 'UTF-8') ; @@ -1551,7 +1589,7 @@ class MailClient public function MessageList(string $sFolderName, int $iOffset = 0, int $iLimit = 10, string $sSearch = '', string $sPrevUidNext = '', ?\MailSo\Cache\CacheClient $oCacher = null, bool $bUseSortIfSupported = false, bool $bUseThreadSortIfSupported = false, - string $sThreadUid = '', string $sFilter = '') : MessageCollection + string $sThreadUid = '', string $sFilter = '', string $sSort = '') : MessageCollection { $sFilter = \trim($sFilter); $sSearch = \trim($sSearch); @@ -1584,7 +1622,7 @@ class MailClient $sUidNext = '0'; $sHighestModSeq = ''; - $bUseSortIfSupported = $bUseSortIfSupported ? $this->oImapClient->IsSupported('SORT') : false; + $bUseSortIfSupported = $bUseSortIfSupported && $this->oImapClient->IsSupported('SORT'); $bUseThreadSortIfSupported = $bUseThreadSortIfSupported ? ($this->oImapClient->IsSupported('THREAD=REFS') || $this->oImapClient->IsSupported('THREAD=REFERENCES') || $this->oImapClient->IsSupported('THREAD=ORDEREDSUBJECT')) : false; @@ -1630,7 +1668,7 @@ class MailClient if (0 < $iMessageRealCount && !$bMessageListOptimization) { $mAllSortedUids = $this->GetUids($oCacher, '', $sFilter, - $oMessageCollection->FolderName, $oMessageCollection->FolderHash, $bUseSortIfSupported); + $oMessageCollection->FolderName, $oMessageCollection->FolderHash, $bUseSortIfSupported, $sSort); $mAllThreads = $bUseThreadSortIfSupported ? $this->MessageListThreadsMap( $oMessageCollection->FolderName, $oMessageCollection->FolderHash, $mAllSortedUids, $oCacher) : null; @@ -2010,6 +2048,8 @@ class MailClient } $oFolderCollection->IsThreadsSupported = $this->IsThreadsSupported(); + + $oFolderCollection->IsSortSupported = $this->oImapClient->IsSupported('SORT'); } return $oFolderCollection; diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Message.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Message.php index f3f2b8fc4..a3c232b01 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Message.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Message.php @@ -17,60 +17,21 @@ namespace MailSo\Mail; */ class Message implements \JsonSerializable { - /** - * @var string - */ - private $sFolder; - - /** - * @var int - */ - private $iUid; - - /** - * @var string - */ - private $sSubject; - - /** - * @var string - */ - private $sMessageId; - - /** - * @var string - */ - private $sContentType; - - /** - * @var int - */ - private $iSize; - - /** - * @var int - */ - private $iInternalTimeStampInUTC; - - /** - * @var int - */ - private $iHeaderTimeStampInUTC; - - /** - * @var string - */ - private $sHeaderDate; - - /** - * @var array - */ - private $aFlags; - - /** - * @var array - */ - private $aFlagsLowerCase; + private + $sFolder = '', + $iUid = 0, + $sSubject = '', + $sMessageId = '', + $sContentType = '', + $iSize = 0, + $iSpamScore = 0, + $sSpamResult = '', + $bIsSpam = false, + $iInternalTimeStampInUTC = 0, + $iHeaderTimeStampInUTC = 0, + $sHeaderDate = '', + $aFlags = [], + $aFlagsLowerCase = []; /** * @var \MailSo\Mime\EmailCollection @@ -189,23 +150,6 @@ class Message implements \JsonSerializable function __construct() { - $this->Clear(); - } - - public function Clear() : self - { - $this->sFolder = ''; - $this->iUid = 0; - $this->sSubject = ''; - $this->sMessageId = ''; - $this->sContentType = ''; - $this->iSize = 0; - $this->iInternalTimeStampInUTC = 0; - $this->iHeaderTimeStampInUTC = 0; - $this->sHeaderDate = ''; - $this->aFlags = array(); - $this->aFlagsLowerCase = array(); - $this->oFrom = null; $this->oSender = null; $this->oReplyTo = null; @@ -300,6 +244,21 @@ class Message implements \JsonSerializable return $this->iSize; } + public function SpamScore() : int + { + return $this->iSpamScore; + } + + public function SpamResult() : string + { + return $this->sSpamResult; + } + + public function IsSpam() : bool + { + return $this->bIsSpam; + } + public function InternalTimeStampInUTC() : int { return $this->iInternalTimeStampInUTC; @@ -556,7 +515,7 @@ class Message implements \JsonSerializable $this->sReadReceipt = \trim($oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::X_CONFIRM_READING_TO)); } - //Unsubscribe links + // Unsubscribe links $this->aUnsubsribeLinks = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::LIST_UNSUBSCRIBE); if (empty($this->aUnsubsribeLinks)) { @@ -573,6 +532,32 @@ class Message implements \JsonSerializable ); } + if ($spam = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::X_SPAMD_RESULT)) { + if (\preg_match('/\\[([\\d\\.-]+)\\s*\\/\\s*([\\d\\.]+)\\];/', $spam, $match)) { + if ($threshold = \floatval($match[2])) { + $this->iSpamScore = \max(0, \min(100, 100 * \floatval($match[1]) / $threshold)); + $this->sSpamResult = "{$match[1]} / {$match[2]}"; + } + } + $this->bIsSpam = false !== \stripos($this->sSubject, '*** SPAM ***'); + } else if ($spam = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::X_BOGOSITY)) { + $this->sSpamResult = $spam; + $this->bIsSpam = !!\preg_match('/yes|spam/', $spam); + if (\preg_match('/spamicity=([\\d\\.]+)/', $spam, $spamicity)) { + $this->iSpamScore = \max(0, \min(100, \floatval($spamicity[1]))); + } + } else if ($spam = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::X_SPAM_STATUS)) { + if (\preg_match('/(?:hits|score)=([\\d\\.-]+)/', $spam, $value) + && \preg_match('/required=([\\d\\.-]+)/', $spam, $required)) { + if ($threshold = \floatval($required[1])) { + $this->iSpamScore = \max(0, \min(100, 100 * \floatval($value[1]) / $threshold)); + $this->sSpamResult = "{$value[1]} / {$required[1]}"; + } + } + $spam = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::X_SPAM_FLAG); + $this->bIsSpam = false !== \stripos($spam, 'YES'); + } + $sDraftInfo = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::X_DRAFT_INFO); if (0 < \strlen($sDraftInfo)) { $sType = ''; @@ -751,6 +736,9 @@ class Message implements \JsonSerializable 'Subject' => \trim(\MailSo\Base\Utils::Utf8Clear($this->Subject())), 'MessageId' => $this->MessageId(), 'Size' => $this->Size(), + 'SpamScore' => $this->SpamScore(), + 'SpamResult' => $this->SpamResult(), + 'IsSpam' => $this->IsSpam(), 'DateTimeStampInUTC' => $this->InternalTimeStampInUTC(), // \MailSo\Mime\EmailCollection diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Enumerations/Header.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Enumerations/Header.php index 5a23e41e9..deb090b8d 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Enumerations/Header.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mime/Enumerations/Header.php @@ -54,7 +54,22 @@ abstract class Header const DKIM_SIGNATURE = 'DKIM-Signature'; const DOMAINKEY_SIGNATURE = 'DomainKey-Signature'; - const X_SPAM_STATUS = 'X-Spam-Status'; + // SpamAssassin + const X_SPAM_FLAG = 'X-Spam-Flag'; // YES/NO + const X_SPAM_LEVEL = 'X-Spam-Level'; // ******* + const X_SPAM_STATUS = 'X-Spam-Status'; // Yes|No + // Rspamd + const X_SPAMD_RESULT = 'X-Spamd-Result'; // default: False [7.13 / 9.00]; + const X_SPAMD_BAR = 'X-Spamd-Bar'; // +++++++ + // Bogofilter + const X_BOGOSITY = 'X-Bogosity'; + // Unknown + const X_SPAM_CATEGORY = 'X-Spam-Category'; // SPAM|LEGIT + const X_SPAM_SCORE = 'X-Spam-Score'; // 0 + const X_HAM_REPORT = 'X-Ham-Report'; + const X_MICROSOFT_ANTISPAM = 'x-microsoft-antispam:'; + + const X_VIRUS = 'X-Virus'; const RETURN_RECEIPT_TO = 'Return-Receipt-To'; const DISPOSITION_NOTIFICATION_TO = 'Disposition-Notification-To'; diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Net/NetClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Net/NetClient.php index 6187e1732..ec34e5232 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Net/NetClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Net/NetClient.php @@ -283,6 +283,8 @@ abstract class NetClient { switch (true) { + case defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT') && OPENSSL_VERSION_NUMBER >= 0x10101000 && + \stream_socket_enable_crypto($this->rConnect, true, STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT): case defined('STREAM_CRYPTO_METHOD_ANY_CLIENT') && \stream_socket_enable_crypto($this->rConnect, true, STREAM_CRYPTO_METHOD_ANY_CLIENT): case defined('STREAM_CRYPTO_METHOD_TLS_CLIENT') && diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Sieve/ManageSieveClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Sieve/ManageSieveClient.php index 69752b485..aefaededa 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Sieve/ManageSieveClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Sieve/ManageSieveClient.php @@ -120,12 +120,31 @@ class ManageSieveClient extends \MailSo\Net\NetClient if ($this->IsSupported('SASL')) { +// $encrypted = !empty(\stream_get_meta_data($this->rConnect)['crypto']); + $type = ''; + $types = [ +// 'SCRAM-SHA-256' => 1, // !$encrypted +// 'SCRAM-SHA-1' => 1, // !$encrypted +// 'CRAM-MD5' => 1, // $encrypted + 'PLAIN' => 1, // $encrypted + 'LOGIN' => 1 // $encrypted + ]; + foreach ($types as $sasl_type => $active) { + if ($active && $this->IsAuthSupported($sasl_type) && \SnappyMail\SASL::isSupported($sasl_type)) { + $type = $sasl_type; + break; + } + } + + $SASL = \SnappyMail\SASL::factory($type); + $SASL->base64 = true; + $bAuth = false; try { - if ($this->IsAuthSupported('PLAIN')) + if ('PLAIN' === $type) { - $sAuth = \base64_encode($sLoginAuthKey."\0".$sLogin."\0".$sPassword); + $sAuth = $SASL->authenticate($sLogin, $sPassword, $sLoginAuthKey); if ($this->__USE_INITIAL_AUTH_PLAIN_COMMAND) { @@ -142,10 +161,10 @@ class ManageSieveClient extends \MailSo\Net\NetClient $this->parseStartupResponse($aResponse); $bAuth = true; } - else if ($this->IsAuthSupported('LOGIN')) + else if ('LOGIN' === $type) { - $sLogin = \base64_encode($sLogin); - $sPassword = \base64_encode($sPassword); + $sLogin = $SASL->authenticate($sLogin, $sPassword); + $sPassword = $SASL->challenge(''); $this->sendRequest('AUTHENTICATE "LOGIN"'); $this->sendRequest('{'.\strlen($sLogin).'+}'); diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php index 96974594b..bd0eb34e7 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php @@ -62,11 +62,6 @@ class SmtpClient extends \MailSo\Net\NetClient */ private $aResults; - /** - * @var bool - */ - public $__USE_SINGLE_LINE_AUTH_PLAIN_COMMAND = false; - function __construct() { parent::__construct(); @@ -150,126 +145,95 @@ class SmtpClient extends \MailSo\Net\NetClient { $sLogin = \MailSo\Base\Utils::IdnToAscii(\MailSo\Base\Utils::Trim($sLogin)); - if ($bUseAuthCramMd5IfSupported && $this->IsAuthSupported('CRAM-MD5')) - { - try - { - $this->sendRequestWithCheck('AUTH', 334, 'CRAM-MD5'); - } - catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) - { - $this->writeLogException( - new \MailSo\Smtp\Exceptions\LoginBadMethodException( - $oException->GetResponses(), $oException->getMessage(), 0, $oException), - \MailSo\Log\Enumerations\Type::NOTICE, true); - } - - $sTicket = ''; - - $sContinuationResponse = !empty($this->aResults[0]) ? \trim($this->aResults[0]) : ''; - if ($sContinuationResponse && '334 ' === \substr($sContinuationResponse, 0, 4) && 0 < \strlen(\substr($sContinuationResponse, 4))) - { - $sTicket = \base64_decode(\substr($sContinuationResponse, 4)); - $this->writeLogWithCrlf('ticket: '.$sTicket); - } - - if (empty($sTicket)) - { - $this->writeLogException( - new \MailSo\Smtp\Exceptions\NegativeResponseException, - \MailSo\Log\Enumerations\Type::NOTICE, true - ); - } - - try - { - $this->sendRequestWithCheck(\base64_encode($sLogin.' '.\hash_hmac('md5', $sTicket, $sPassword)), 235, '', true); - } - catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) - { - $this->writeLogException( - new \MailSo\Smtp\Exceptions\LoginBadCredentialsException( - $oException->GetResponses(), $oException->getMessage(), 0, $oException), - \MailSo\Log\Enumerations\Type::NOTICE, true); +// $encrypted = !empty(\stream_get_meta_data($this->rConnect)['crypto']); + $type = ''; + $types = [ + 'SCRAM-SHA-256' => 1, // !$encrypted + 'SCRAM-SHA-1' => 1, // !$encrypted + 'CRAM-MD5' => $bUseAuthCramMd5IfSupported, + 'PLAIN' => $bUseAuthPlainIfSupported, + 'LOGIN' => 1 // $encrypted + ]; + foreach ($types as $sasl_type => $active) { + if ($active && $this->IsAuthSupported($sasl_type) && \SnappyMail\SASL::isSupported($sasl_type)) { + $type = $sasl_type; + break; } } - else if ($bUseAuthPlainIfSupported && $this->IsAuthSupported('PLAIN')) - { - if ($this->__USE_SINGLE_LINE_AUTH_PLAIN_COMMAND) - { - try - { - $this->sendRequestWithCheck('AUTH', 235, 'PLAIN '.\base64_encode("\0".$sLogin."\0".$sPassword), true); - } - catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) - { - $this->writeLogException( - new \MailSo\Smtp\Exceptions\LoginBadCredentialsException( - $oException->GetResponses(), $oException->getMessage(), 0, $oException), - \MailSo\Log\Enumerations\Type::NOTICE, true); - } - } - else - { - try - { - $this->sendRequestWithCheck('AUTH', 334, 'PLAIN'); - } - catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) - { - $this->writeLogException( - new \MailSo\Smtp\Exceptions\LoginBadMethodException( - $oException->GetResponses(), $oException->getMessage(), 0, $oException), - \MailSo\Log\Enumerations\Type::NOTICE, true); - } - try - { - $this->sendRequestWithCheck(\base64_encode("\0".$sLogin."\0".$sPassword), 235, '', true); - } - catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) - { - $this->writeLogException( - new \MailSo\Smtp\Exceptions\LoginBadCredentialsException( - $oException->GetResponses(), $oException->getMessage(), 0, $oException), - \MailSo\Log\Enumerations\Type::NOTICE, true); - } - } - } - else if ($this->IsAuthSupported('LOGIN')) - { - try - { - $this->sendRequestWithCheck('AUTH', 334, 'LOGIN'); - } - catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) - { - $this->writeLogException( - new \MailSo\Smtp\Exceptions\LoginBadMethodException( - $oException->GetResponses(), $oException->getMessage(), 0, $oException), - \MailSo\Log\Enumerations\Type::NOTICE, true); - } - - try - { - $this->sendRequestWithCheck(\base64_encode($sLogin), 334, ''); - $this->sendRequestWithCheck(\base64_encode($sPassword), 235, '', true); - } - catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) - { - $this->writeLogException( - new \MailSo\Smtp\Exceptions\LoginBadCredentialsException( - $oException->GetResponses(), $oException->getMessage(), 0, $oException), - \MailSo\Log\Enumerations\Type::NOTICE, true); - } - } - else - { + if (!$type) { + \trigger_error("SMTP {$this->sConnectedHost} no supported AUTH options. Disable login" . ($this->IsSupported('STARTTLS') ? ' or try with STARTTLS' : '')); $this->writeLogException( new \MailSo\Smtp\Exceptions\LoginBadMethodException, \MailSo\Log\Enumerations\Type::NOTICE, true); } + $SASL = \SnappyMail\SASL::factory($type); + $SASL->base64 = true; + + // Start authentication + try + { + $sResult = $this->sendRequestWithCheck('AUTH', 334, $type); + } + catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) + { + $this->writeLogException( + new \MailSo\Smtp\Exceptions\LoginBadMethodException( + $oException->GetResponses(), $oException->getMessage(), 0, $oException), + \MailSo\Log\Enumerations\Type::NOTICE, true); + } + + try + { + switch ($type) + { + // RFC 4616 + case 'PLAIN': + $this->sendRequestWithCheck($SASL->authenticate($sLogin, $sPassword), 235, '', true); + break; + + case 'LOGIN': + $sResult = $this->sendRequestWithCheck($SASL->authenticate($sLogin, $sPassword, $sResult), 334, ''); + $this->sendRequestWithCheck($SASL->challenge($sResult), 235, '', true); + break; + + // RFC 2195 + case 'CRAM-MD5': + if (empty($sResult)) { + $this->writeLogException( + new \MailSo\Smtp\Exceptions\NegativeResponseException, + \MailSo\Log\Enumerations\Type::NOTICE, true + ); + } + $this->sendRequestWithCheck($SASL->authenticate($sLogin, $sPassword, $sResult), 235, '', true); + break; + + // RFC 5802 + case 'SCRAM-SHA-1': + case 'SCRAM-SHA-256': + $sResult = $this->sendRequestWithCheck($SASL->authenticate($sLogin, $sPassword, $sResult), 234, ''); + $sResult = $this->sendRequestWithCheck($SASL->challenge($sResult), 235, '', true); + $SASL->verify($sResult); + break; + +/* + // https://developers.google.com/gmail/imap/xoauth2-protocol + case 'XOAUTH2': + throw new \Exception('Please use app passphrases: https://support.google.com/mail/answer/185833'); + break; +*/ + + } + } + catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException) + { + $this->writeLogException( + new \MailSo\Smtp\Exceptions\LoginBadCredentialsException( + $oException->GetResponses(), $oException->getMessage(), 0, $oException), + \MailSo\Log\Enumerations\Type::NOTICE, true); + } + return $this; } @@ -542,10 +506,11 @@ class SmtpClient extends \MailSo\Net\NetClient * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Smtp\Exceptions\Exception */ - private function sendRequestWithCheck(string $sCommand, $mExpectCode, string $sAddToCommand = '', bool $bSecureLog = false, string $sErrorPrefix = '') : void + private function sendRequestWithCheck(string $sCommand, $mExpectCode, string $sAddToCommand = '', bool $bSecureLog = false, string $sErrorPrefix = '') : string { $this->sendRequest($sCommand, $sAddToCommand, $bSecureLog); $this->validateResponse($mExpectCode, $sErrorPrefix); + return empty($this->aResults[0]) ? '' : \trim(\substr($this->aResults[0], 4)); } private function ehloOrHelo(string $sHost) : void diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Vendors/Net/IDNA2.php b/snappymail/v/0.0.0/app/libraries/MailSo/Vendors/Net/IDNA2.php deleted file mode 100644 index c0a985e79..000000000 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Vendors/Net/IDNA2.php +++ /dev/null @@ -1,3259 +0,0 @@ - - * @author Matthias Sommerfeld - * @author Stefan Neufeind - * @version $Id: IDNA2.php 305344 2010-11-14 23:52:42Z neufeind $ - */ -class Net_IDNA2 -{ - // {{{ npdata - /** - * These Unicode codepoints are - * mapped to nothing, See RFC3454 for details - * - * @var array - */ - private static $_np_map_nothing = array( - 0xAD, - 0x34F, - 0x1806, - 0x180B, - 0x180C, - 0x180D, - 0x200B, - 0x200C, - 0x200D, - 0x2060, - 0xFE00, - 0xFE01, - 0xFE02, - 0xFE03, - 0xFE04, - 0xFE05, - 0xFE06, - 0xFE07, - 0xFE08, - 0xFE09, - 0xFE0A, - 0xFE0B, - 0xFE0C, - 0xFE0D, - 0xFE0E, - 0xFE0F, - 0xFEFF - ); - - /** - * Prohibited codepints - * - * @var array - */ - private static $_general_prohibited = array( - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 0xA, - 0xB, - 0xC, - 0xD, - 0xE, - 0xF, - 0x10, - 0x11, - 0x12, - 0x13, - 0x14, - 0x15, - 0x16, - 0x17, - 0x18, - 0x19, - 0x1A, - 0x1B, - 0x1C, - 0x1D, - 0x1E, - 0x1F, - 0x20, - 0x21, - 0x22, - 0x23, - 0x24, - 0x25, - 0x26, - 0x27, - 0x28, - 0x29, - 0x2A, - 0x2B, - 0x2C, - 0x2F, - 0x3B, - 0x3C, - 0x3D, - 0x3E, - 0x3F, - 0x40, - 0x5B, - 0x5C, - 0x5D, - 0x5E, - 0x5F, - 0x60, - 0x7B, - 0x7C, - 0x7D, - 0x7E, - 0x7F, - 0x3002 - ); - - /** - * Codepints prohibited by Nameprep - * @var array - */ - private static $_np_prohibit = array( - 0xA0, - 0x1680, - 0x2000, - 0x2001, - 0x2002, - 0x2003, - 0x2004, - 0x2005, - 0x2006, - 0x2007, - 0x2008, - 0x2009, - 0x200A, - 0x200B, - 0x202F, - 0x205F, - 0x3000, - 0x6DD, - 0x70F, - 0x180E, - 0x200C, - 0x200D, - 0x2028, - 0x2029, - 0xFEFF, - 0xFFF9, - 0xFFFA, - 0xFFFB, - 0xFFFC, - 0xFFFE, - 0xFFFF, - 0x1FFFE, - 0x1FFFF, - 0x2FFFE, - 0x2FFFF, - 0x3FFFE, - 0x3FFFF, - 0x4FFFE, - 0x4FFFF, - 0x5FFFE, - 0x5FFFF, - 0x6FFFE, - 0x6FFFF, - 0x7FFFE, - 0x7FFFF, - 0x8FFFE, - 0x8FFFF, - 0x9FFFE, - 0x9FFFF, - 0xAFFFE, - 0xAFFFF, - 0xBFFFE, - 0xBFFFF, - 0xCFFFE, - 0xCFFFF, - 0xDFFFE, - 0xDFFFF, - 0xEFFFE, - 0xEFFFF, - 0xFFFFE, - 0xFFFFF, - 0x10FFFE, - 0x10FFFF, - 0xFFF9, - 0xFFFA, - 0xFFFB, - 0xFFFC, - 0xFFFD, - 0x340, - 0x341, - 0x200E, - 0x200F, - 0x202A, - 0x202B, - 0x202C, - 0x202D, - 0x202E, - 0x206A, - 0x206B, - 0x206C, - 0x206D, - 0x206E, - 0x206F, - 0xE0001 - ); - - /** - * Codepoint ranges prohibited by nameprep - * - * @var array - */ - private static $_np_prohibit_ranges = array( - array(0x80, 0x9F ), - array(0x2060, 0x206F ), - array(0x1D173, 0x1D17A ), - array(0xE000, 0xF8FF ), - array(0xF0000, 0xFFFFD ), - array(0x100000, 0x10FFFD), - array(0xFDD0, 0xFDEF ), - array(0xD800, 0xDFFF ), - array(0x2FF0, 0x2FFB ), - array(0xE0020, 0xE007F ) - ); - - /** - * Replacement mappings (casemapping, replacement sequences, ...) - * - * @var array - */ - private static $_np_replacemaps = array( - 0x41 => array(0x61), - 0x42 => array(0x62), - 0x43 => array(0x63), - 0x44 => array(0x64), - 0x45 => array(0x65), - 0x46 => array(0x66), - 0x47 => array(0x67), - 0x48 => array(0x68), - 0x49 => array(0x69), - 0x4A => array(0x6A), - 0x4B => array(0x6B), - 0x4C => array(0x6C), - 0x4D => array(0x6D), - 0x4E => array(0x6E), - 0x4F => array(0x6F), - 0x50 => array(0x70), - 0x51 => array(0x71), - 0x52 => array(0x72), - 0x53 => array(0x73), - 0x54 => array(0x74), - 0x55 => array(0x75), - 0x56 => array(0x76), - 0x57 => array(0x77), - 0x58 => array(0x78), - 0x59 => array(0x79), - 0x5A => array(0x7A), - 0xB5 => array(0x3BC), - 0xC0 => array(0xE0), - 0xC1 => array(0xE1), - 0xC2 => array(0xE2), - 0xC3 => array(0xE3), - 0xC4 => array(0xE4), - 0xC5 => array(0xE5), - 0xC6 => array(0xE6), - 0xC7 => array(0xE7), - 0xC8 => array(0xE8), - 0xC9 => array(0xE9), - 0xCA => array(0xEA), - 0xCB => array(0xEB), - 0xCC => array(0xEC), - 0xCD => array(0xED), - 0xCE => array(0xEE), - 0xCF => array(0xEF), - 0xD0 => array(0xF0), - 0xD1 => array(0xF1), - 0xD2 => array(0xF2), - 0xD3 => array(0xF3), - 0xD4 => array(0xF4), - 0xD5 => array(0xF5), - 0xD6 => array(0xF6), - 0xD8 => array(0xF8), - 0xD9 => array(0xF9), - 0xDA => array(0xFA), - 0xDB => array(0xFB), - 0xDC => array(0xFC), - 0xDD => array(0xFD), - 0xDE => array(0xFE), - 0xDF => array(0x73, 0x73), - 0x100 => array(0x101), - 0x102 => array(0x103), - 0x104 => array(0x105), - 0x106 => array(0x107), - 0x108 => array(0x109), - 0x10A => array(0x10B), - 0x10C => array(0x10D), - 0x10E => array(0x10F), - 0x110 => array(0x111), - 0x112 => array(0x113), - 0x114 => array(0x115), - 0x116 => array(0x117), - 0x118 => array(0x119), - 0x11A => array(0x11B), - 0x11C => array(0x11D), - 0x11E => array(0x11F), - 0x120 => array(0x121), - 0x122 => array(0x123), - 0x124 => array(0x125), - 0x126 => array(0x127), - 0x128 => array(0x129), - 0x12A => array(0x12B), - 0x12C => array(0x12D), - 0x12E => array(0x12F), - 0x130 => array(0x69, 0x307), - 0x132 => array(0x133), - 0x134 => array(0x135), - 0x136 => array(0x137), - 0x139 => array(0x13A), - 0x13B => array(0x13C), - 0x13D => array(0x13E), - 0x13F => array(0x140), - 0x141 => array(0x142), - 0x143 => array(0x144), - 0x145 => array(0x146), - 0x147 => array(0x148), - 0x149 => array(0x2BC, 0x6E), - 0x14A => array(0x14B), - 0x14C => array(0x14D), - 0x14E => array(0x14F), - 0x150 => array(0x151), - 0x152 => array(0x153), - 0x154 => array(0x155), - 0x156 => array(0x157), - 0x158 => array(0x159), - 0x15A => array(0x15B), - 0x15C => array(0x15D), - 0x15E => array(0x15F), - 0x160 => array(0x161), - 0x162 => array(0x163), - 0x164 => array(0x165), - 0x166 => array(0x167), - 0x168 => array(0x169), - 0x16A => array(0x16B), - 0x16C => array(0x16D), - 0x16E => array(0x16F), - 0x170 => array(0x171), - 0x172 => array(0x173), - 0x174 => array(0x175), - 0x176 => array(0x177), - 0x178 => array(0xFF), - 0x179 => array(0x17A), - 0x17B => array(0x17C), - 0x17D => array(0x17E), - 0x17F => array(0x73), - 0x181 => array(0x253), - 0x182 => array(0x183), - 0x184 => array(0x185), - 0x186 => array(0x254), - 0x187 => array(0x188), - 0x189 => array(0x256), - 0x18A => array(0x257), - 0x18B => array(0x18C), - 0x18E => array(0x1DD), - 0x18F => array(0x259), - 0x190 => array(0x25B), - 0x191 => array(0x192), - 0x193 => array(0x260), - 0x194 => array(0x263), - 0x196 => array(0x269), - 0x197 => array(0x268), - 0x198 => array(0x199), - 0x19C => array(0x26F), - 0x19D => array(0x272), - 0x19F => array(0x275), - 0x1A0 => array(0x1A1), - 0x1A2 => array(0x1A3), - 0x1A4 => array(0x1A5), - 0x1A6 => array(0x280), - 0x1A7 => array(0x1A8), - 0x1A9 => array(0x283), - 0x1AC => array(0x1AD), - 0x1AE => array(0x288), - 0x1AF => array(0x1B0), - 0x1B1 => array(0x28A), - 0x1B2 => array(0x28B), - 0x1B3 => array(0x1B4), - 0x1B5 => array(0x1B6), - 0x1B7 => array(0x292), - 0x1B8 => array(0x1B9), - 0x1BC => array(0x1BD), - 0x1C4 => array(0x1C6), - 0x1C5 => array(0x1C6), - 0x1C7 => array(0x1C9), - 0x1C8 => array(0x1C9), - 0x1CA => array(0x1CC), - 0x1CB => array(0x1CC), - 0x1CD => array(0x1CE), - 0x1CF => array(0x1D0), - 0x1D1 => array(0x1D2), - 0x1D3 => array(0x1D4), - 0x1D5 => array(0x1D6), - 0x1D7 => array(0x1D8), - 0x1D9 => array(0x1DA), - 0x1DB => array(0x1DC), - 0x1DE => array(0x1DF), - 0x1E0 => array(0x1E1), - 0x1E2 => array(0x1E3), - 0x1E4 => array(0x1E5), - 0x1E6 => array(0x1E7), - 0x1E8 => array(0x1E9), - 0x1EA => array(0x1EB), - 0x1EC => array(0x1ED), - 0x1EE => array(0x1EF), - 0x1F0 => array(0x6A, 0x30C), - 0x1F1 => array(0x1F3), - 0x1F2 => array(0x1F3), - 0x1F4 => array(0x1F5), - 0x1F6 => array(0x195), - 0x1F7 => array(0x1BF), - 0x1F8 => array(0x1F9), - 0x1FA => array(0x1FB), - 0x1FC => array(0x1FD), - 0x1FE => array(0x1FF), - 0x200 => array(0x201), - 0x202 => array(0x203), - 0x204 => array(0x205), - 0x206 => array(0x207), - 0x208 => array(0x209), - 0x20A => array(0x20B), - 0x20C => array(0x20D), - 0x20E => array(0x20F), - 0x210 => array(0x211), - 0x212 => array(0x213), - 0x214 => array(0x215), - 0x216 => array(0x217), - 0x218 => array(0x219), - 0x21A => array(0x21B), - 0x21C => array(0x21D), - 0x21E => array(0x21F), - 0x220 => array(0x19E), - 0x222 => array(0x223), - 0x224 => array(0x225), - 0x226 => array(0x227), - 0x228 => array(0x229), - 0x22A => array(0x22B), - 0x22C => array(0x22D), - 0x22E => array(0x22F), - 0x230 => array(0x231), - 0x232 => array(0x233), - 0x345 => array(0x3B9), - 0x37A => array(0x20, 0x3B9), - 0x386 => array(0x3AC), - 0x388 => array(0x3AD), - 0x389 => array(0x3AE), - 0x38A => array(0x3AF), - 0x38C => array(0x3CC), - 0x38E => array(0x3CD), - 0x38F => array(0x3CE), - 0x390 => array(0x3B9, 0x308, 0x301), - 0x391 => array(0x3B1), - 0x392 => array(0x3B2), - 0x393 => array(0x3B3), - 0x394 => array(0x3B4), - 0x395 => array(0x3B5), - 0x396 => array(0x3B6), - 0x397 => array(0x3B7), - 0x398 => array(0x3B8), - 0x399 => array(0x3B9), - 0x39A => array(0x3BA), - 0x39B => array(0x3BB), - 0x39C => array(0x3BC), - 0x39D => array(0x3BD), - 0x39E => array(0x3BE), - 0x39F => array(0x3BF), - 0x3A0 => array(0x3C0), - 0x3A1 => array(0x3C1), - 0x3A3 => array(0x3C3), - 0x3A4 => array(0x3C4), - 0x3A5 => array(0x3C5), - 0x3A6 => array(0x3C6), - 0x3A7 => array(0x3C7), - 0x3A8 => array(0x3C8), - 0x3A9 => array(0x3C9), - 0x3AA => array(0x3CA), - 0x3AB => array(0x3CB), - 0x3B0 => array(0x3C5, 0x308, 0x301), - 0x3C2 => array(0x3C3), - 0x3D0 => array(0x3B2), - 0x3D1 => array(0x3B8), - 0x3D2 => array(0x3C5), - 0x3D3 => array(0x3CD), - 0x3D4 => array(0x3CB), - 0x3D5 => array(0x3C6), - 0x3D6 => array(0x3C0), - 0x3D8 => array(0x3D9), - 0x3DA => array(0x3DB), - 0x3DC => array(0x3DD), - 0x3DE => array(0x3DF), - 0x3E0 => array(0x3E1), - 0x3E2 => array(0x3E3), - 0x3E4 => array(0x3E5), - 0x3E6 => array(0x3E7), - 0x3E8 => array(0x3E9), - 0x3EA => array(0x3EB), - 0x3EC => array(0x3ED), - 0x3EE => array(0x3EF), - 0x3F0 => array(0x3BA), - 0x3F1 => array(0x3C1), - 0x3F2 => array(0x3C3), - 0x3F4 => array(0x3B8), - 0x3F5 => array(0x3B5), - 0x400 => array(0x450), - 0x401 => array(0x451), - 0x402 => array(0x452), - 0x403 => array(0x453), - 0x404 => array(0x454), - 0x405 => array(0x455), - 0x406 => array(0x456), - 0x407 => array(0x457), - 0x408 => array(0x458), - 0x409 => array(0x459), - 0x40A => array(0x45A), - 0x40B => array(0x45B), - 0x40C => array(0x45C), - 0x40D => array(0x45D), - 0x40E => array(0x45E), - 0x40F => array(0x45F), - 0x410 => array(0x430), - 0x411 => array(0x431), - 0x412 => array(0x432), - 0x413 => array(0x433), - 0x414 => array(0x434), - 0x415 => array(0x435), - 0x416 => array(0x436), - 0x417 => array(0x437), - 0x418 => array(0x438), - 0x419 => array(0x439), - 0x41A => array(0x43A), - 0x41B => array(0x43B), - 0x41C => array(0x43C), - 0x41D => array(0x43D), - 0x41E => array(0x43E), - 0x41F => array(0x43F), - 0x420 => array(0x440), - 0x421 => array(0x441), - 0x422 => array(0x442), - 0x423 => array(0x443), - 0x424 => array(0x444), - 0x425 => array(0x445), - 0x426 => array(0x446), - 0x427 => array(0x447), - 0x428 => array(0x448), - 0x429 => array(0x449), - 0x42A => array(0x44A), - 0x42B => array(0x44B), - 0x42C => array(0x44C), - 0x42D => array(0x44D), - 0x42E => array(0x44E), - 0x42F => array(0x44F), - 0x460 => array(0x461), - 0x462 => array(0x463), - 0x464 => array(0x465), - 0x466 => array(0x467), - 0x468 => array(0x469), - 0x46A => array(0x46B), - 0x46C => array(0x46D), - 0x46E => array(0x46F), - 0x470 => array(0x471), - 0x472 => array(0x473), - 0x474 => array(0x475), - 0x476 => array(0x477), - 0x478 => array(0x479), - 0x47A => array(0x47B), - 0x47C => array(0x47D), - 0x47E => array(0x47F), - 0x480 => array(0x481), - 0x48A => array(0x48B), - 0x48C => array(0x48D), - 0x48E => array(0x48F), - 0x490 => array(0x491), - 0x492 => array(0x493), - 0x494 => array(0x495), - 0x496 => array(0x497), - 0x498 => array(0x499), - 0x49A => array(0x49B), - 0x49C => array(0x49D), - 0x49E => array(0x49F), - 0x4A0 => array(0x4A1), - 0x4A2 => array(0x4A3), - 0x4A4 => array(0x4A5), - 0x4A6 => array(0x4A7), - 0x4A8 => array(0x4A9), - 0x4AA => array(0x4AB), - 0x4AC => array(0x4AD), - 0x4AE => array(0x4AF), - 0x4B0 => array(0x4B1), - 0x4B2 => array(0x4B3), - 0x4B4 => array(0x4B5), - 0x4B6 => array(0x4B7), - 0x4B8 => array(0x4B9), - 0x4BA => array(0x4BB), - 0x4BC => array(0x4BD), - 0x4BE => array(0x4BF), - 0x4C1 => array(0x4C2), - 0x4C3 => array(0x4C4), - 0x4C5 => array(0x4C6), - 0x4C7 => array(0x4C8), - 0x4C9 => array(0x4CA), - 0x4CB => array(0x4CC), - 0x4CD => array(0x4CE), - 0x4D0 => array(0x4D1), - 0x4D2 => array(0x4D3), - 0x4D4 => array(0x4D5), - 0x4D6 => array(0x4D7), - 0x4D8 => array(0x4D9), - 0x4DA => array(0x4DB), - 0x4DC => array(0x4DD), - 0x4DE => array(0x4DF), - 0x4E0 => array(0x4E1), - 0x4E2 => array(0x4E3), - 0x4E4 => array(0x4E5), - 0x4E6 => array(0x4E7), - 0x4E8 => array(0x4E9), - 0x4EA => array(0x4EB), - 0x4EC => array(0x4ED), - 0x4EE => array(0x4EF), - 0x4F0 => array(0x4F1), - 0x4F2 => array(0x4F3), - 0x4F4 => array(0x4F5), - 0x4F8 => array(0x4F9), - 0x500 => array(0x501), - 0x502 => array(0x503), - 0x504 => array(0x505), - 0x506 => array(0x507), - 0x508 => array(0x509), - 0x50A => array(0x50B), - 0x50C => array(0x50D), - 0x50E => array(0x50F), - 0x531 => array(0x561), - 0x532 => array(0x562), - 0x533 => array(0x563), - 0x534 => array(0x564), - 0x535 => array(0x565), - 0x536 => array(0x566), - 0x537 => array(0x567), - 0x538 => array(0x568), - 0x539 => array(0x569), - 0x53A => array(0x56A), - 0x53B => array(0x56B), - 0x53C => array(0x56C), - 0x53D => array(0x56D), - 0x53E => array(0x56E), - 0x53F => array(0x56F), - 0x540 => array(0x570), - 0x541 => array(0x571), - 0x542 => array(0x572), - 0x543 => array(0x573), - 0x544 => array(0x574), - 0x545 => array(0x575), - 0x546 => array(0x576), - 0x547 => array(0x577), - 0x548 => array(0x578), - 0x549 => array(0x579), - 0x54A => array(0x57A), - 0x54B => array(0x57B), - 0x54C => array(0x57C), - 0x54D => array(0x57D), - 0x54E => array(0x57E), - 0x54F => array(0x57F), - 0x550 => array(0x580), - 0x551 => array(0x581), - 0x552 => array(0x582), - 0x553 => array(0x583), - 0x554 => array(0x584), - 0x555 => array(0x585), - 0x556 => array(0x586), - 0x587 => array(0x565, 0x582), - 0x1E00 => array(0x1E01), - 0x1E02 => array(0x1E03), - 0x1E04 => array(0x1E05), - 0x1E06 => array(0x1E07), - 0x1E08 => array(0x1E09), - 0x1E0A => array(0x1E0B), - 0x1E0C => array(0x1E0D), - 0x1E0E => array(0x1E0F), - 0x1E10 => array(0x1E11), - 0x1E12 => array(0x1E13), - 0x1E14 => array(0x1E15), - 0x1E16 => array(0x1E17), - 0x1E18 => array(0x1E19), - 0x1E1A => array(0x1E1B), - 0x1E1C => array(0x1E1D), - 0x1E1E => array(0x1E1F), - 0x1E20 => array(0x1E21), - 0x1E22 => array(0x1E23), - 0x1E24 => array(0x1E25), - 0x1E26 => array(0x1E27), - 0x1E28 => array(0x1E29), - 0x1E2A => array(0x1E2B), - 0x1E2C => array(0x1E2D), - 0x1E2E => array(0x1E2F), - 0x1E30 => array(0x1E31), - 0x1E32 => array(0x1E33), - 0x1E34 => array(0x1E35), - 0x1E36 => array(0x1E37), - 0x1E38 => array(0x1E39), - 0x1E3A => array(0x1E3B), - 0x1E3C => array(0x1E3D), - 0x1E3E => array(0x1E3F), - 0x1E40 => array(0x1E41), - 0x1E42 => array(0x1E43), - 0x1E44 => array(0x1E45), - 0x1E46 => array(0x1E47), - 0x1E48 => array(0x1E49), - 0x1E4A => array(0x1E4B), - 0x1E4C => array(0x1E4D), - 0x1E4E => array(0x1E4F), - 0x1E50 => array(0x1E51), - 0x1E52 => array(0x1E53), - 0x1E54 => array(0x1E55), - 0x1E56 => array(0x1E57), - 0x1E58 => array(0x1E59), - 0x1E5A => array(0x1E5B), - 0x1E5C => array(0x1E5D), - 0x1E5E => array(0x1E5F), - 0x1E60 => array(0x1E61), - 0x1E62 => array(0x1E63), - 0x1E64 => array(0x1E65), - 0x1E66 => array(0x1E67), - 0x1E68 => array(0x1E69), - 0x1E6A => array(0x1E6B), - 0x1E6C => array(0x1E6D), - 0x1E6E => array(0x1E6F), - 0x1E70 => array(0x1E71), - 0x1E72 => array(0x1E73), - 0x1E74 => array(0x1E75), - 0x1E76 => array(0x1E77), - 0x1E78 => array(0x1E79), - 0x1E7A => array(0x1E7B), - 0x1E7C => array(0x1E7D), - 0x1E7E => array(0x1E7F), - 0x1E80 => array(0x1E81), - 0x1E82 => array(0x1E83), - 0x1E84 => array(0x1E85), - 0x1E86 => array(0x1E87), - 0x1E88 => array(0x1E89), - 0x1E8A => array(0x1E8B), - 0x1E8C => array(0x1E8D), - 0x1E8E => array(0x1E8F), - 0x1E90 => array(0x1E91), - 0x1E92 => array(0x1E93), - 0x1E94 => array(0x1E95), - 0x1E96 => array(0x68, 0x331), - 0x1E97 => array(0x74, 0x308), - 0x1E98 => array(0x77, 0x30A), - 0x1E99 => array(0x79, 0x30A), - 0x1E9A => array(0x61, 0x2BE), - 0x1E9B => array(0x1E61), - 0x1EA0 => array(0x1EA1), - 0x1EA2 => array(0x1EA3), - 0x1EA4 => array(0x1EA5), - 0x1EA6 => array(0x1EA7), - 0x1EA8 => array(0x1EA9), - 0x1EAA => array(0x1EAB), - 0x1EAC => array(0x1EAD), - 0x1EAE => array(0x1EAF), - 0x1EB0 => array(0x1EB1), - 0x1EB2 => array(0x1EB3), - 0x1EB4 => array(0x1EB5), - 0x1EB6 => array(0x1EB7), - 0x1EB8 => array(0x1EB9), - 0x1EBA => array(0x1EBB), - 0x1EBC => array(0x1EBD), - 0x1EBE => array(0x1EBF), - 0x1EC0 => array(0x1EC1), - 0x1EC2 => array(0x1EC3), - 0x1EC4 => array(0x1EC5), - 0x1EC6 => array(0x1EC7), - 0x1EC8 => array(0x1EC9), - 0x1ECA => array(0x1ECB), - 0x1ECC => array(0x1ECD), - 0x1ECE => array(0x1ECF), - 0x1ED0 => array(0x1ED1), - 0x1ED2 => array(0x1ED3), - 0x1ED4 => array(0x1ED5), - 0x1ED6 => array(0x1ED7), - 0x1ED8 => array(0x1ED9), - 0x1EDA => array(0x1EDB), - 0x1EDC => array(0x1EDD), - 0x1EDE => array(0x1EDF), - 0x1EE0 => array(0x1EE1), - 0x1EE2 => array(0x1EE3), - 0x1EE4 => array(0x1EE5), - 0x1EE6 => array(0x1EE7), - 0x1EE8 => array(0x1EE9), - 0x1EEA => array(0x1EEB), - 0x1EEC => array(0x1EED), - 0x1EEE => array(0x1EEF), - 0x1EF0 => array(0x1EF1), - 0x1EF2 => array(0x1EF3), - 0x1EF4 => array(0x1EF5), - 0x1EF6 => array(0x1EF7), - 0x1EF8 => array(0x1EF9), - 0x1F08 => array(0x1F00), - 0x1F09 => array(0x1F01), - 0x1F0A => array(0x1F02), - 0x1F0B => array(0x1F03), - 0x1F0C => array(0x1F04), - 0x1F0D => array(0x1F05), - 0x1F0E => array(0x1F06), - 0x1F0F => array(0x1F07), - 0x1F18 => array(0x1F10), - 0x1F19 => array(0x1F11), - 0x1F1A => array(0x1F12), - 0x1F1B => array(0x1F13), - 0x1F1C => array(0x1F14), - 0x1F1D => array(0x1F15), - 0x1F28 => array(0x1F20), - 0x1F29 => array(0x1F21), - 0x1F2A => array(0x1F22), - 0x1F2B => array(0x1F23), - 0x1F2C => array(0x1F24), - 0x1F2D => array(0x1F25), - 0x1F2E => array(0x1F26), - 0x1F2F => array(0x1F27), - 0x1F38 => array(0x1F30), - 0x1F39 => array(0x1F31), - 0x1F3A => array(0x1F32), - 0x1F3B => array(0x1F33), - 0x1F3C => array(0x1F34), - 0x1F3D => array(0x1F35), - 0x1F3E => array(0x1F36), - 0x1F3F => array(0x1F37), - 0x1F48 => array(0x1F40), - 0x1F49 => array(0x1F41), - 0x1F4A => array(0x1F42), - 0x1F4B => array(0x1F43), - 0x1F4C => array(0x1F44), - 0x1F4D => array(0x1F45), - 0x1F50 => array(0x3C5, 0x313), - 0x1F52 => array(0x3C5, 0x313, 0x300), - 0x1F54 => array(0x3C5, 0x313, 0x301), - 0x1F56 => array(0x3C5, 0x313, 0x342), - 0x1F59 => array(0x1F51), - 0x1F5B => array(0x1F53), - 0x1F5D => array(0x1F55), - 0x1F5F => array(0x1F57), - 0x1F68 => array(0x1F60), - 0x1F69 => array(0x1F61), - 0x1F6A => array(0x1F62), - 0x1F6B => array(0x1F63), - 0x1F6C => array(0x1F64), - 0x1F6D => array(0x1F65), - 0x1F6E => array(0x1F66), - 0x1F6F => array(0x1F67), - 0x1F80 => array(0x1F00, 0x3B9), - 0x1F81 => array(0x1F01, 0x3B9), - 0x1F82 => array(0x1F02, 0x3B9), - 0x1F83 => array(0x1F03, 0x3B9), - 0x1F84 => array(0x1F04, 0x3B9), - 0x1F85 => array(0x1F05, 0x3B9), - 0x1F86 => array(0x1F06, 0x3B9), - 0x1F87 => array(0x1F07, 0x3B9), - 0x1F88 => array(0x1F00, 0x3B9), - 0x1F89 => array(0x1F01, 0x3B9), - 0x1F8A => array(0x1F02, 0x3B9), - 0x1F8B => array(0x1F03, 0x3B9), - 0x1F8C => array(0x1F04, 0x3B9), - 0x1F8D => array(0x1F05, 0x3B9), - 0x1F8E => array(0x1F06, 0x3B9), - 0x1F8F => array(0x1F07, 0x3B9), - 0x1F90 => array(0x1F20, 0x3B9), - 0x1F91 => array(0x1F21, 0x3B9), - 0x1F92 => array(0x1F22, 0x3B9), - 0x1F93 => array(0x1F23, 0x3B9), - 0x1F94 => array(0x1F24, 0x3B9), - 0x1F95 => array(0x1F25, 0x3B9), - 0x1F96 => array(0x1F26, 0x3B9), - 0x1F97 => array(0x1F27, 0x3B9), - 0x1F98 => array(0x1F20, 0x3B9), - 0x1F99 => array(0x1F21, 0x3B9), - 0x1F9A => array(0x1F22, 0x3B9), - 0x1F9B => array(0x1F23, 0x3B9), - 0x1F9C => array(0x1F24, 0x3B9), - 0x1F9D => array(0x1F25, 0x3B9), - 0x1F9E => array(0x1F26, 0x3B9), - 0x1F9F => array(0x1F27, 0x3B9), - 0x1FA0 => array(0x1F60, 0x3B9), - 0x1FA1 => array(0x1F61, 0x3B9), - 0x1FA2 => array(0x1F62, 0x3B9), - 0x1FA3 => array(0x1F63, 0x3B9), - 0x1FA4 => array(0x1F64, 0x3B9), - 0x1FA5 => array(0x1F65, 0x3B9), - 0x1FA6 => array(0x1F66, 0x3B9), - 0x1FA7 => array(0x1F67, 0x3B9), - 0x1FA8 => array(0x1F60, 0x3B9), - 0x1FA9 => array(0x1F61, 0x3B9), - 0x1FAA => array(0x1F62, 0x3B9), - 0x1FAB => array(0x1F63, 0x3B9), - 0x1FAC => array(0x1F64, 0x3B9), - 0x1FAD => array(0x1F65, 0x3B9), - 0x1FAE => array(0x1F66, 0x3B9), - 0x1FAF => array(0x1F67, 0x3B9), - 0x1FB2 => array(0x1F70, 0x3B9), - 0x1FB3 => array(0x3B1, 0x3B9), - 0x1FB4 => array(0x3AC, 0x3B9), - 0x1FB6 => array(0x3B1, 0x342), - 0x1FB7 => array(0x3B1, 0x342, 0x3B9), - 0x1FB8 => array(0x1FB0), - 0x1FB9 => array(0x1FB1), - 0x1FBA => array(0x1F70), - 0x1FBB => array(0x1F71), - 0x1FBC => array(0x3B1, 0x3B9), - 0x1FBE => array(0x3B9), - 0x1FC2 => array(0x1F74, 0x3B9), - 0x1FC3 => array(0x3B7, 0x3B9), - 0x1FC4 => array(0x3AE, 0x3B9), - 0x1FC6 => array(0x3B7, 0x342), - 0x1FC7 => array(0x3B7, 0x342, 0x3B9), - 0x1FC8 => array(0x1F72), - 0x1FC9 => array(0x1F73), - 0x1FCA => array(0x1F74), - 0x1FCB => array(0x1F75), - 0x1FCC => array(0x3B7, 0x3B9), - 0x1FD2 => array(0x3B9, 0x308, 0x300), - 0x1FD3 => array(0x3B9, 0x308, 0x301), - 0x1FD6 => array(0x3B9, 0x342), - 0x1FD7 => array(0x3B9, 0x308, 0x342), - 0x1FD8 => array(0x1FD0), - 0x1FD9 => array(0x1FD1), - 0x1FDA => array(0x1F76), - 0x1FDB => array(0x1F77), - 0x1FE2 => array(0x3C5, 0x308, 0x300), - 0x1FE3 => array(0x3C5, 0x308, 0x301), - 0x1FE4 => array(0x3C1, 0x313), - 0x1FE6 => array(0x3C5, 0x342), - 0x1FE7 => array(0x3C5, 0x308, 0x342), - 0x1FE8 => array(0x1FE0), - 0x1FE9 => array(0x1FE1), - 0x1FEA => array(0x1F7A), - 0x1FEB => array(0x1F7B), - 0x1FEC => array(0x1FE5), - 0x1FF2 => array(0x1F7C, 0x3B9), - 0x1FF3 => array(0x3C9, 0x3B9), - 0x1FF4 => array(0x3CE, 0x3B9), - 0x1FF6 => array(0x3C9, 0x342), - 0x1FF7 => array(0x3C9, 0x342, 0x3B9), - 0x1FF8 => array(0x1F78), - 0x1FF9 => array(0x1F79), - 0x1FFA => array(0x1F7C), - 0x1FFB => array(0x1F7D), - 0x1FFC => array(0x3C9, 0x3B9), - 0x20A8 => array(0x72, 0x73), - 0x2102 => array(0x63), - 0x2103 => array(0xB0, 0x63), - 0x2107 => array(0x25B), - 0x2109 => array(0xB0, 0x66), - 0x210B => array(0x68), - 0x210C => array(0x68), - 0x210D => array(0x68), - 0x2110 => array(0x69), - 0x2111 => array(0x69), - 0x2112 => array(0x6C), - 0x2115 => array(0x6E), - 0x2116 => array(0x6E, 0x6F), - 0x2119 => array(0x70), - 0x211A => array(0x71), - 0x211B => array(0x72), - 0x211C => array(0x72), - 0x211D => array(0x72), - 0x2120 => array(0x73, 0x6D), - 0x2121 => array(0x74, 0x65, 0x6C), - 0x2122 => array(0x74, 0x6D), - 0x2124 => array(0x7A), - 0x2126 => array(0x3C9), - 0x2128 => array(0x7A), - 0x212A => array(0x6B), - 0x212B => array(0xE5), - 0x212C => array(0x62), - 0x212D => array(0x63), - 0x2130 => array(0x65), - 0x2131 => array(0x66), - 0x2133 => array(0x6D), - 0x213E => array(0x3B3), - 0x213F => array(0x3C0), - 0x2145 => array(0x64), - 0x2160 => array(0x2170), - 0x2161 => array(0x2171), - 0x2162 => array(0x2172), - 0x2163 => array(0x2173), - 0x2164 => array(0x2174), - 0x2165 => array(0x2175), - 0x2166 => array(0x2176), - 0x2167 => array(0x2177), - 0x2168 => array(0x2178), - 0x2169 => array(0x2179), - 0x216A => array(0x217A), - 0x216B => array(0x217B), - 0x216C => array(0x217C), - 0x216D => array(0x217D), - 0x216E => array(0x217E), - 0x216F => array(0x217F), - 0x24B6 => array(0x24D0), - 0x24B7 => array(0x24D1), - 0x24B8 => array(0x24D2), - 0x24B9 => array(0x24D3), - 0x24BA => array(0x24D4), - 0x24BB => array(0x24D5), - 0x24BC => array(0x24D6), - 0x24BD => array(0x24D7), - 0x24BE => array(0x24D8), - 0x24BF => array(0x24D9), - 0x24C0 => array(0x24DA), - 0x24C1 => array(0x24DB), - 0x24C2 => array(0x24DC), - 0x24C3 => array(0x24DD), - 0x24C4 => array(0x24DE), - 0x24C5 => array(0x24DF), - 0x24C6 => array(0x24E0), - 0x24C7 => array(0x24E1), - 0x24C8 => array(0x24E2), - 0x24C9 => array(0x24E3), - 0x24CA => array(0x24E4), - 0x24CB => array(0x24E5), - 0x24CC => array(0x24E6), - 0x24CD => array(0x24E7), - 0x24CE => array(0x24E8), - 0x24CF => array(0x24E9), - 0x3371 => array(0x68, 0x70, 0x61), - 0x3373 => array(0x61, 0x75), - 0x3375 => array(0x6F, 0x76), - 0x3380 => array(0x70, 0x61), - 0x3381 => array(0x6E, 0x61), - 0x3382 => array(0x3BC, 0x61), - 0x3383 => array(0x6D, 0x61), - 0x3384 => array(0x6B, 0x61), - 0x3385 => array(0x6B, 0x62), - 0x3386 => array(0x6D, 0x62), - 0x3387 => array(0x67, 0x62), - 0x338A => array(0x70, 0x66), - 0x338B => array(0x6E, 0x66), - 0x338C => array(0x3BC, 0x66), - 0x3390 => array(0x68, 0x7A), - 0x3391 => array(0x6B, 0x68, 0x7A), - 0x3392 => array(0x6D, 0x68, 0x7A), - 0x3393 => array(0x67, 0x68, 0x7A), - 0x3394 => array(0x74, 0x68, 0x7A), - 0x33A9 => array(0x70, 0x61), - 0x33AA => array(0x6B, 0x70, 0x61), - 0x33AB => array(0x6D, 0x70, 0x61), - 0x33AC => array(0x67, 0x70, 0x61), - 0x33B4 => array(0x70, 0x76), - 0x33B5 => array(0x6E, 0x76), - 0x33B6 => array(0x3BC, 0x76), - 0x33B7 => array(0x6D, 0x76), - 0x33B8 => array(0x6B, 0x76), - 0x33B9 => array(0x6D, 0x76), - 0x33BA => array(0x70, 0x77), - 0x33BB => array(0x6E, 0x77), - 0x33BC => array(0x3BC, 0x77), - 0x33BD => array(0x6D, 0x77), - 0x33BE => array(0x6B, 0x77), - 0x33BF => array(0x6D, 0x77), - 0x33C0 => array(0x6B, 0x3C9), - 0x33C1 => array(0x6D, 0x3C9), - /* 0x33C2 => array(0x61, 0x2E, 0x6D, 0x2E), */ - 0x33C3 => array(0x62, 0x71), - 0x33C6 => array(0x63, 0x2215, 0x6B, 0x67), - 0x33C7 => array(0x63, 0x6F, 0x2E), - 0x33C8 => array(0x64, 0x62), - 0x33C9 => array(0x67, 0x79), - 0x33CB => array(0x68, 0x70), - 0x33CD => array(0x6B, 0x6B), - 0x33CE => array(0x6B, 0x6D), - 0x33D7 => array(0x70, 0x68), - 0x33D9 => array(0x70, 0x70, 0x6D), - 0x33DA => array(0x70, 0x72), - 0x33DC => array(0x73, 0x76), - 0x33DD => array(0x77, 0x62), - 0xFB00 => array(0x66, 0x66), - 0xFB01 => array(0x66, 0x69), - 0xFB02 => array(0x66, 0x6C), - 0xFB03 => array(0x66, 0x66, 0x69), - 0xFB04 => array(0x66, 0x66, 0x6C), - 0xFB05 => array(0x73, 0x74), - 0xFB06 => array(0x73, 0x74), - 0xFB13 => array(0x574, 0x576), - 0xFB14 => array(0x574, 0x565), - 0xFB15 => array(0x574, 0x56B), - 0xFB16 => array(0x57E, 0x576), - 0xFB17 => array(0x574, 0x56D), - 0xFF21 => array(0xFF41), - 0xFF22 => array(0xFF42), - 0xFF23 => array(0xFF43), - 0xFF24 => array(0xFF44), - 0xFF25 => array(0xFF45), - 0xFF26 => array(0xFF46), - 0xFF27 => array(0xFF47), - 0xFF28 => array(0xFF48), - 0xFF29 => array(0xFF49), - 0xFF2A => array(0xFF4A), - 0xFF2B => array(0xFF4B), - 0xFF2C => array(0xFF4C), - 0xFF2D => array(0xFF4D), - 0xFF2E => array(0xFF4E), - 0xFF2F => array(0xFF4F), - 0xFF30 => array(0xFF50), - 0xFF31 => array(0xFF51), - 0xFF32 => array(0xFF52), - 0xFF33 => array(0xFF53), - 0xFF34 => array(0xFF54), - 0xFF35 => array(0xFF55), - 0xFF36 => array(0xFF56), - 0xFF37 => array(0xFF57), - 0xFF38 => array(0xFF58), - 0xFF39 => array(0xFF59), - 0xFF3A => array(0xFF5A), - 0x10400 => array(0x10428), - 0x10401 => array(0x10429), - 0x10402 => array(0x1042A), - 0x10403 => array(0x1042B), - 0x10404 => array(0x1042C), - 0x10405 => array(0x1042D), - 0x10406 => array(0x1042E), - 0x10407 => array(0x1042F), - 0x10408 => array(0x10430), - 0x10409 => array(0x10431), - 0x1040A => array(0x10432), - 0x1040B => array(0x10433), - 0x1040C => array(0x10434), - 0x1040D => array(0x10435), - 0x1040E => array(0x10436), - 0x1040F => array(0x10437), - 0x10410 => array(0x10438), - 0x10411 => array(0x10439), - 0x10412 => array(0x1043A), - 0x10413 => array(0x1043B), - 0x10414 => array(0x1043C), - 0x10415 => array(0x1043D), - 0x10416 => array(0x1043E), - 0x10417 => array(0x1043F), - 0x10418 => array(0x10440), - 0x10419 => array(0x10441), - 0x1041A => array(0x10442), - 0x1041B => array(0x10443), - 0x1041C => array(0x10444), - 0x1041D => array(0x10445), - 0x1041E => array(0x10446), - 0x1041F => array(0x10447), - 0x10420 => array(0x10448), - 0x10421 => array(0x10449), - 0x10422 => array(0x1044A), - 0x10423 => array(0x1044B), - 0x10424 => array(0x1044C), - 0x10425 => array(0x1044D), - 0x1D400 => array(0x61), - 0x1D401 => array(0x62), - 0x1D402 => array(0x63), - 0x1D403 => array(0x64), - 0x1D404 => array(0x65), - 0x1D405 => array(0x66), - 0x1D406 => array(0x67), - 0x1D407 => array(0x68), - 0x1D408 => array(0x69), - 0x1D409 => array(0x6A), - 0x1D40A => array(0x6B), - 0x1D40B => array(0x6C), - 0x1D40C => array(0x6D), - 0x1D40D => array(0x6E), - 0x1D40E => array(0x6F), - 0x1D40F => array(0x70), - 0x1D410 => array(0x71), - 0x1D411 => array(0x72), - 0x1D412 => array(0x73), - 0x1D413 => array(0x74), - 0x1D414 => array(0x75), - 0x1D415 => array(0x76), - 0x1D416 => array(0x77), - 0x1D417 => array(0x78), - 0x1D418 => array(0x79), - 0x1D419 => array(0x7A), - 0x1D434 => array(0x61), - 0x1D435 => array(0x62), - 0x1D436 => array(0x63), - 0x1D437 => array(0x64), - 0x1D438 => array(0x65), - 0x1D439 => array(0x66), - 0x1D43A => array(0x67), - 0x1D43B => array(0x68), - 0x1D43C => array(0x69), - 0x1D43D => array(0x6A), - 0x1D43E => array(0x6B), - 0x1D43F => array(0x6C), - 0x1D440 => array(0x6D), - 0x1D441 => array(0x6E), - 0x1D442 => array(0x6F), - 0x1D443 => array(0x70), - 0x1D444 => array(0x71), - 0x1D445 => array(0x72), - 0x1D446 => array(0x73), - 0x1D447 => array(0x74), - 0x1D448 => array(0x75), - 0x1D449 => array(0x76), - 0x1D44A => array(0x77), - 0x1D44B => array(0x78), - 0x1D44C => array(0x79), - 0x1D44D => array(0x7A), - 0x1D468 => array(0x61), - 0x1D469 => array(0x62), - 0x1D46A => array(0x63), - 0x1D46B => array(0x64), - 0x1D46C => array(0x65), - 0x1D46D => array(0x66), - 0x1D46E => array(0x67), - 0x1D46F => array(0x68), - 0x1D470 => array(0x69), - 0x1D471 => array(0x6A), - 0x1D472 => array(0x6B), - 0x1D473 => array(0x6C), - 0x1D474 => array(0x6D), - 0x1D475 => array(0x6E), - 0x1D476 => array(0x6F), - 0x1D477 => array(0x70), - 0x1D478 => array(0x71), - 0x1D479 => array(0x72), - 0x1D47A => array(0x73), - 0x1D47B => array(0x74), - 0x1D47C => array(0x75), - 0x1D47D => array(0x76), - 0x1D47E => array(0x77), - 0x1D47F => array(0x78), - 0x1D480 => array(0x79), - 0x1D481 => array(0x7A), - 0x1D49C => array(0x61), - 0x1D49E => array(0x63), - 0x1D49F => array(0x64), - 0x1D4A2 => array(0x67), - 0x1D4A5 => array(0x6A), - 0x1D4A6 => array(0x6B), - 0x1D4A9 => array(0x6E), - 0x1D4AA => array(0x6F), - 0x1D4AB => array(0x70), - 0x1D4AC => array(0x71), - 0x1D4AE => array(0x73), - 0x1D4AF => array(0x74), - 0x1D4B0 => array(0x75), - 0x1D4B1 => array(0x76), - 0x1D4B2 => array(0x77), - 0x1D4B3 => array(0x78), - 0x1D4B4 => array(0x79), - 0x1D4B5 => array(0x7A), - 0x1D4D0 => array(0x61), - 0x1D4D1 => array(0x62), - 0x1D4D2 => array(0x63), - 0x1D4D3 => array(0x64), - 0x1D4D4 => array(0x65), - 0x1D4D5 => array(0x66), - 0x1D4D6 => array(0x67), - 0x1D4D7 => array(0x68), - 0x1D4D8 => array(0x69), - 0x1D4D9 => array(0x6A), - 0x1D4DA => array(0x6B), - 0x1D4DB => array(0x6C), - 0x1D4DC => array(0x6D), - 0x1D4DD => array(0x6E), - 0x1D4DE => array(0x6F), - 0x1D4DF => array(0x70), - 0x1D4E0 => array(0x71), - 0x1D4E1 => array(0x72), - 0x1D4E2 => array(0x73), - 0x1D4E3 => array(0x74), - 0x1D4E4 => array(0x75), - 0x1D4E5 => array(0x76), - 0x1D4E6 => array(0x77), - 0x1D4E7 => array(0x78), - 0x1D4E8 => array(0x79), - 0x1D4E9 => array(0x7A), - 0x1D504 => array(0x61), - 0x1D505 => array(0x62), - 0x1D507 => array(0x64), - 0x1D508 => array(0x65), - 0x1D509 => array(0x66), - 0x1D50A => array(0x67), - 0x1D50D => array(0x6A), - 0x1D50E => array(0x6B), - 0x1D50F => array(0x6C), - 0x1D510 => array(0x6D), - 0x1D511 => array(0x6E), - 0x1D512 => array(0x6F), - 0x1D513 => array(0x70), - 0x1D514 => array(0x71), - 0x1D516 => array(0x73), - 0x1D517 => array(0x74), - 0x1D518 => array(0x75), - 0x1D519 => array(0x76), - 0x1D51A => array(0x77), - 0x1D51B => array(0x78), - 0x1D51C => array(0x79), - 0x1D538 => array(0x61), - 0x1D539 => array(0x62), - 0x1D53B => array(0x64), - 0x1D53C => array(0x65), - 0x1D53D => array(0x66), - 0x1D53E => array(0x67), - 0x1D540 => array(0x69), - 0x1D541 => array(0x6A), - 0x1D542 => array(0x6B), - 0x1D543 => array(0x6C), - 0x1D544 => array(0x6D), - 0x1D546 => array(0x6F), - 0x1D54A => array(0x73), - 0x1D54B => array(0x74), - 0x1D54C => array(0x75), - 0x1D54D => array(0x76), - 0x1D54E => array(0x77), - 0x1D54F => array(0x78), - 0x1D550 => array(0x79), - 0x1D56C => array(0x61), - 0x1D56D => array(0x62), - 0x1D56E => array(0x63), - 0x1D56F => array(0x64), - 0x1D570 => array(0x65), - 0x1D571 => array(0x66), - 0x1D572 => array(0x67), - 0x1D573 => array(0x68), - 0x1D574 => array(0x69), - 0x1D575 => array(0x6A), - 0x1D576 => array(0x6B), - 0x1D577 => array(0x6C), - 0x1D578 => array(0x6D), - 0x1D579 => array(0x6E), - 0x1D57A => array(0x6F), - 0x1D57B => array(0x70), - 0x1D57C => array(0x71), - 0x1D57D => array(0x72), - 0x1D57E => array(0x73), - 0x1D57F => array(0x74), - 0x1D580 => array(0x75), - 0x1D581 => array(0x76), - 0x1D582 => array(0x77), - 0x1D583 => array(0x78), - 0x1D584 => array(0x79), - 0x1D585 => array(0x7A), - 0x1D5A0 => array(0x61), - 0x1D5A1 => array(0x62), - 0x1D5A2 => array(0x63), - 0x1D5A3 => array(0x64), - 0x1D5A4 => array(0x65), - 0x1D5A5 => array(0x66), - 0x1D5A6 => array(0x67), - 0x1D5A7 => array(0x68), - 0x1D5A8 => array(0x69), - 0x1D5A9 => array(0x6A), - 0x1D5AA => array(0x6B), - 0x1D5AB => array(0x6C), - 0x1D5AC => array(0x6D), - 0x1D5AD => array(0x6E), - 0x1D5AE => array(0x6F), - 0x1D5AF => array(0x70), - 0x1D5B0 => array(0x71), - 0x1D5B1 => array(0x72), - 0x1D5B2 => array(0x73), - 0x1D5B3 => array(0x74), - 0x1D5B4 => array(0x75), - 0x1D5B5 => array(0x76), - 0x1D5B6 => array(0x77), - 0x1D5B7 => array(0x78), - 0x1D5B8 => array(0x79), - 0x1D5B9 => array(0x7A), - 0x1D5D4 => array(0x61), - 0x1D5D5 => array(0x62), - 0x1D5D6 => array(0x63), - 0x1D5D7 => array(0x64), - 0x1D5D8 => array(0x65), - 0x1D5D9 => array(0x66), - 0x1D5DA => array(0x67), - 0x1D5DB => array(0x68), - 0x1D5DC => array(0x69), - 0x1D5DD => array(0x6A), - 0x1D5DE => array(0x6B), - 0x1D5DF => array(0x6C), - 0x1D5E0 => array(0x6D), - 0x1D5E1 => array(0x6E), - 0x1D5E2 => array(0x6F), - 0x1D5E3 => array(0x70), - 0x1D5E4 => array(0x71), - 0x1D5E5 => array(0x72), - 0x1D5E6 => array(0x73), - 0x1D5E7 => array(0x74), - 0x1D5E8 => array(0x75), - 0x1D5E9 => array(0x76), - 0x1D5EA => array(0x77), - 0x1D5EB => array(0x78), - 0x1D5EC => array(0x79), - 0x1D5ED => array(0x7A), - 0x1D608 => array(0x61), - 0x1D609 => array(0x62), - 0x1D60A => array(0x63), - 0x1D60B => array(0x64), - 0x1D60C => array(0x65), - 0x1D60D => array(0x66), - 0x1D60E => array(0x67), - 0x1D60F => array(0x68), - 0x1D610 => array(0x69), - 0x1D611 => array(0x6A), - 0x1D612 => array(0x6B), - 0x1D613 => array(0x6C), - 0x1D614 => array(0x6D), - 0x1D615 => array(0x6E), - 0x1D616 => array(0x6F), - 0x1D617 => array(0x70), - 0x1D618 => array(0x71), - 0x1D619 => array(0x72), - 0x1D61A => array(0x73), - 0x1D61B => array(0x74), - 0x1D61C => array(0x75), - 0x1D61D => array(0x76), - 0x1D61E => array(0x77), - 0x1D61F => array(0x78), - 0x1D620 => array(0x79), - 0x1D621 => array(0x7A), - 0x1D63C => array(0x61), - 0x1D63D => array(0x62), - 0x1D63E => array(0x63), - 0x1D63F => array(0x64), - 0x1D640 => array(0x65), - 0x1D641 => array(0x66), - 0x1D642 => array(0x67), - 0x1D643 => array(0x68), - 0x1D644 => array(0x69), - 0x1D645 => array(0x6A), - 0x1D646 => array(0x6B), - 0x1D647 => array(0x6C), - 0x1D648 => array(0x6D), - 0x1D649 => array(0x6E), - 0x1D64A => array(0x6F), - 0x1D64B => array(0x70), - 0x1D64C => array(0x71), - 0x1D64D => array(0x72), - 0x1D64E => array(0x73), - 0x1D64F => array(0x74), - 0x1D650 => array(0x75), - 0x1D651 => array(0x76), - 0x1D652 => array(0x77), - 0x1D653 => array(0x78), - 0x1D654 => array(0x79), - 0x1D655 => array(0x7A), - 0x1D670 => array(0x61), - 0x1D671 => array(0x62), - 0x1D672 => array(0x63), - 0x1D673 => array(0x64), - 0x1D674 => array(0x65), - 0x1D675 => array(0x66), - 0x1D676 => array(0x67), - 0x1D677 => array(0x68), - 0x1D678 => array(0x69), - 0x1D679 => array(0x6A), - 0x1D67A => array(0x6B), - 0x1D67B => array(0x6C), - 0x1D67C => array(0x6D), - 0x1D67D => array(0x6E), - 0x1D67E => array(0x6F), - 0x1D67F => array(0x70), - 0x1D680 => array(0x71), - 0x1D681 => array(0x72), - 0x1D682 => array(0x73), - 0x1D683 => array(0x74), - 0x1D684 => array(0x75), - 0x1D685 => array(0x76), - 0x1D686 => array(0x77), - 0x1D687 => array(0x78), - 0x1D688 => array(0x79), - 0x1D689 => array(0x7A), - 0x1D6A8 => array(0x3B1), - 0x1D6A9 => array(0x3B2), - 0x1D6AA => array(0x3B3), - 0x1D6AB => array(0x3B4), - 0x1D6AC => array(0x3B5), - 0x1D6AD => array(0x3B6), - 0x1D6AE => array(0x3B7), - 0x1D6AF => array(0x3B8), - 0x1D6B0 => array(0x3B9), - 0x1D6B1 => array(0x3BA), - 0x1D6B2 => array(0x3BB), - 0x1D6B3 => array(0x3BC), - 0x1D6B4 => array(0x3BD), - 0x1D6B5 => array(0x3BE), - 0x1D6B6 => array(0x3BF), - 0x1D6B7 => array(0x3C0), - 0x1D6B8 => array(0x3C1), - 0x1D6B9 => array(0x3B8), - 0x1D6BA => array(0x3C3), - 0x1D6BB => array(0x3C4), - 0x1D6BC => array(0x3C5), - 0x1D6BD => array(0x3C6), - 0x1D6BE => array(0x3C7), - 0x1D6BF => array(0x3C8), - 0x1D6C0 => array(0x3C9), - 0x1D6D3 => array(0x3C3), - 0x1D6E2 => array(0x3B1), - 0x1D6E3 => array(0x3B2), - 0x1D6E4 => array(0x3B3), - 0x1D6E5 => array(0x3B4), - 0x1D6E6 => array(0x3B5), - 0x1D6E7 => array(0x3B6), - 0x1D6E8 => array(0x3B7), - 0x1D6E9 => array(0x3B8), - 0x1D6EA => array(0x3B9), - 0x1D6EB => array(0x3BA), - 0x1D6EC => array(0x3BB), - 0x1D6ED => array(0x3BC), - 0x1D6EE => array(0x3BD), - 0x1D6EF => array(0x3BE), - 0x1D6F0 => array(0x3BF), - 0x1D6F1 => array(0x3C0), - 0x1D6F2 => array(0x3C1), - 0x1D6F3 => array(0x3B8), - 0x1D6F4 => array(0x3C3), - 0x1D6F5 => array(0x3C4), - 0x1D6F6 => array(0x3C5), - 0x1D6F7 => array(0x3C6), - 0x1D6F8 => array(0x3C7), - 0x1D6F9 => array(0x3C8), - 0x1D6FA => array(0x3C9), - 0x1D70D => array(0x3C3), - 0x1D71C => array(0x3B1), - 0x1D71D => array(0x3B2), - 0x1D71E => array(0x3B3), - 0x1D71F => array(0x3B4), - 0x1D720 => array(0x3B5), - 0x1D721 => array(0x3B6), - 0x1D722 => array(0x3B7), - 0x1D723 => array(0x3B8), - 0x1D724 => array(0x3B9), - 0x1D725 => array(0x3BA), - 0x1D726 => array(0x3BB), - 0x1D727 => array(0x3BC), - 0x1D728 => array(0x3BD), - 0x1D729 => array(0x3BE), - 0x1D72A => array(0x3BF), - 0x1D72B => array(0x3C0), - 0x1D72C => array(0x3C1), - 0x1D72D => array(0x3B8), - 0x1D72E => array(0x3C3), - 0x1D72F => array(0x3C4), - 0x1D730 => array(0x3C5), - 0x1D731 => array(0x3C6), - 0x1D732 => array(0x3C7), - 0x1D733 => array(0x3C8), - 0x1D734 => array(0x3C9), - 0x1D747 => array(0x3C3), - 0x1D756 => array(0x3B1), - 0x1D757 => array(0x3B2), - 0x1D758 => array(0x3B3), - 0x1D759 => array(0x3B4), - 0x1D75A => array(0x3B5), - 0x1D75B => array(0x3B6), - 0x1D75C => array(0x3B7), - 0x1D75D => array(0x3B8), - 0x1D75E => array(0x3B9), - 0x1D75F => array(0x3BA), - 0x1D760 => array(0x3BB), - 0x1D761 => array(0x3BC), - 0x1D762 => array(0x3BD), - 0x1D763 => array(0x3BE), - 0x1D764 => array(0x3BF), - 0x1D765 => array(0x3C0), - 0x1D766 => array(0x3C1), - 0x1D767 => array(0x3B8), - 0x1D768 => array(0x3C3), - 0x1D769 => array(0x3C4), - 0x1D76A => array(0x3C5), - 0x1D76B => array(0x3C6), - 0x1D76C => array(0x3C7), - 0x1D76D => array(0x3C8), - 0x1D76E => array(0x3C9), - 0x1D781 => array(0x3C3), - 0x1D790 => array(0x3B1), - 0x1D791 => array(0x3B2), - 0x1D792 => array(0x3B3), - 0x1D793 => array(0x3B4), - 0x1D794 => array(0x3B5), - 0x1D795 => array(0x3B6), - 0x1D796 => array(0x3B7), - 0x1D797 => array(0x3B8), - 0x1D798 => array(0x3B9), - 0x1D799 => array(0x3BA), - 0x1D79A => array(0x3BB), - 0x1D79B => array(0x3BC), - 0x1D79C => array(0x3BD), - 0x1D79D => array(0x3BE), - 0x1D79E => array(0x3BF), - 0x1D79F => array(0x3C0), - 0x1D7A0 => array(0x3C1), - 0x1D7A1 => array(0x3B8), - 0x1D7A2 => array(0x3C3), - 0x1D7A3 => array(0x3C4), - 0x1D7A4 => array(0x3C5), - 0x1D7A5 => array(0x3C6), - 0x1D7A6 => array(0x3C7), - 0x1D7A7 => array(0x3C8), - 0x1D7A8 => array(0x3C9), - 0x1D7BB => array(0x3C3), - 0x3F9 => array(0x3C3), - 0x1D2C => array(0x61), - 0x1D2D => array(0xE6), - 0x1D2E => array(0x62), - 0x1D30 => array(0x64), - 0x1D31 => array(0x65), - 0x1D32 => array(0x1DD), - 0x1D33 => array(0x67), - 0x1D34 => array(0x68), - 0x1D35 => array(0x69), - 0x1D36 => array(0x6A), - 0x1D37 => array(0x6B), - 0x1D38 => array(0x6C), - 0x1D39 => array(0x6D), - 0x1D3A => array(0x6E), - 0x1D3C => array(0x6F), - 0x1D3D => array(0x223), - 0x1D3E => array(0x70), - 0x1D3F => array(0x72), - 0x1D40 => array(0x74), - 0x1D41 => array(0x75), - 0x1D42 => array(0x77), - 0x213B => array(0x66, 0x61, 0x78), - 0x3250 => array(0x70, 0x74, 0x65), - 0x32CC => array(0x68, 0x67), - 0x32CE => array(0x65, 0x76), - 0x32CF => array(0x6C, 0x74, 0x64), - 0x337A => array(0x69, 0x75), - 0x33DE => array(0x76, 0x2215, 0x6D), - 0x33DF => array(0x61, 0x2215, 0x6D) - ); - - /** - * Normalization Combining Classes; Code Points not listed - * got Combining Class 0. - * - * @var array - */ - private static $_np_norm_combcls = array( - 0x334 => 1, - 0x335 => 1, - 0x336 => 1, - 0x337 => 1, - 0x338 => 1, - 0x93C => 7, - 0x9BC => 7, - 0xA3C => 7, - 0xABC => 7, - 0xB3C => 7, - 0xCBC => 7, - 0x1037 => 7, - 0x3099 => 8, - 0x309A => 8, - 0x94D => 9, - 0x9CD => 9, - 0xA4D => 9, - 0xACD => 9, - 0xB4D => 9, - 0xBCD => 9, - 0xC4D => 9, - 0xCCD => 9, - 0xD4D => 9, - 0xDCA => 9, - 0xE3A => 9, - 0xF84 => 9, - 0x1039 => 9, - 0x1714 => 9, - 0x1734 => 9, - 0x17D2 => 9, - 0x5B0 => 10, - 0x5B1 => 11, - 0x5B2 => 12, - 0x5B3 => 13, - 0x5B4 => 14, - 0x5B5 => 15, - 0x5B6 => 16, - 0x5B7 => 17, - 0x5B8 => 18, - 0x5B9 => 19, - 0x5BB => 20, - 0x5Bc => 21, - 0x5BD => 22, - 0x5BF => 23, - 0x5C1 => 24, - 0x5C2 => 25, - 0xFB1E => 26, - 0x64B => 27, - 0x64C => 28, - 0x64D => 29, - 0x64E => 30, - 0x64F => 31, - 0x650 => 32, - 0x651 => 33, - 0x652 => 34, - 0x670 => 35, - 0x711 => 36, - 0xC55 => 84, - 0xC56 => 91, - 0xE38 => 103, - 0xE39 => 103, - 0xE48 => 107, - 0xE49 => 107, - 0xE4A => 107, - 0xE4B => 107, - 0xEB8 => 118, - 0xEB9 => 118, - 0xEC8 => 122, - 0xEC9 => 122, - 0xECA => 122, - 0xECB => 122, - 0xF71 => 129, - 0xF72 => 130, - 0xF7A => 130, - 0xF7B => 130, - 0xF7C => 130, - 0xF7D => 130, - 0xF80 => 130, - 0xF74 => 132, - 0x321 => 202, - 0x322 => 202, - 0x327 => 202, - 0x328 => 202, - 0x31B => 216, - 0xF39 => 216, - 0x1D165 => 216, - 0x1D166 => 216, - 0x1D16E => 216, - 0x1D16F => 216, - 0x1D170 => 216, - 0x1D171 => 216, - 0x1D172 => 216, - 0x302A => 218, - 0x316 => 220, - 0x317 => 220, - 0x318 => 220, - 0x319 => 220, - 0x31C => 220, - 0x31D => 220, - 0x31E => 220, - 0x31F => 220, - 0x320 => 220, - 0x323 => 220, - 0x324 => 220, - 0x325 => 220, - 0x326 => 220, - 0x329 => 220, - 0x32A => 220, - 0x32B => 220, - 0x32C => 220, - 0x32D => 220, - 0x32E => 220, - 0x32F => 220, - 0x330 => 220, - 0x331 => 220, - 0x332 => 220, - 0x333 => 220, - 0x339 => 220, - 0x33A => 220, - 0x33B => 220, - 0x33C => 220, - 0x347 => 220, - 0x348 => 220, - 0x349 => 220, - 0x34D => 220, - 0x34E => 220, - 0x353 => 220, - 0x354 => 220, - 0x355 => 220, - 0x356 => 220, - 0x591 => 220, - 0x596 => 220, - 0x59B => 220, - 0x5A3 => 220, - 0x5A4 => 220, - 0x5A5 => 220, - 0x5A6 => 220, - 0x5A7 => 220, - 0x5AA => 220, - 0x655 => 220, - 0x656 => 220, - 0x6E3 => 220, - 0x6EA => 220, - 0x6ED => 220, - 0x731 => 220, - 0x734 => 220, - 0x737 => 220, - 0x738 => 220, - 0x739 => 220, - 0x73B => 220, - 0x73C => 220, - 0x73E => 220, - 0x742 => 220, - 0x744 => 220, - 0x746 => 220, - 0x748 => 220, - 0x952 => 220, - 0xF18 => 220, - 0xF19 => 220, - 0xF35 => 220, - 0xF37 => 220, - 0xFC6 => 220, - 0x193B => 220, - 0x20E8 => 220, - 0x1D17B => 220, - 0x1D17C => 220, - 0x1D17D => 220, - 0x1D17E => 220, - 0x1D17F => 220, - 0x1D180 => 220, - 0x1D181 => 220, - 0x1D182 => 220, - 0x1D18A => 220, - 0x1D18B => 220, - 0x59A => 222, - 0x5AD => 222, - 0x1929 => 222, - 0x302D => 222, - 0x302E => 224, - 0x302F => 224, - 0x1D16D => 226, - 0x5AE => 228, - 0x18A9 => 228, - 0x302B => 228, - 0x300 => 230, - 0x301 => 230, - 0x302 => 230, - 0x303 => 230, - 0x304 => 230, - 0x305 => 230, - 0x306 => 230, - 0x307 => 230, - 0x308 => 230, - 0x309 => 230, - 0x30A => 230, - 0x30B => 230, - 0x30C => 230, - 0x30D => 230, - 0x30E => 230, - 0x30F => 230, - 0x310 => 230, - 0x311 => 230, - 0x312 => 230, - 0x313 => 230, - 0x314 => 230, - 0x33D => 230, - 0x33E => 230, - 0x33F => 230, - 0x340 => 230, - 0x341 => 230, - 0x342 => 230, - 0x343 => 230, - 0x344 => 230, - 0x346 => 230, - 0x34A => 230, - 0x34B => 230, - 0x34C => 230, - 0x350 => 230, - 0x351 => 230, - 0x352 => 230, - 0x357 => 230, - 0x363 => 230, - 0x364 => 230, - 0x365 => 230, - 0x366 => 230, - 0x367 => 230, - 0x368 => 230, - 0x369 => 230, - 0x36A => 230, - 0x36B => 230, - 0x36C => 230, - 0x36D => 230, - 0x36E => 230, - 0x36F => 230, - 0x483 => 230, - 0x484 => 230, - 0x485 => 230, - 0x486 => 230, - 0x592 => 230, - 0x593 => 230, - 0x594 => 230, - 0x595 => 230, - 0x597 => 230, - 0x598 => 230, - 0x599 => 230, - 0x59C => 230, - 0x59D => 230, - 0x59E => 230, - 0x59F => 230, - 0x5A0 => 230, - 0x5A1 => 230, - 0x5A8 => 230, - 0x5A9 => 230, - 0x5AB => 230, - 0x5AC => 230, - 0x5AF => 230, - 0x5C4 => 230, - 0x610 => 230, - 0x611 => 230, - 0x612 => 230, - 0x613 => 230, - 0x614 => 230, - 0x615 => 230, - 0x653 => 230, - 0x654 => 230, - 0x657 => 230, - 0x658 => 230, - 0x6D6 => 230, - 0x6D7 => 230, - 0x6D8 => 230, - 0x6D9 => 230, - 0x6DA => 230, - 0x6DB => 230, - 0x6DC => 230, - 0x6DF => 230, - 0x6E0 => 230, - 0x6E1 => 230, - 0x6E2 => 230, - 0x6E4 => 230, - 0x6E7 => 230, - 0x6E8 => 230, - 0x6EB => 230, - 0x6EC => 230, - 0x730 => 230, - 0x732 => 230, - 0x733 => 230, - 0x735 => 230, - 0x736 => 230, - 0x73A => 230, - 0x73D => 230, - 0x73F => 230, - 0x740 => 230, - 0x741 => 230, - 0x743 => 230, - 0x745 => 230, - 0x747 => 230, - 0x749 => 230, - 0x74A => 230, - 0x951 => 230, - 0x953 => 230, - 0x954 => 230, - 0xF82 => 230, - 0xF83 => 230, - 0xF86 => 230, - 0xF87 => 230, - 0x170D => 230, - 0x193A => 230, - 0x20D0 => 230, - 0x20D1 => 230, - 0x20D4 => 230, - 0x20D5 => 230, - 0x20D6 => 230, - 0x20D7 => 230, - 0x20DB => 230, - 0x20DC => 230, - 0x20E1 => 230, - 0x20E7 => 230, - 0x20E9 => 230, - 0xFE20 => 230, - 0xFE21 => 230, - 0xFE22 => 230, - 0xFE23 => 230, - 0x1D185 => 230, - 0x1D186 => 230, - 0x1D187 => 230, - 0x1D189 => 230, - 0x1D188 => 230, - 0x1D1AA => 230, - 0x1D1AB => 230, - 0x1D1AC => 230, - 0x1D1AD => 230, - 0x315 => 232, - 0x31A => 232, - 0x302C => 232, - 0x35F => 233, - 0x362 => 233, - 0x35D => 234, - 0x35E => 234, - 0x360 => 234, - 0x361 => 234, - 0x345 => 240 - ); - // }}} - - // {{{ properties - /** - * @var string - */ - private $_punycode_prefix = 'xn--'; - - /** - */ - private $_invalid_ucs = 0x80000000; - - /** - */ - private $_max_ucs = 0x10FFFF; - - /** - * @var int - */ - private $_base = 36; - - /** - * @var int - */ - private $_tmin = 1; - - /** - * @var int - */ - private $_tmax = 26; - - /** - * @var int - */ - private $_skew = 38; - - /** - * @var int - */ - private $_damp = 700; - - /** - * @var int - */ - private $_initial_bias = 72; - - /** - * @var int - */ - private $_initial_n = 0x80; - - /** - * @var int - */ - private $_slast; - - /** - */ - private $_sbase = 0xAC00; - - /** - */ - private $_lbase = 0x1100; - - /** - */ - private $_vbase = 0x1161; - - /** - */ - private $_tbase = 0x11a7; - - /** - * @var int - */ - private $_lcount = 19; - - /** - * @var int - */ - private $_vcount = 21; - - /** - * @var int - */ - private $_tcount = 28; - - /** - * vcount * tcount - * - * @var int - */ - private $_ncount = 588; - - /** - * lcount * tcount * vcount - * - * @var int - */ - private $_scount = 11172; - - /** - * Default encoding for encode()'s input and decode()'s output is UTF-8; - * Other possible encodings are ucs4_string and ucs4_array - * See {@link setParams()} for how to select these - * - * @var bool - */ - private $_api_encoding = 'utf8'; - - /** - * Overlong UTF-8 encodings are forbidden - * - * @var bool - */ - private $_allow_overlong = false; - - /** - * Behave strict or not - * - * @var bool - */ - private $_strict_mode = false; - - /** - * IDNA-version to use - * - * Values are "2003" and "2008". - * Defaults to "2003", since that was the original version and for - * compatibility with previous versions of this library. - * If you need to encode "new" characters like the German "Eszett", - * please switch to 2008 first before encoding. - * - * @var bool - */ - private $_version = '2003'; - - /** - * Cached value indicating whether or not mbstring function overloading is - * on for strlen - * - * This is cached for optimal performance. - * - * @var boolean - * @see Net_IDNA2::_byteLength() - */ - private static $_mb_string_overload = null; - // }}} - - - // {{{ constructor - /** - * Constructor - * - * @see setParams() - */ - public function __construct($options = null) - { - $this->_slast = $this->_sbase + $this->_lcount * $this->_vcount * $this->_tcount; - - if (is_array($options)) { - $this->setParams($options); - } - - // populate mbstring overloading cache if not set - if (self::$_mb_string_overload === null) { - self::$_mb_string_overload = (extension_loaded('mbstring') - && (ini_get('mbstring.func_overload') & 0x02) === 0x02); - } - } - // }}} - - - /** - * Sets a new option value. Available options and values: - * - * [utf8 - Use either UTF-8 or ISO-8859-1 as input (true for UTF-8, false - * otherwise); The output is always UTF-8] - * [overlong - Unicode does not allow unnecessarily long encodings of chars, - * to allow this, set this parameter to true, else to false; - * default is false.] - * [strict - true: strict mode, good for registration purposes - Causes errors - * on failures; false: loose mode, ideal for "wildlife" applications - * by silently ignoring errors and returning the original input instead] - * - * @param mixed $option Parameter to set (string: single parameter; array of Parameter => Value pairs) - * - */ - public function setParams($option, $value = false) : bool - { - if (!is_array($option)) { - $option = array($option => $value); - } - - foreach ($option as $k => $v) { - switch ($k) { - case 'encoding': - switch ($v) { - case 'utf8': - case 'ucs4_string': - case 'ucs4_array': - $this->_api_encoding = $v; - break; - - default: - throw new InvalidArgumentException('Set Parameter: Unknown parameter '.$v.' for option '.$k); - } - - break; - - case 'overlong': - $this->_allow_overlong = ($v) ? true : false; - break; - - case 'strict': - $this->_strict_mode = ($v) ? true : false; - break; - - case 'version': - if (in_array($v, array('2003', '2008'))) { - $this->_version = $v; - } else { - throw new InvalidArgumentException('Set Parameter: Invalid parameter '.$v.' for option '.$k); - } - break; - - default: - return false; - } - } - - return true; - } - - /** - * Encode a given UTF-8 domain name. - * - * If not given will use default-encoding - * - * @return mixed processed string - * @throws Exception - */ - public function encode($decoded, $one_time_encoding = false) - { - // Forcing conversion of input to UCS4 array - // If one time encoding is given, use this, else the objects property - switch (($one_time_encoding) ? $one_time_encoding : $this->_api_encoding) { - case 'utf8': - $decoded = $this->_utf8_to_ucs4($decoded); - break; - case 'ucs4_string': - $decoded = $this->_ucs4_string_to_ucs4($decoded); - case 'ucs4_array': // No break; before this line. Catch case, but do nothing - break; - default: - throw new InvalidArgumentException('Unsupported input format'); - } - - // No input, no output, what else did you expect? - if (empty($decoded)) return ''; - - // Anchors for iteration - $last_begin = 0; - // Output string - $output = ''; - - foreach ($decoded as $k => $v) { - // Make sure to use just the plain dot - switch($v) { - case 0x3002: - case 0xFF0E: - case 0xFF61: - $decoded[$k] = 0x2E; - // It's right, no break here - // The codepoints above have to be converted to dots anyway - - // Stumbling across an anchoring character - case 0x2E: - case 0x2F: - case 0x3A: - case 0x3F: - case 0x40: - // Neither email addresses nor URLs allowed in strict mode - if ($this->_strict_mode) { - throw new InvalidArgumentException('Neither email addresses nor URLs are allowed in strict mode.'); - } - // Skip first char - if ($k) { - $encoded = ''; - $encoded = $this->_encode(array_slice($decoded, $last_begin, (($k)-$last_begin))); - if ($encoded) { - $output .= $encoded; - } else { - $output .= $this->_ucs4_to_utf8(array_slice($decoded, $last_begin, (($k)-$last_begin))); - } - $output .= chr($decoded[$k]); - } - $last_begin = $k + 1; - } - } - // Catch the rest of the string - if ($last_begin) { - $inp_len = sizeof($decoded); - $encoded = ''; - $encoded = $this->_encode(array_slice($decoded, $last_begin, (($inp_len)-$last_begin))); - if ($encoded) { - $output .= $encoded; - } else { - $output .= $this->_ucs4_to_utf8(array_slice($decoded, $last_begin, (($inp_len)-$last_begin))); - } - return $output; - } - - if ($output = $this->_encode($decoded)) { - return $output; - } - - return $this->_ucs4_to_utf8($decoded); - } - - /** - * Decode a given ACE domain name. - * - * @throws Exception - */ - public function decode($input, $one_time_encoding = false) - { - // Optionally set - if ($one_time_encoding) { - switch ($one_time_encoding) { - case 'utf8': - case 'ucs4_string': - case 'ucs4_array': - break; - default: - throw new InvalidArgumentException('Unknown encoding '.$one_time_encoding); - } - } - // Make sure to drop any newline characters around - $input = trim($input); - - // Negotiate input and try to determine, wether it is a plain string, - // an email address or something like a complete URL - if (strpos($input, '@')) { // Maybe it is an email address - // No no in strict mode - if ($this->_strict_mode) { - throw new InvalidArgumentException('Only simple domain name parts can be handled in strict mode'); - } - list($email_pref, $input) = explode('@', $input, 2); - $arr = explode('.', $input); - foreach ($arr as $k => $v) { - $conv = $this->_decode($v); - if ($conv) $arr[$k] = $conv; - } - $return = $email_pref . '@' . join('.', $arr); - } elseif (preg_match('![:\./]!', $input)) { // Or a complete domain name (with or without paths / parameters) - // No no in strict mode - if ($this->_strict_mode) { - throw new InvalidArgumentException('Only simple domain name parts can be handled in strict mode'); - } - - $parsed = parse_url($input); - if (isset($parsed['host'])) { - $arr = explode('.', $parsed['host']); - foreach ($arr as $k => $v) { - $conv = $this->_decode($v); - if ($conv) $arr[$k] = $conv; - } - $parsed['host'] = join('.', $arr); - if (isset($parsed['scheme'])) { - $parsed['scheme'] .= (strtolower($parsed['scheme']) == 'mailto') ? ':' : '://'; - } - $return = $this->_unparse_url($parsed); - } else { // parse_url seems to have failed, try without it - $arr = explode('.', $input); - foreach ($arr as $k => $v) { - $conv = $this->_decode($v); - if ($conv) $arr[$k] = $conv; - } - $return = join('.', $arr); - } - } else { // Otherwise we consider it being a pure domain name string - $return = $this->_decode($input); - } - // The output is UTF-8 by default, other output formats need conversion here - // If one time encoding is given, use this, else the objects property - switch (($one_time_encoding) ? $one_time_encoding : $this->_api_encoding) { - case 'utf8': - return $return; - break; - case 'ucs4_string': - return $this->_ucs4_to_ucs4_string($this->_utf8_to_ucs4($return)); - break; - case 'ucs4_array': - return $this->_utf8_to_ucs4($return); - break; - default: - throw new InvalidArgumentException('Unsupported output format'); - } - } - - - // {{{ private - /** - * Opposite function to parse_url() - * - * Inspired by code from comments of php.net-documentation for parse_url() - */ - private function _unparse_url($parts_arr) : string - { - if (!empty($parts_arr['scheme'])) { - $ret_url = $parts_arr['scheme']; - } - if (!empty($parts_arr['user'])) { - $ret_url .= $parts_arr['user']; - if (!empty($parts_arr['pass'])) { - $ret_url .= ':' . $parts_arr['pass']; - } - $ret_url .= '@'; - } - $ret_url .= $parts_arr['host']; - if (!empty($parts_arr['port'])) { - $ret_url .= ':' . $parts_arr['port']; - } - $ret_url .= $parts_arr['path']; - if (!empty($parts_arr['query'])) { - $ret_url .= '?' . $parts_arr['query']; - } - if (!empty($parts_arr['fragment'])) { - $ret_url .= '#' . $parts_arr['fragment']; - } - return $ret_url; - } - - /** - * The actual encoding algorithm. - * - * @throws Exception - */ - private function _encode($decoded) : string - { - // We cannot encode a domain name containing the Punycode prefix - $extract = self::_byteLength($this->_punycode_prefix); - $check_pref = $this->_utf8_to_ucs4($this->_punycode_prefix); - $check_deco = array_slice($decoded, 0, $extract); - - if ($check_pref == $check_deco) { - throw new InvalidArgumentException('This is already a punycode string'); - } - - // We will not try to encode strings consisting of basic code points only - $encodable = false; - foreach ($decoded as $k => $v) { - if ($v > 0x7a) { - $encodable = true; - break; - } - } - if (!$encodable) { - if ($this->_strict_mode) { - throw new InvalidArgumentException('The given string does not contain encodable chars'); - } - - return false; - } - - // Do NAMEPREP - $decoded = $this->_nameprep($decoded); - - $deco_len = count($decoded); - - // Empty array - if (!$deco_len) { - return false; - } - - // How many chars have been consumed - $codecount = 0; - - // Start with the prefix; copy it to output - $encoded = $this->_punycode_prefix; - - $encoded = ''; - // Copy all basic code points to output - for ($i = 0; $i < $deco_len; ++$i) { - $test = $decoded[$i]; - // Will match [0-9a-zA-Z-] - if ((0x2F < $test && $test < 0x40) - || (0x40 < $test && $test < 0x5B) - || (0x60 < $test && $test <= 0x7B) - || (0x2D == $test) - ) { - $encoded .= chr($decoded[$i]); - $codecount++; - } - } - - // All codepoints were basic ones - if ($codecount == $deco_len) { - return $encoded; - } - - // Start with the prefix; copy it to output - $encoded = $this->_punycode_prefix . $encoded; - - // If we have basic code points in output, add an hyphen to the end - if ($codecount) { - $encoded .= '-'; - } - - // Now find and encode all non-basic code points - $is_first = true; - $cur_code = $this->_initial_n; - $bias = $this->_initial_bias; - $delta = 0; - - while ($codecount < $deco_len) { - // Find the smallest code point >= the current code point and - // remember the last ouccrence of it in the input - for ($i = 0, $next_code = $this->_max_ucs; $i < $deco_len; $i++) { - if ($decoded[$i] >= $cur_code && $decoded[$i] <= $next_code) { - $next_code = $decoded[$i]; - } - } - - $delta += ($next_code - $cur_code) * ($codecount + 1); - $cur_code = $next_code; - - // Scan input again and encode all characters whose code point is $cur_code - for ($i = 0; $i < $deco_len; $i++) { - if ($decoded[$i] < $cur_code) { - $delta++; - } else if ($decoded[$i] == $cur_code) { - for ($q = $delta, $k = $this->_base; 1; $k += $this->_base) { - $t = ($k <= $bias)? - $this->_tmin : - (($k >= $bias + $this->_tmax)? $this->_tmax : $k - $bias); - - if ($q < $t) { - break; - } - - $encoded .= $this->_encodeDigit(ceil($t + (($q - $t) % ($this->_base - $t)))); - $q = ($q - $t) / ($this->_base - $t); - } - - $encoded .= $this->_encodeDigit($q); - $bias = $this->_adapt($delta, $codecount + 1, $is_first); - $codecount++; - $delta = 0; - $is_first = false; - } - } - - $delta++; - $cur_code++; - } - - return $encoded; - } - - /** - * The actual decoding algorithm. - * - * @throws Exception - */ - private function _decode($encoded) : string - { - // We do need to find the Punycode prefix - if (!preg_match('!^' . preg_quote($this->_punycode_prefix, '!') . '!', $encoded)) { - return false; - } - - $encode_test = preg_replace('!^' . preg_quote($this->_punycode_prefix, '!') . '!', '', $encoded); - - // If nothing left after removing the prefix, it is hopeless - if (!$encode_test) { - return false; - } - - // Find last occurence of the delimiter - $delim_pos = strrpos($encoded, '-'); - - if ($delim_pos > self::_byteLength($this->_punycode_prefix)) { - for ($k = self::_byteLength($this->_punycode_prefix); $k < $delim_pos; ++$k) { - $decoded[] = ord($encoded[$k]); - } - } else { - $decoded = array(); - } - - $deco_len = count($decoded); - $enco_len = self::_byteLength($encoded); - - // Wandering through the strings; init - $is_first = true; - $bias = $this->_initial_bias; - $idx = 0; - $char = $this->_initial_n; - - for ($enco_idx = ($delim_pos)? ($delim_pos + 1) : 0; $enco_idx < $enco_len; ++$deco_len) { - for ($old_idx = $idx, $w = 1, $k = $this->_base; 1 ; $k += $this->_base) { - $digit = $this->_decodeDigit($encoded[$enco_idx++]); - $idx += $digit * $w; - - $t = ($k <= $bias) ? - $this->_tmin : - (($k >= $bias + $this->_tmax)? $this->_tmax : ($k - $bias)); - - if ($digit < $t) { - break; - } - - $w = (int)($w * ($this->_base - $t)); - } - - $bias = $this->_adapt($idx - $old_idx, $deco_len + 1, $is_first); - $is_first = false; - $char += (int) ($idx / ($deco_len + 1)); - $idx %= ($deco_len + 1); - - if ($deco_len > 0) { - // Make room for the decoded char - for ($i = $deco_len; $i > $idx; $i--) { - $decoded[$i] = $decoded[($i - 1)]; - } - } - - $decoded[$idx++] = $char; - } - - return $this->_ucs4_to_utf8($decoded); - } - - /** - * Adapt the bias according to the current code point and position. - */ - private function _adapt($delta, $npoints, $is_first) : int - { - $delta = (int) ($is_first ? ($delta / $this->_damp) : ($delta / 2)); - $delta += (int) ($delta / $npoints); - - for ($k = 0; $delta > (($this->_base - $this->_tmin) * $this->_tmax) / 2; $k += $this->_base) { - $delta = (int) ($delta / ($this->_base - $this->_tmin)); - } - - return (int) ($k + ($this->_base - $this->_tmin + 1) * $delta / ($delta + $this->_skew)); - } - - /** - * Encoding a certain digit. - * - * @return char Encoded digit - */ - private function _encodeDigit($d) - { - return chr($d + 22 + 75 * ($d < 26)); - } - - /** - * Decode a certain digit. - * - * @param char $cp One digit (character) to decode - */ - private function _decodeDigit($cp) : int - { - $cp = ord($cp); - return ($cp - 48 < 10)? $cp - 22 : (($cp - 65 < 26)? $cp - 65 : (($cp - 97 < 26)? $cp - 97 : $this->_base)); - } - - /** - * Do Nameprep according to RFC3491 and RFC3454. - * - * @throws Exception - */ - private function _nameprep($input) : string - { - $output = array(); - - // Walking through the input array, performing the required steps on each of - // the input chars and putting the result into the output array - // While mapping required chars we apply the cannonical ordering - - foreach ($input as $v) { - // Map to nothing == skip that code point - if (in_array($v, self::$_np_map_nothing)) { - continue; - } - - // Try to find prohibited input - if (in_array($v, self::$_np_prohibit) || in_array($v, self::$_general_prohibited)) { - throw new Net_IDNA2_Exception_Nameprep('Prohibited input U+' . sprintf('%08X', $v)); - } - - foreach (self::$_np_prohibit_ranges as $range) { - if ($range[0] <= $v && $v <= $range[1]) { - throw new Net_IDNA2_Exception_Nameprep('Prohibited input U+' . sprintf('%08X', $v)); - } - } - - // Hangul syllable decomposition - if (0xAC00 <= $v && $v <= 0xD7AF) { - foreach ($this->_hangulDecompose($v) as $out) { - $output[] = $out; - } - } else if (($this->_version == '2003') && isset(self::$_np_replacemaps[$v])) { - // There's a decomposition mapping for that code point - // Decompositions only in version 2003 (original) of IDNA - foreach ($this->_applyCannonicalOrdering(self::$_np_replacemaps[$v]) as $out) { - $output[] = $out; - } - } else { - $output[] = $v; - } - } - - // Combine code points - - $last_class = 0; - $last_starter = 0; - $out_len = count($output); - - for ($i = 0; $i < $out_len; ++$i) { - $class = $this->_getCombiningClass($output[$i]); - - if ((!$last_class || $last_class != $class) && $class) { - // Try to match - $seq_len = $i - $last_starter; - $out = $this->_combine(array_slice($output, $last_starter, $seq_len)); - - // On match: Replace the last starter with the composed character and remove - // the now redundant non-starter(s) - if ($out) { - $output[$last_starter] = $out; - - if (count($out) != $seq_len) { - for ($j = $i + 1; $j < $out_len; ++$j) { - $output[$j - 1] = $output[$j]; - } - - unset($output[$out_len]); - } - - // Rewind the for loop by one, since there can be more possible compositions - $i--; - $out_len--; - $last_class = ($i == $last_starter)? 0 : $this->_getCombiningClass($output[$i - 1]); - - continue; - } - } - - // The current class is 0 - if (!$class) { - $last_starter = $i; - } - - $last_class = $class; - } - - return $output; - } - - /** - * Decomposes a Hangul syllable - * (see http://www.unicode.org/unicode/reports/tr15/#Hangul). - * - * value as one value array - */ - private function _hangulDecompose($char) : array - { - $sindex = $char - $this->_sbase; - - if ($sindex < 0 || $sindex >= $this->_scount) { - return array($char); - } - - $result = array(); - $T = $this->_tbase + $sindex % $this->_tcount; - $result[] = (int)($this->_lbase + $sindex / $this->_ncount); - $result[] = (int)($this->_vbase + ($sindex % $this->_ncount) / $this->_tcount); - - if ($T != $this->_tbase) { - $result[] = $T; - } - - return $result; - } - - /** - * Ccomposes a Hangul syllable - * (see http://www.unicode.org/unicode/reports/tr15/#Hangul). - */ - private function _hangulCompose($input) : array - { - $inp_len = count($input); - - if (!$inp_len) { - return array(); - } - - $result = array(); - $last = $input[0]; - $result[] = $last; // copy first char from input to output - - for ($i = 1; $i < $inp_len; ++$i) { - $char = $input[$i]; - - // Find out, wether two current characters from L and V - $lindex = $last - $this->_lbase; - - if (0 <= $lindex && $lindex < $this->_lcount) { - $vindex = $char - $this->_vbase; - - if (0 <= $vindex && $vindex < $this->_vcount) { - // create syllable of form LV - $last = ($this->_sbase + ($lindex * $this->_vcount + $vindex) * $this->_tcount); - $out_off = count($result) - 1; - $result[$out_off] = $last; // reset last - - // discard char - continue; - } - } - - // Find out, wether two current characters are LV and T - $sindex = $last - $this->_sbase; - - if (0 <= $sindex && $sindex < $this->_scount && ($sindex % $this->_tcount) == 0) { - $tindex = $char - $this->_tbase; - - if (0 <= $tindex && $tindex <= $this->_tcount) { - // create syllable of form LVT - $last += $tindex; - $out_off = count($result) - 1; - $result[$out_off] = $last; // reset last - - // discard char - continue; - } - } - - // if neither case was true, just add the character - $last = $char; - $result[] = $char; - } - - return $result; - } - - /** - * Returns the combining class of a certain wide char. - */ - private function _getCombiningClass($char) : int - { - return isset(self::$_np_norm_combcls[$char])? self::$_np_norm_combcls[$char] : 0; - } - - /** - * Apllies the cannonical ordering of a decomposed UCS4 sequence. - */ - private function _applyCannonicalOrdering($input) : array - { - $swap = true; - $size = count($input); - - while ($swap) { - $swap = false; - $last = $this->_getCombiningClass($input[0]); - - for ($i = 0; $i < $size - 1; ++$i) { - $next = $this->_getCombiningClass($input[$i + 1]); - - if ($next != 0 && $last > $next) { - // Move item leftward until it fits - for ($j = $i + 1; $j > 0; --$j) { - if ($this->_getCombiningClass($input[$j - 1]) <= $next) { - break; - } - - $t = $input[$j]; - $input[$j] = $input[$j - 1]; - $input[$j - 1] = $t; - $swap = 1; - } - - // Reentering the loop looking at the old character again - $next = $last; - } - - $last = $next; - } - } - - return $input; - } - - /** - * Do composition of a sequence of starter and non-starter. - */ - private function _combine($input) : array - { - $inp_len = count($input); - - // Is it a Hangul syllable? - if (1 != $inp_len) { - $hangul = $this->_hangulCompose($input); - - // This place is probably wrong - if (count($hangul) != $inp_len) { - return $hangul; - } - } - - foreach (self::$_np_replacemaps as $np_src => $np_target) { - if ($np_target[0] != $input[0]) { - continue; - } - - if (count($np_target) != $inp_len) { - continue; - } - - $hit = false; - - foreach ($input as $k2 => $v2) { - if ($v2 == $np_target[$k2]) { - $hit = true; - } else { - $hit = false; - break; - } - } - - if ($hit) { - return $np_src; - } - } - - return false; - } - - /** - * This converts an UTF-8 encoded string to its UCS-4 (array) representation - * By talking about UCS-4 we mean arrays of 32bit integers representing - * each of the "chars". This is due to PHP not being able to handle strings with - * bit depth different from 8. This applies to the reverse method _ucs4_to_utf8(), too. - * The following UTF-8 encodings are supported: - * - * bytes bits representation - * 1 7 0xxxxxxx - * 2 11 110xxxxx 10xxxxxx - * 3 16 1110xxxx 10xxxxxx 10xxxxxx - * 4 21 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - * 5 26 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - * 6 31 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - * - * Each x represents a bit that can be used to store character data. - * - * @throws Exception - */ - private function _utf8_to_ucs4($input) : array - { - $output = array(); - $out_len = 0; - $inp_len = self::_byteLength($input, '8bit'); - $mode = 'next'; - $test = 'none'; - for ($k = 0; $k < $inp_len; ++$k) { - $v = ord($input[$k]); // Extract byte from input string - - if ($v < 128) { // We found an ASCII char - put into stirng as is - $output[$out_len] = $v; - ++$out_len; - if ('add' == $mode) { - throw new UnexpectedValueException('Conversion from UTF-8 to UCS-4 failed: malformed input at byte '.$k); - } - continue; - } - if ('next' == $mode) { // Try to find the next start byte; determine the width of the Unicode char - $start_byte = $v; - $mode = 'add'; - $test = 'range'; - if ($v >> 5 == 6) { // &110xxxxx 10xxxxx - $next_byte = 0; // Tells, how many times subsequent bitmasks must rotate 6bits to the left - $v = ($v - 192) << 6; - } elseif ($v >> 4 == 14) { // &1110xxxx 10xxxxxx 10xxxxxx - $next_byte = 1; - $v = ($v - 224) << 12; - } elseif ($v >> 3 == 30) { // &11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - $next_byte = 2; - $v = ($v - 240) << 18; - } elseif ($v >> 2 == 62) { // &111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - $next_byte = 3; - $v = ($v - 248) << 24; - } elseif ($v >> 1 == 126) { // &1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - $next_byte = 4; - $v = ($v - 252) << 30; - } else { - throw new UnexpectedValueException('This might be UTF-8, but I don\'t understand it at byte '.$k); - } - if ('add' == $mode) { - $output[$out_len] = (int) $v; - ++$out_len; - continue; - } - } - if ('add' == $mode) { - if (!$this->_allow_overlong && $test == 'range') { - $test = 'none'; - if (($v < 0xA0 && $start_byte == 0xE0) || ($v < 0x90 && $start_byte == 0xF0) || ($v > 0x8F && $start_byte == 0xF4)) { - throw new OutOfRangeException('Bogus UTF-8 character detected (out of legal range) at byte '.$k); - } - } - if ($v >> 6 == 2) { // Bit mask must be 10xxxxxx - $v = ($v - 128) << ($next_byte * 6); - $output[($out_len - 1)] += $v; - --$next_byte; - } else { - throw new UnexpectedValueException('Conversion from UTF-8 to UCS-4 failed: malformed input at byte '.$k); - } - if ($next_byte < 0) { - $mode = 'next'; - } - } - } // for - return $output; - } - - /** - * Convert UCS-4 array into UTF-8 string - * - * @throws Exception - */ - private function _ucs4_to_utf8($input) : string - { - $output = ''; - - foreach ($input as $v) { - // $v = ord($v); - - if ($v < 128) { - // 7bit are transferred literally - $output .= chr($v); - } else if ($v < 1 << 11) { - // 2 bytes - $output .= chr(192 + ($v >> 6)) - . chr(128 + ($v & 63)); - } else if ($v < 1 << 16) { - // 3 bytes - $output .= chr(224 + ($v >> 12)) - . chr(128 + (($v >> 6) & 63)) - . chr(128 + ($v & 63)); - } else if ($v < 1 << 21) { - // 4 bytes - $output .= chr(240 + ($v >> 18)) - . chr(128 + (($v >> 12) & 63)) - . chr(128 + (($v >> 6) & 63)) - . chr(128 + ($v & 63)); - } else if ($v < 1 << 26) { - // 5 bytes - $output .= chr(248 + ($v >> 24)) - . chr(128 + (($v >> 18) & 63)) - . chr(128 + (($v >> 12) & 63)) - . chr(128 + (($v >> 6) & 63)) - . chr(128 + ($v & 63)); - } else if ($v < 1 << 31) { - // 6 bytes - $output .= chr(252 + ($v >> 30)) - . chr(128 + (($v >> 24) & 63)) - . chr(128 + (($v >> 18) & 63)) - . chr(128 + (($v >> 12) & 63)) - . chr(128 + (($v >> 6) & 63)) - . chr(128 + ($v & 63)); - } else { - throw new UnexpectedValueException('Conversion from UCS-4 to UTF-8 failed: malformed input'); - } - } - - return $output; - } - - /** - * Convert UCS-4 array into UCS-4 string - * - * @throws Exception - */ - private function _ucs4_to_ucs4_string($input) : string - { - $output = ''; - // Take array values and split output to 4 bytes per value - // The bit mask is 255, which reads &11111111 - foreach ($input as $v) { - $output .= ($v & (255 << 24) >> 24) . ($v & (255 << 16) >> 16) . ($v & (255 << 8) >> 8) . ($v & 255); - } - return $output; - } - - /** - * Convert UCS-4 string into UCS-4 array - * - * @throws InvalidArgumentException - */ - private function _ucs4_string_to_ucs4($input) : array - { - $output = array(); - - $inp_len = self::_byteLength($input); - // Input length must be dividable by 4 - if ($inp_len % 4) { - throw new InvalidArgumentException('Input UCS4 string is broken'); - } - - // Empty input - return empty output - if (!$inp_len) { - return $output; - } - - for ($i = 0, $out_len = -1; $i < $inp_len; ++$i) { - // Increment output position every 4 input bytes - if (!$i % 4) { - $out_len++; - $output[$out_len] = 0; - } - $output[$out_len] += ord($input[$i]) << (8 * (3 - ($i % 4) ) ); - } - return $output; - } - - /** - * Echo hex representation of UCS4 sequence. - */ - private static function _showHex($input, $include_bit = false) : void - { - foreach ($input as $k => $v) { - echo '[', $k, '] => ', sprintf('%X', $v); - - if ($include_bit) { - echo ' (', Net_IDNA2::_showBitmask($v), ')'; - } - - echo "\n"; - } - } - - /** - * Gives you a bit representation of given Byte (8 bits), Word (16 bits) or DWord (32 bits) - * Output width is automagically determined - */ - private static function _showBitmask($octet) : string - { - if ($octet >= (1 << 16)) { - $w = 31; - } else if ($octet >= (1 << 8)) { - $w = 15; - } else { - $w = 7; - } - - $return = ''; - - for ($i = $w; $i > -1; $i--) { - $return .= ($octet & (1 << $i))? '1' : '0'; - } - - return $return; - } - - /** - * Gets the length of a string in bytes even if mbstring function - * overloading is turned on - * - * @see Net_IDNA2::$_mb_string_overload - */ - private static function _byteLength($string) : int - { - if (self::$_mb_string_overload) { - return mb_strlen($string, '8bit'); - } - return strlen((binary)$string); - } - - // }}}} - - // {{{ factory - /** - * Attempts to return a concrete IDNA instance for either php4 or php5. - * - * @return Net_IDNA2 - */ - function getInstance($params = array()) - { - return new Net_IDNA2($params); - } - // }}} - - // {{{ singleton - /** - * Attempts to return a concrete IDNA instance for either php4 or php5, - * only creating a new instance if no IDNA instance with the same - * parameters currently exists. - * - * @return object Net_IDNA2 - */ - function singleton($params = array()) - { - static $instances; - if (!isset($instances)) { - $instances = array(); - } - - $signature = serialize($params); - if (!isset($instances[$signature])) { - $instances[$signature] = Net_IDNA2::getInstance($params); - } - - return $instances[$signature]; - } - // }}} -} diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Vendors/Net/IDNA2CustomExceptions.php b/snappymail/v/0.0.0/app/libraries/MailSo/Vendors/Net/IDNA2CustomExceptions.php deleted file mode 100644 index 69b0f6914..000000000 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Vendors/Net/IDNA2CustomExceptions.php +++ /dev/null @@ -1,18 +0,0 @@ - - * Copyright (c) 2009, Ian Selby/Gen X Design - * - * Author(s): Ian Selby - * - * Licensed under the MIT License - * Redistributions of files must retain the above copyright notice. - * - * @author Ian Selby - * @copyright Copyright (c) 2009 Gen X Design - * @link http://phpthumb.gxdlabs.com - * @license http://www.opensource.org/licenses/mit-license.php The MIT License - */ - -class GD extends PHPThumb -{ - /** - * The prior image (before manipulation) - * - * @var resource - */ - protected $oldImage; - - /** - * The working image (used during manipulation) - * - * @var resource - */ - protected $workingImage; - - /** - * The current dimensions of the image - * - * @var array - */ - protected $currentDimensions; - - /** - * The new, calculated dimensions of the image - * - * @var array - */ - protected $newDimensions; - - /** - * The options for this class - * - * This array contains various options that determine the behavior in - * various functions throughout the class. Functions note which specific - * option key / values are used in their documentation - * - * @var array - */ - protected $options; - - /** - * The maximum width an image can be after resizing (in pixels) - * - * @var int - */ - protected $maxWidth; - - /** - * The maximum height an image can be after resizing (in pixels) - * - * @var int - */ - protected $maxHeight; - - /** - * The percentage to resize the image by - * - * @var int - */ - protected $percent; - - /** - * @param string $fileName - * @param array $options - * @param array $plugins - */ - public function __construct($fileName, $options = array(), array $plugins = array()) - { - parent::__construct($fileName, $options, $plugins); - - $this->determineFormat(); - $this->verifyFormatCompatiblity(); - - switch ($this->format) { - case 'GIF': - $this->oldImage = @imagecreatefromgif($this->fileName); - break; - case 'JPG': - $this->oldImage = @imagecreatefromjpeg($this->fileName); - break; - case 'PNG': - $this->oldImage = @imagecreatefrompng($this->fileName); - break; - case 'STRING': - $this->oldImage = @imagecreatefromstring($this->fileName); - break; - } - - if (!is_resource($this->oldImage)) - { - throw new \Exception('Invalid image file'); - } - else - { - $this->currentDimensions = array ( - 'width' => imagesx($this->oldImage), - 'height' => imagesy($this->oldImage) - ); - } - } - - public function __destruct() - { - if (is_resource($this->oldImage)) { - imagedestroy($this->oldImage); - } - - if (is_resource($this->workingImage)) { - imagedestroy($this->workingImage); - } - } - - /** - * Pad an image to desired dimensions. Moves the image into the center and fills the rest with $color. - * @param $width - * @param $height - * @param array $color - * @return GD - */ - public function pad($width, $height, $color = array(255, 255, 255)) - { - // no resize - woohoo! - if ($width == $this->currentDimensions['width'] && $height == $this->currentDimensions['height']) { - return $this; - } - - // create the working image - if (function_exists('imagecreatetruecolor')) { - $this->workingImage = imagecreatetruecolor($width, $height); - } else { - $this->workingImage = imagecreate($width, $height); - } - - // create the fill color - $fillColor = imagecolorallocate( - $this->workingImage, - $color[0], - $color[1], - $color[2] - ); - - // fill our working image with the fill color - imagefill( - $this->workingImage, - 0, - 0, - $fillColor - ); - - // copy the image into the center of our working image - imagecopyresampled( - $this->workingImage, - $this->oldImage, - intval(($width-$this->currentDimensions['width']) / 2), - intval(($height-$this->currentDimensions['height']) / 2), - 0, - 0, - $this->currentDimensions['width'], - $this->currentDimensions['height'], - $this->currentDimensions['width'], - $this->currentDimensions['height'] - ); - - // update all the variables and resources to be correct - $this->oldImage = $this->workingImage; - $this->currentDimensions['width'] = $width; - $this->currentDimensions['height'] = $height; - - return $this; - } - - /** - * Resizes an image to be no larger than $maxWidth or $maxHeight - * - * If either param is set to zero, then that dimension will not be considered as a part of the resize. - * Additionally, if $this->options['resizeUp'] is set to true (false by default), then this function will - * also scale the image up to the maximum dimensions provided. - * - * @param int $maxWidth The maximum width of the image in pixels - * @param int $maxHeight The maximum height of the image in pixels - * @return \PHPThumb\GD - */ - public function resize($maxWidth = 0, $maxHeight = 0) - { - // make sure our arguments are valid - if (!is_numeric($maxWidth)) { - throw new \InvalidArgumentException('$maxWidth must be numeric'); - } - - if (!is_numeric($maxHeight)) { - throw new \InvalidArgumentException('$maxHeight must be numeric'); - } - - // make sure we're not exceeding our image size if we're not supposed to - if ($this->options['resizeUp'] === false) { - $this->maxHeight = (intval($maxHeight) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $maxHeight; - $this->maxWidth = (intval($maxWidth) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $maxWidth; - } else { - $this->maxHeight = intval($maxHeight); - $this->maxWidth = intval($maxWidth); - } - - // get the new dimensions... - $this->calcImageSize($this->currentDimensions['width'], $this->currentDimensions['height']); - - // create the working image - if (function_exists('imagecreatetruecolor')) { - $this->workingImage = imagecreatetruecolor($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); - } else { - $this->workingImage = imagecreate($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); - } - - $this->preserveAlpha(); - - // and create the newly sized image - imagecopyresampled( - $this->workingImage, - $this->oldImage, - 0, - 0, - 0, - 0, - $this->newDimensions['newWidth'], - $this->newDimensions['newHeight'], - $this->currentDimensions['width'], - $this->currentDimensions['height'] - ); - - // update all the variables and resources to be correct - $this->oldImage = $this->workingImage; - $this->currentDimensions['width'] = $this->newDimensions['newWidth']; - $this->currentDimensions['height'] = $this->newDimensions['newHeight']; - - return $this; - } - - /** - * Adaptively Resizes the Image - * - * This function attempts to get the image to as close to the provided dimensions as possible, and then crops the - * remaining overflow (from the center) to get the image to be the size specified - * - * @param int $maxWidth - * @param int $maxHeight - * @return \PHPThumb\GD - */ - public function adaptiveResize($width, $height) - { - // make sure our arguments are valid - if ((!is_numeric($width) || $width == 0) && (!is_numeric($height) || $height == 0)) { - throw new \InvalidArgumentException('$width and $height must be numeric and greater than zero'); - } - - if (!is_numeric($width) || $width == 0) { - $width = ($height * $this->currentDimensions['width']) / $this->currentDimensions['height']; - } - - if (!is_numeric($height) || $height == 0) { - $height = ($width * $this->currentDimensions['height']) / $this->currentDimensions['width']; - } - - // make sure we're not exceeding our image size if we're not supposed to - if ($this->options['resizeUp'] === false) { - $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; - $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; - } else { - $this->maxHeight = intval($height); - $this->maxWidth = intval($width); - } - - $this->calcImageSizeStrict($this->currentDimensions['width'], $this->currentDimensions['height']); - - // resize the image to be close to our desired dimensions - $this->resize($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); - - // reset the max dimensions... - if ($this->options['resizeUp'] === false) { - $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; - $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; - } else { - $this->maxHeight = intval($height); - $this->maxWidth = intval($width); - } - - // create the working image - if (function_exists('imagecreatetruecolor')) { - $this->workingImage = imagecreatetruecolor($this->maxWidth, $this->maxHeight); - } else { - $this->workingImage = imagecreate($this->maxWidth, $this->maxHeight); - } - - $this->preserveAlpha(); - - $cropWidth = $this->maxWidth; - $cropHeight = $this->maxHeight; - $cropX = 0; - $cropY = 0; - - // now, figure out how to crop the rest of the image... - if ($this->currentDimensions['width'] > $this->maxWidth) { - $cropX = intval(($this->currentDimensions['width'] - $this->maxWidth) / 2); - } elseif ($this->currentDimensions['height'] > $this->maxHeight) { - $cropY = intval(($this->currentDimensions['height'] - $this->maxHeight) / 2); - } - - imagecopyresampled( - $this->workingImage, - $this->oldImage, - 0, - 0, - $cropX, - $cropY, - $cropWidth, - $cropHeight, - $cropWidth, - $cropHeight - ); - - // update all the variables and resources to be correct - $this->oldImage = $this->workingImage; - $this->currentDimensions['width'] = $this->maxWidth; - $this->currentDimensions['height'] = $this->maxHeight; - - return $this; - } - - /** - * Adaptively Resizes the Image and Crops Using a Percentage - * - * This function attempts to get the image to as close to the provided dimensions as possible, and then crops the - * remaining overflow using a provided percentage to get the image to be the size specified. - * - * The percentage mean different things depending on the orientation of the original image. - * - * For Landscape images: - * --------------------- - * - * A percentage of 1 would crop the image all the way to the left, which would be the same as - * using adaptiveResizeQuadrant() with $quadrant = 'L' - * - * A percentage of 50 would crop the image to the center which would be the same as using - * adaptiveResizeQuadrant() with $quadrant = 'C', or even the original adaptiveResize() - * - * A percentage of 100 would crop the image to the image all the way to the right, etc, etc. - * Note that you can use any percentage between 1 and 100. - * - * For Portrait images: - * -------------------- - * - * This works the same as for Landscape images except that a percentage of 1 means top and 100 means bottom - * - * @param int $maxWidth - * @param int $maxHeight - * @param int $percent - * @return \PHPThumb\GD - */ - public function adaptiveResizePercent($width, $height, $percent = 50) - { - // make sure our arguments are valid - if (!is_numeric($width) || $width == 0) { - throw new \InvalidArgumentException('$width must be numeric and greater than zero'); - } - - if (!is_numeric($height) || $height == 0) { - throw new \InvalidArgumentException('$height must be numeric and greater than zero'); - } - - // make sure we're not exceeding our image size if we're not supposed to - if ($this->options['resizeUp'] === false) { - $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; - $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; - } else { - $this->maxHeight = intval($height); - $this->maxWidth = intval($width); - } - - $this->calcImageSizeStrict($this->currentDimensions['width'], $this->currentDimensions['height']); - - // resize the image to be close to our desired dimensions - $this->resize($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); - - // reset the max dimensions... - if ($this->options['resizeUp'] === false) { - $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; - $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; - } else { - $this->maxHeight = intval($height); - $this->maxWidth = intval($width); - } - - // create the working image - if (function_exists('imagecreatetruecolor')) { - $this->workingImage = imagecreatetruecolor($this->maxWidth, $this->maxHeight); - } else { - $this->workingImage = imagecreate($this->maxWidth, $this->maxHeight); - } - - $this->preserveAlpha(); - - $cropWidth = $this->maxWidth; - $cropHeight = $this->maxHeight; - $cropX = 0; - $cropY = 0; - - // Crop the rest of the image using the quadrant - - if ($percent > 100) { - $percent = 100; - } elseif ($percent < 1) { - $percent = 1; - } - - if ($this->currentDimensions['width'] > $this->maxWidth) { - // Image is landscape - $maxCropX = $this->currentDimensions['width'] - $this->maxWidth; - $cropX = intval(($percent / 100) * $maxCropX); - - } elseif ($this->currentDimensions['height'] > $this->maxHeight) { - // Image is portrait - $maxCropY = $this->currentDimensions['height'] - $this->maxHeight; - $cropY = intval(($percent / 100) * $maxCropY); - } - - imagecopyresampled( - $this->workingImage, - $this->oldImage, - 0, - 0, - $cropX, - $cropY, - $cropWidth, - $cropHeight, - $cropWidth, - $cropHeight - ); - - // update all the variables and resources to be correct - $this->oldImage = $this->workingImage; - $this->currentDimensions['width'] = $this->maxWidth; - $this->currentDimensions['height'] = $this->maxHeight; - - return $this; - } - - /** - * Adaptively Resizes the Image and Crops Using a Quadrant - * - * This function attempts to get the image to as close to the provided dimensions as possible, and then crops the - * remaining overflow using the quadrant to get the image to be the size specified. - * - * The quadrants available are Top, Bottom, Center, Left, and Right: - * - * - * +---+---+---+ - * | | T | | - * +---+---+---+ - * | L | C | R | - * +---+---+---+ - * | | B | | - * +---+---+---+ - * - * Note that if your image is Landscape and you choose either of the Top or Bottom quadrants (which won't - * make sence since only the Left and Right would be available, then the Center quadrant will be used - * to crop. This would have exactly the same result as using adaptiveResize(). - * The same goes if your image is portrait and you choose either the Left or Right quadrants. - * - * @param int $maxWidth - * @param int $maxHeight - * @param string $quadrant T, B, C, L, R - * @return \PHPThumb\GD - */ - public function adaptiveResizeQuadrant($width, $height, $quadrant = 'C') - { - // make sure our arguments are valid - if (!is_numeric($width) || $width == 0) { - throw new \InvalidArgumentException('$width must be numeric and greater than zero'); - } - - if (!is_numeric($height) || $height == 0) { - throw new \InvalidArgumentException('$height must be numeric and greater than zero'); - } - - // make sure we're not exceeding our image size if we're not supposed to - if ($this->options['resizeUp'] === false) { - $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; - $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; - } else { - $this->maxHeight = intval($height); - $this->maxWidth = intval($width); - } - - $this->calcImageSizeStrict($this->currentDimensions['width'], $this->currentDimensions['height']); - - // resize the image to be close to our desired dimensions - $this->resize($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); - - // reset the max dimensions... - if ($this->options['resizeUp'] === false) { - $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height; - $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width; - } else { - $this->maxHeight = intval($height); - $this->maxWidth = intval($width); - } - - // create the working image - if (function_exists('imagecreatetruecolor')) { - $this->workingImage = imagecreatetruecolor($this->maxWidth, $this->maxHeight); - } else { - $this->workingImage = imagecreate($this->maxWidth, $this->maxHeight); - } - - $this->preserveAlpha(); - - $cropWidth = $this->maxWidth; - $cropHeight = $this->maxHeight; - $cropX = 0; - $cropY = 0; - - // Crop the rest of the image using the quadrant - - if ($this->currentDimensions['width'] > $this->maxWidth) { - // Image is landscape - switch ($quadrant) { - case 'L': - $cropX = 0; - break; - case 'R': - $cropX = intval(($this->currentDimensions['width'] - $this->maxWidth)); - break; - case 'C': - default: - $cropX = intval(($this->currentDimensions['width'] - $this->maxWidth) / 2); - break; - } - } elseif ($this->currentDimensions['height'] > $this->maxHeight) { - // Image is portrait - switch ($quadrant) { - case 'T': - $cropY = 0; - break; - case 'B': - $cropY = intval(($this->currentDimensions['height'] - $this->maxHeight)); - break; - case 'C': - default: - $cropY = intval(($this->currentDimensions['height'] - $this->maxHeight) / 2); - break; - } - } - - imagecopyresampled( - $this->workingImage, - $this->oldImage, - 0, - 0, - $cropX, - $cropY, - $cropWidth, - $cropHeight, - $cropWidth, - $cropHeight - ); - - // update all the variables and resources to be correct - $this->oldImage = $this->workingImage; - $this->currentDimensions['width'] = $this->maxWidth; - $this->currentDimensions['height'] = $this->maxHeight; - - return $this; - } - - /** - * Resizes an image by a given percent uniformly, - * Percentage should be whole number representation (i.e. 1-100) - * - * @param int $percent - * @return GD - * @throws \InvalidArgumentException - */ - public function resizePercent($percent = 0) - { - if (!is_numeric($percent)) { - throw new \InvalidArgumentException ('$percent must be numeric'); - } - - $this->percent = intval($percent); - - $this->calcImageSizePercent($this->currentDimensions['width'], $this->currentDimensions['height']); - - if (function_exists('imagecreatetruecolor')) { - $this->workingImage = imagecreatetruecolor($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); - } else { - $this->workingImage = imagecreate($this->newDimensions['newWidth'], $this->newDimensions['newHeight']); - } - - $this->preserveAlpha(); - - imagecopyresampled( - $this->workingImage, - $this->oldImage, - 0, - 0, - 0, - 0, - $this->newDimensions['newWidth'], - $this->newDimensions['newHeight'], - $this->currentDimensions['width'], - $this->currentDimensions['height'] - ); - - $this->oldImage = $this->workingImage; - $this->currentDimensions['width'] = $this->newDimensions['newWidth']; - $this->currentDimensions['height'] = $this->newDimensions['newHeight']; - - return $this; - } - - /** - * Crops an image from the center with provided dimensions - * - * If no height is given, the width will be used as a height, thus creating a square crop - * - * @param int $cropWidth - * @param int $cropHeight - * @return \PHPThumb\GD - */ - public function cropFromCenter($cropWidth, $cropHeight = null) - { - if (!is_numeric($cropWidth)) { - throw new \InvalidArgumentException('$cropWidth must be numeric'); - } - - if ($cropHeight !== null && !is_numeric($cropHeight)) { - throw new \InvalidArgumentException('$cropHeight must be numeric'); - } - - if ($cropHeight === null) { - $cropHeight = $cropWidth; - } - - $cropWidth = ($this->currentDimensions['width'] < $cropWidth) ? $this->currentDimensions['width'] : $cropWidth; - $cropHeight = ($this->currentDimensions['height'] < $cropHeight) ? $this->currentDimensions['height'] : $cropHeight; - - $cropX = intval(($this->currentDimensions['width'] - $cropWidth) / 2); - $cropY = intval(($this->currentDimensions['height'] - $cropHeight) / 2); - - $this->crop($cropX, $cropY, $cropWidth, $cropHeight); - - return $this; - } - - /** - * Vanilla Cropping - Crops from x,y with specified width and height - * - * @param int $startX - * @param int $startY - * @param int $cropWidth - * @param int $cropHeight - * @return \PHPThumb\GD - */ - public function crop($startX, $startY, $cropWidth, $cropHeight) - { - // validate input - if (!is_numeric($startX)) { - throw new \InvalidArgumentException('$startX must be numeric'); - } - - if (!is_numeric($startY)) { - throw new \InvalidArgumentException('$startY must be numeric'); - } - - if (!is_numeric($cropWidth)) { - throw new \InvalidArgumentException('$cropWidth must be numeric'); - } - - if (!is_numeric($cropHeight)) { - throw new \InvalidArgumentException('$cropHeight must be numeric'); - } - - // do some calculations - $cropWidth = ($this->currentDimensions['width'] < $cropWidth) ? $this->currentDimensions['width'] : $cropWidth; - $cropHeight = ($this->currentDimensions['height'] < $cropHeight) ? $this->currentDimensions['height'] : $cropHeight; - - // ensure everything's in bounds - if (($startX + $cropWidth) > $this->currentDimensions['width']) { - $startX = ($this->currentDimensions['width'] - $cropWidth); - } - - if (($startY + $cropHeight) > $this->currentDimensions['height']) { - $startY = ($this->currentDimensions['height'] - $cropHeight); - } - - if ($startX < 0) { - $startX = 0; - } - - if ($startY < 0) { - $startY = 0; - } - - // create the working image - if (function_exists('imagecreatetruecolor')) { - $this->workingImage = imagecreatetruecolor($cropWidth, $cropHeight); - } else { - $this->workingImage = imagecreate($cropWidth, $cropHeight); - } - - $this->preserveAlpha(); - - imagecopyresampled( - $this->workingImage, - $this->oldImage, - 0, - 0, - $startX, - $startY, - $cropWidth, - $cropHeight, - $cropWidth, - $cropHeight - ); - - $this->oldImage = $this->workingImage; - $this->currentDimensions['width'] = $cropWidth; - $this->currentDimensions['height'] = $cropHeight; - - return $this; - } - - /** - * Rotates image either 90 degrees clockwise or counter-clockwise - * - * @param string $direction - * @retunrn \PHPThumb\GD - */ - public function rotateImage($direction = 'CW') - { - if ($direction == 'CW') { - $this->rotateImageNDegrees(90); - } else { - $this->rotateImageNDegrees(-90); - } - - return $this; - } - - /** - * Rotates image specified number of degrees - * - * @param int $degrees - * @return \PHPThumb\GD - */ - public function rotateImageNDegrees($degrees) - { - if (!is_numeric($degrees)) { - throw new \InvalidArgumentException('$degrees must be numeric'); - } - - if (!function_exists('imagerotate')) { - throw new \RuntimeException('Your version of GD does not support image rotation'); - } - - $this->workingImage = imagerotate($this->oldImage, $degrees, 0); - - $newWidth = $this->currentDimensions['height']; - $newHeight = $this->currentDimensions['width']; - $this->oldImage = $this->workingImage; - $this->currentDimensions['width'] = $newWidth; - $this->currentDimensions['height'] = $newHeight; - - return $this; - } - - /** - * Applies a filter to the image - * - * @param int $filter - * @return \PHPThumb\GD - */ - public function imageFilter($filter, $arg1 = false, $arg2 = false, $arg3 = false, $arg4 = false) - { - if (!is_numeric($filter)) { - throw new \InvalidArgumentException('$filter must be numeric'); - } - - if (!function_exists('imagefilter')) { - throw new \RuntimeException('Your version of GD does not support image filters'); - } - - $result = false; - if ($arg1 === false) { - $result = imagefilter($this->oldImage, $filter); - } elseif ($arg2 === false) { - $result = imagefilter($this->oldImage, $filter, $arg1); - } elseif ($arg3 === false) { - $result = imagefilter($this->oldImage, $filter, $arg1, $arg2); - } elseif ($arg4 === false) { - $result = imagefilter($this->oldImage, $filter, $arg1, $arg2, $arg3); - } else { - $result = imagefilter($this->oldImage, $filter, $arg1, $arg2, $arg3, $arg4); - } - - if (!$result) { - throw new \RuntimeException('GD imagefilter failed'); - } - - $this->workingImage = $this->oldImage; - - return $this; - } - - /** - * Shows an image - * - * This function will show the current image by first sending the appropriate header - * for the format, and then outputting the image data. If headers have already been sent, - * a runtime exception will be thrown - * - * @param bool $rawData Whether or not the raw image stream should be output - * @return \PHPThumb\GD - */ - public function show($rawData = false) - { - //Execute any plugins - if ($this->plugins) { - foreach ($this->plugins as $plugin) { - /* @var $plugin \PHPThumb\PluginInterface */ - $plugin->execute($this); - } - } - - if (headers_sent() && php_sapi_name() != 'cli') { - throw new \RuntimeException('Cannot show image, headers have already been sent'); - } - - // When the interlace option equals true or false call imageinterlace else leave it to default - if ($this->options['interlace'] === true) { - imageinterlace($this->oldImage, 1); - } elseif ($this->options['interlace'] === false) { - imageinterlace($this->oldImage, 0); - } - - switch ($this->format) { - case 'GIF': - if ($rawData === false) { - header('Content-type: image/gif'); - } - imagegif($this->oldImage); - break; - case 'JPG': - if ($rawData === false) { - header('Content-type: image/jpeg'); - } - imagejpeg($this->oldImage, null, $this->options['jpegQuality']); - break; - case 'PNG': - case 'STRING': - if ($rawData === false) { - header('Content-type: image/png'); - } - imagepng($this->oldImage); - break; - } - - return $this; - } - - /** - * Returns the Working Image as a String - * - * This function is useful for getting the raw image data as a string for storage in - * a database, or other similar things. - * - * @return string - */ - public function getImageAsString() - { - $data = null; - ob_start(); - $this->show(true); - $data = ob_get_contents(); - ob_end_clean(); - - return $data; - } - - /** - * Saves an image - * - * This function will make sure the target directory is writeable, and then save the image. - * - * If the target directory is not writeable, the function will try to correct the permissions (if allowed, this - * is set as an option ($this->options['correctPermissions']). If the target cannot be made writeable, then a - * \RuntimeException is thrown. - * - * @param string $fileName The full path and filename of the image to save - * @param string $format The format to save the image in (optional, must be one of [GIF,JPG,PNG] - * @return \PHPThumb\GD - */ - public function save($fileName, $format = null) - { - $validFormats = array('GIF', 'JPG', 'PNG'); - $format = ($format !== null) ? strtoupper($format) : $this->format; - - if (!in_array($format, $validFormats)) { - throw new \InvalidArgumentException("Invalid format type specified in save function: {$format}"); - } - - // make sure the directory is writeable - if (!is_writeable(dirname($fileName))) { - // try to correct the permissions - if ($this->options['correctPermissions'] === true) { - @chmod(dirname($fileName), 0777); - - // throw an exception if not writeable - if (!is_writeable(dirname($fileName))) { - throw new \RuntimeException("File is not writeable, and could not correct permissions: {$fileName}"); - } - } else { // throw an exception if not writeable - throw new \RuntimeException("File not writeable: {$fileName}"); - } - } - - // When the interlace option equals true or false call imageinterlace else leave it to default - if ($this->options['interlace'] === true) { - imageinterlace($this->oldImage, 1); - } elseif ($this->options['interlace'] === false) { - imageinterlace($this->oldImage, 0); - } - - switch ($format) { - case 'GIF': - imagegif($this->oldImage, $fileName); - break; - case 'JPG': - imagejpeg($this->oldImage, $fileName, $this->options['jpegQuality']); - break; - case 'PNG': - imagepng($this->oldImage, $fileName); - break; - } - - return $this; - } - - ################################# - # ----- GETTERS / SETTERS ----- # - ################################# - - /** - * Sets options for all operations. - * @param array $options - * @return GD - */ - public function setOptions(array $options = array()) - { - // we've yet to init the default options, so create them here - if (sizeof($this->options) == 0) { - $defaultOptions = array( - 'resizeUp' => false, - 'jpegQuality' => 100, - 'correctPermissions' => false, - 'preserveAlpha' => true, - 'alphaMaskColor' => array (255, 255, 255), - 'preserveTransparency' => true, - 'transparencyMaskColor' => array (0, 0, 0), - 'interlace' => null - ); - } else { // otherwise, let's use what we've got already - $defaultOptions = $this->options; - } - - $this->options = array_merge($defaultOptions, $options); - - return $this; - } - - /** - * Returns $currentDimensions. - * - * @see \PHPThumb\GD::$currentDimensions - */ - public function getCurrentDimensions() - { - return $this->currentDimensions; - } - - /** - * @param $currentDimensions - * @return GD - */ - public function setCurrentDimensions($currentDimensions) - { - $this->currentDimensions = $currentDimensions; - - return $this; - } - - /** - * @return int - */ - public function getMaxHeight() - { - return $this->maxHeight; - } - - /** - * @param $maxHeight - * @return GD - */ - public function setMaxHeight($maxHeight) - { - $this->maxHeight = $maxHeight; - - return $this; - } - - /** - * @return int - */ - public function getMaxWidth() - { - return $this->maxWidth; - } - - /** - * @param $maxWidth - * @return GD - */ - public function setMaxWidth($maxWidth) - { - $this->maxWidth = $maxWidth; - - return $this; - } - - /** - * Returns $newDimensions. - * - * @see \PHPThumb\GD::$newDimensions - */ - public function getNewDimensions() - { - return $this->newDimensions; - } - - /** - * Sets $newDimensions. - * - * @param object $newDimensions - * @see \PHPThumb\GD::$newDimensions - */ - public function setNewDimensions($newDimensions) - { - $this->newDimensions = $newDimensions; - - return $this; - } - - /** - * Returns $options. - * - * @see \PHPThumb\GD::$options - */ - public function getOptions() - { - return $this->options; - } - - /** - * Returns $percent. - * - * @see \PHPThumb\GD::$percent - */ - public function getPercent() - { - return $this->percent; - } - - /** - * Sets $percent. - * - * @param object $percent - * @see \PHPThumb\GD::$percent - */ - public function setPercent($percent) - { - $this->percent = $percent; - - return $this; - } - - /** - * Returns $oldImage. - * - * @see \PHPThumb\GD::$oldImage - */ - public function getOldImage() - { - return $this->oldImage; - } - - /** - * Sets $oldImage. - * - * @param object $oldImage - * @see \PHPThumb\GD::$oldImage - */ - public function setOldImage($oldImage) - { - $this->oldImage = $oldImage; - - return $this; - } - - /** - * Returns $workingImage. - * - * @see \PHPThumb\GD::$workingImage - */ - public function getWorkingImage() - { - return $this->workingImage; - } - - /** - * Sets $workingImage. - * - * @param object $workingImage - * @see \PHPThumb\GD::$workingImage - */ - public function setWorkingImage($workingImage) - { - $this->workingImage = $workingImage; - - return $this; - } - - - ################################# - # ----- UTILITY FUNCTIONS ----- # - ################################# - - /** - * Calculates a new width and height for the image based on $this->maxWidth and the provided dimensions - * - * @return array - * @param int $width - * @param int $height - */ - protected function calcWidth($width, $height) - { - $newWidthPercentage = (100 * $this->maxWidth) / $width; - $newHeight = ($height * $newWidthPercentage) / 100; - - return array( - 'newWidth' => intval($this->maxWidth), - 'newHeight' => intval($newHeight) - ); - } - - /** - * Calculates a new width and height for the image based on $this->maxWidth and the provided dimensions - * - * @return array - * @param int $width - * @param int $height - */ - protected function calcHeight($width, $height) - { - $newHeightPercentage = (100 * $this->maxHeight) / $height; - $newWidth = ($width * $newHeightPercentage) / 100; - - return array( - 'newWidth' => ceil($newWidth), - 'newHeight' => ceil($this->maxHeight) - ); - } - - /** - * Calculates a new width and height for the image based on $this->percent and the provided dimensions - * - * @return array - * @param int $width - * @param int $height - */ - protected function calcPercent($width, $height) - { - $newWidth = ($width * $this->percent) / 100; - $newHeight = ($height * $this->percent) / 100; - - return array( - 'newWidth' => ceil($newWidth), - 'newHeight' => ceil($newHeight) - ); - } - - /** - * Calculates the new image dimensions - * - * These calculations are based on both the provided dimensions and $this->maxWidth and $this->maxHeight - * - * @param int $width - * @param int $height - */ - protected function calcImageSize($width, $height) - { - $newSize = array( - 'newWidth' => $width, - 'newHeight' => $height - ); - - if ($this->maxWidth > 0) { - $newSize = $this->calcWidth($width, $height); - - if ($this->maxHeight > 0 && $newSize['newHeight'] > $this->maxHeight) { - $newSize = $this->calcHeight($newSize['newWidth'], $newSize['newHeight']); - } - } - - if ($this->maxHeight > 0) { - $newSize = $this->calcHeight($width, $height); - - if ($this->maxWidth > 0 && $newSize['newWidth'] > $this->maxWidth) { - $newSize = $this->calcWidth($newSize['newWidth'], $newSize['newHeight']); - } - } - - $this->newDimensions = $newSize; - } - - /** - * Calculates new image dimensions, not allowing the width and height to be less than either the max width or height - * - * @param int $width - * @param int $height - */ - protected function calcImageSizeStrict($width, $height) - { - // first, we need to determine what the longest resize dimension is.. - if ($this->maxWidth >= $this->maxHeight) { - // and determine the longest original dimension - if ($width > $height) { - $newDimensions = $this->calcHeight($width, $height); - - if ($newDimensions['newWidth'] < $this->maxWidth) { - $newDimensions = $this->calcWidth($width, $height); - } - } elseif ($height >= $width) { - $newDimensions = $this->calcWidth($width, $height); - - if ($newDimensions['newHeight'] < $this->maxHeight) { - $newDimensions = $this->calcHeight($width, $height); - } - } - } elseif ($this->maxHeight > $this->maxWidth) { - if ($width >= $height) { - $newDimensions = $this->calcWidth($width, $height); - - if ($newDimensions['newHeight'] < $this->maxHeight) { - $newDimensions = $this->calcHeight($width, $height); - } - } elseif ($height > $width) { - $newDimensions = $this->calcHeight($width, $height); - - if ($newDimensions['newWidth'] < $this->maxWidth) { - $newDimensions = $this->calcWidth($width, $height); - } - } - } - - $this->newDimensions = $newDimensions; - } - - /** - * Calculates new dimensions based on $this->percent and the provided dimensions - * - * @param int $width - * @param int $height - */ - protected function calcImageSizePercent($width, $height) - { - if ($this->percent > 0) { - $this->newDimensions = $this->calcPercent($width, $height); - } - } - - /** - * Determines the file format by mime-type - * - * This function will throw exceptions for invalid images / mime-types - * - */ - protected function determineFormat() - { - $formatInfo = getimagesize($this->fileName); - - // non-image files will return false - if ($formatInfo === false) { - if ($this->remoteImage) { - throw new \Exception("Could not determine format of remote image: {$this->fileName}"); - } else { - throw new \Exception("File is not a valid image: {$this->fileName}"); - } - } - - $mimeType = isset($formatInfo['mime']) ? $formatInfo['mime'] : null; - - switch ($mimeType) { - case 'image/gif': - $this->format = 'GIF'; - break; - case 'image/jpeg': - $this->format = 'JPG'; - break; - case 'image/png': - $this->format = 'PNG'; - break; - default: - throw new \Exception("Image format not supported: {$mimeType}"); - } - } - - /** - * Makes sure the correct GD implementation exists for the file type - * - */ - protected function verifyFormatCompatiblity() - { - $isCompatible = true; - $gdInfo = gd_info(); - - switch ($this->format) { - case 'GIF': - $isCompatible = isset($gdInfo['GIF Create Support']); - break; - case 'JPG': - $isCompatible = (isset($gdInfo['JPG Support']) || isset($gdInfo['JPEG Support'])) ? true : false; - break; - case 'PNG': - $isCompatible = isset($gdInfo[$this->format . ' Support']); - break; - default: - $isCompatible = false; - } - - if (!$isCompatible) { - // one last check for "JPEG" instead - $isCompatible = isset($gdInfo['JPEG Support']); - - if (!$isCompatible) { - throw new \Exception("Your GD installation does not support {$this->format} image types"); - } - } - } - - /** - * Preserves the alpha or transparency for PNG and GIF files - * - * Alpha / transparency will not be preserved if the appropriate options are set to false. - * Also, the GIF transparency is pretty skunky (the results aren't awesome), but it works like a - * champ... that's the nature of GIFs tho, so no huge surprise. - * - * This functionality was originally suggested by commenter Aimi (no links / site provided) - Thanks! :) - * - */ - protected function preserveAlpha() - { - if ($this->format == 'PNG' && $this->options['preserveAlpha'] === true) { - imagealphablending($this->workingImage, false); - - $colorTransparent = imagecolorallocatealpha( - $this->workingImage, - $this->options['alphaMaskColor'][0], - $this->options['alphaMaskColor'][1], - $this->options['alphaMaskColor'][2], - 0 - ); - - imagefill($this->workingImage, 0, 0, $colorTransparent); - imagesavealpha($this->workingImage, true); - } - // preserve transparency in GIFs... this is usually pretty rough tho - if ($this->format == 'GIF' && $this->options['preserveTransparency'] === true) { - $colorTransparent = imagecolorallocate( - $this->workingImage, - $this->options['transparencyMaskColor'][0], - $this->options['transparencyMaskColor'][1], - $this->options['transparencyMaskColor'][2] - ); - - imagecolortransparent($this->workingImage, $colorTransparent); - imagetruecolortopalette($this->workingImage, true, 256); - } - } -} diff --git a/snappymail/v/0.0.0/app/libraries/PHPThumb/PHPThumb.php b/snappymail/v/0.0.0/app/libraries/PHPThumb/PHPThumb.php deleted file mode 100644 index a86c8c91e..000000000 --- a/snappymail/v/0.0.0/app/libraries/PHPThumb/PHPThumb.php +++ /dev/null @@ -1,143 +0,0 @@ - - * Copyright (c) 2009, Ian Selby/Gen X Design - * - * Author(s): Ian Selby - * - * Licensed under the MIT License - * Redistributions of files must retain the above copyright notice. - * - * @author Ian Selby - * @copyright Copyright (c) 2009 Gen X Design - * @link http://phpthumb.gxdlabs.com - * @license http://www.opensource.org/licenses/mit-license.php The MIT License - */ - -abstract class PHPThumb -{ - /** - * The name of the file we're manipulating - * This must include the path to the file (absolute paths recommended) - * - * @var string - */ - protected $fileName; - - /** - * What the file format is (mime-type) - * - * @var string - */ - protected $format; - - /** - * Whether or not the image is hosted remotely - * - * @var bool - */ - protected $remoteImage; - - /** - * An array of attached plugins to execute in order. - * @var array - */ - protected $plugins; - - /** - * @param $fileName - * @param array $options - * @param array $plugins - */ - public function __construct($fileName, array $options = array(), array $plugins = array()) - { - $this->fileName = $fileName; - $this->remoteImage = false; - - if(!$this->validateRequestedResource($fileName)) { - throw new \InvalidArgumentException("Image file not found: {$fileName}"); - } - - $this->setOptions($options); - - $this->plugins = $plugins; - } - - abstract public function setOptions(array $options = array()); - - /** - * Check the provided filename/url. If it is a url, validate that it is properly - * formatted. If it is a file, check to make sure that it actually exists on - * the filesystem. - * - * @param $filename - * @return bool - */ - protected function validateRequestedResource($filename) - { - if(false !== filter_var($filename, FILTER_VALIDATE_URL)) { - $this->remoteImage = true; - return true; - } - - if (file_exists($filename)) { - return true; - } - - return false; - } - - /** - * Returns the filename. - * @return string - */ - public function getFileName() - { - return $this->fileName; - } - - /** - * Sets the filename. - * @param $fileName - * @return PHPThumb - */ - public function setFileName($fileName) - { - $this->fileName = $fileName; - - return $this; - } - - /** - * Returns the format. - * @return string - */ - public function getFormat() - { - return $this->format; - } - - /** - * Sets the format. - * @param $format - * @return PHPThumb - */ - public function setFormat($format) - { - $this->format = $format; - - return $this; - } - - /** - * Returns whether the image exists remotely, i.e. it was loaded via a URL. - * @return bool - */ - public function getIsRemoteImage() - { - return $this->remoteImage; - } -} diff --git a/snappymail/v/0.0.0/app/libraries/PHPThumb/PluginInterface.php b/snappymail/v/0.0.0/app/libraries/PHPThumb/PluginInterface.php deleted file mode 100644 index 56df9768a..000000000 --- a/snappymail/v/0.0.0/app/libraries/PHPThumb/PluginInterface.php +++ /dev/null @@ -1,12 +0,0 @@ - - * Copyright (c) 2009, Ian Selby/Gen X Design - * - * Author(s): Ian Selby - * - * Licensed under the MIT License - * Redistributions of files must retain the above copyright notice. - * - * @author Ian Selby - * @copyright Copyright (c) 2009 Gen X Design - * @link http://phpthumb.gxdlabs.com - * @license http://www.opensource.org/licenses/mit-license.php The MIT License - * @version 3.0 - * @package PhpThumb - * @filesource - */ - -/** - * GD Reflection Lib Plugin - * - * This plugin allows you to create those fun Apple(tm)-style reflections in your images - * - * @package PhpThumb - * @subpackage Plugins - */ -class Reflection implements \PHPThumb\PluginInterface -{ - protected $currentDimensions; - protected $workingImage; - protected $newImage; - protected $options; - - protected $percent; - protected $reflection; - protected $white; - protected $border; - protected $borderColor; - - public function __construct($percent, $reflection, $white, $border, $borderColor) - { - $this->percent = $percent; - $this->reflection = $reflection; - $this->white = $white; - $this->border = $border; - $this->borderColor = $borderColor; - } - - /** - * @param \PHPThumb\PHPThumb $phpthumb - * @return \PHPThumb\PHPThumb - */ - public function execute($phpthumb) - { - $this->currentDimensions = $phpthumb->getCurrentDimensions(); - $this->workingImage = $phpthumb->getWorkingImage(); - $this->newImage = $phpthumb->getOldImage(); - $this->options = $phpthumb->getOptions(); - - $width = $this->currentDimensions['width']; - $height = $this->currentDimensions['height']; - $this->reflectionHeight = intval($height * ($this->reflection / 100)); - $newHeight = $height + $this->reflectionHeight; - $reflectedPart = $height * ($this->percent / 100); - - $this->workingImage = imagecreatetruecolor($width, $newHeight); - - imagealphablending($this->workingImage, true); - - $colorToPaint = imagecolorallocatealpha( - $this->workingImage, - 255, - 255, - 255, - 0 - ); - - imagefilledrectangle( - $this->workingImage, - 0, - 0, - $width, - $newHeight, - $colorToPaint - ); - - imagecopyresampled( - $this->workingImage, - $this->newImage, - 0, - 0, - 0, - $reflectedPart, - $width, - $this->reflectionHeight, - $width, - ($height - $reflectedPart) - ); - - $this->imageFlipVertical(); - - imagecopy( - $this->workingImage, - $this->newImage, - 0, - 0, - 0, - 0, - $width, - $height - ); - - imagealphablending($this->workingImage, true); - - for ($i = 0; $i < $this->reflectionHeight; $i++) { - $colorToPaint = imagecolorallocatealpha( - $this->workingImage, - 255, - 255, - 255, - ($i / $this->reflectionHeight * -1 + 1) * $this->white - ); - - imagefilledrectangle( - $this->workingImage, - 0, - $height + $i, - $width, - $height + $i, - $colorToPaint - ); - } - - if ($this->border == true) { - $rgb = $this->hex2rgb($this->borderColor, false); - $colorToPaint = imagecolorallocate($this->workingImage, $rgb[0], $rgb[1], $rgb[2]); - - //top line - imageline( - $this->workingImage, - 0, - 0, - $width, - 0, - $colorToPaint - ); - - //bottom line - imageline( - $this->workingImage, - 0, - $height, - $width, - $height, - $colorToPaint - ); - - //left line - imageline( - $this->workingImage, - 0, - 0, - 0, - $height, - $colorToPaint - ); - - //right line - imageline( - $this->workingImage, - $width - 1, - 0, - $width - 1, - $height, - $colorToPaint - ); - } - - if ($phpthumb->getFormat() == 'PNG') { - $colorTransparent = imagecolorallocatealpha( - $this->workingImage, - $this->options['alphaMaskColor'][0], - $this->options['alphaMaskColor'][1], - $this->options['alphaMaskColor'][2], - 0 - ); - - imagefill($this->workingImage, 0, 0, $colorTransparent); - imagesavealpha($this->workingImage, true); - } - - $phpthumb->setOldImage($this->workingImage); - $this->currentDimensions['width'] = $width; - $this->currentDimensions['height'] = $newHeight; - $phpthumb->setCurrentDimensions($this->currentDimensions); - - return $phpthumb; - } - - /** - * Flips the image vertically - * - */ - protected function imageFlipVertical () - { - $x_i = imagesx($this->workingImage); - $y_i = imagesy($this->workingImage); - - for ($x = 0; $x < $x_i; $x++) { - for ($y = 0; $y < $y_i; $y++) { - imagecopy( - $this->workingImage, - $this->workingImage, - $x, - $y_i - $y - 1, - $x, - $y, - 1, - 1 - ); - } - } - } - - /** - * Converts a hex color to rgb tuples - * - * @return mixed - * @param string $hex - * @param bool $asString - */ - protected function hex2rgb ($hex, $asString = false) - { - // strip off any leading # - if (0 === strpos($hex, '#')) { - $hex = substr($hex, 1); - } elseif (0 === strpos($hex, '&H')) { - $hex = substr($hex, 2); - } - - // break into hex 3-tuple - $cutpoint = ceil(strlen($hex) / 2)-1; - $rgb = explode(':', wordwrap($hex, $cutpoint, ':', $cutpoint), 3); - - // convert each tuple to decimal - $rgb[0] = (isset($rgb[0]) ? hexdec($rgb[0]) : 0); - $rgb[1] = (isset($rgb[1]) ? hexdec($rgb[1]) : 0); - $rgb[2] = (isset($rgb[2]) ? hexdec($rgb[2]) : 0); - - return ($asString ? "{$rgb[0]} {$rgb[1]} {$rgb[2]}" : $rgb); - } -} diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php index 9da2246c4..844df3b44 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php @@ -265,18 +265,17 @@ class Actions break; case 'address-book': // Providers\AddressBook\AddressBookInterface - $sDsn = \trim($this->Config()->Get('contacts', 'pdo_dsn', '')); $sUser = \trim($this->Config()->Get('contacts', 'pdo_user', '')); $sPassword = (string)$this->Config()->Get('contacts', 'pdo_password', ''); - $sDsnType = $this->ValidateContactPdoType(\trim($this->Config()->Get('contacts', 'type', 'sqlite'))); if ('sqlite' === $sDsnType) { - $mResult = new Providers\AddressBook\PdoAddressBook( - 'sqlite:' . APP_PRIVATE_DATA . 'AddressBook.sqlite', '', '', 'sqlite'); + $sUser = $sPassword = ''; + $sDsn = 'sqlite:' . APP_PRIVATE_DATA . 'AddressBook.sqlite'; } else { - $mResult = new Providers\AddressBook\PdoAddressBook($sDsn, $sUser, $sPassword, $sDsnType); + $sDsn = $sDsnType . ':' . \preg_replace('/^[a-z]+:/', '', $sDsn); } + $mResult = new Providers\AddressBook\PdoAddressBook($sDsn, $sUser, $sPassword, $sDsnType); break; case 'identities': $mResult = []; @@ -284,10 +283,6 @@ class Actions case 'suggestions': $mResult = []; break; - case 'two-factor-auth': - // Providers\TwoFactorAuth\TwoFactorAuthInterface - $mResult = new Providers\TwoFactorAuth\TotpTwoFactorAuth(); - break; } } @@ -804,13 +799,10 @@ class Actions (\MailSo\Base\Utils::FunctionExistsAndEnabled('php_sapi_name') ? \php_sapi_name() : '~') . ']' ); - $sPdo = (\class_exists('PDO') ? \implode(',', \PDO::getAvailableDrivers()) : 'off'); - $sPdo = empty($sPdo) ? '~' : $sPdo; - $this->oLogger->Write( '[APC:' . (\MailSo\Base\Utils::FunctionExistsAndEnabled('apc_fetch') ? 'on' : 'off') . '][MB:' . (\MailSo\Base\Utils::FunctionExistsAndEnabled('mb_convert_encoding') ? 'on' : 'off') . - '][PDO:' . $sPdo . + '][PDO:' . (\class_exists('PDO') ? (\implode(',', \Pdo::getAvailableDrivers()) ?: '~') : 'off') . '][Streams:' . \implode(',', \stream_get_transports()) . ']'); @@ -879,7 +871,7 @@ class Actions } } - public function LoginProvide(string $sEmail, string $sLogin, string $sPassword, string $sSignMeToken = '', string $sClientCert = '', bool $bThrowProvideException = false): ?Model\Account + protected function LoginProvide(string $sEmail, string $sLogin, string $sPassword, string $sSignMeToken = '', string $sClientCert = '', bool $bThrowProvideException = false): ?Model\Account { $oAccount = null; if (0 < \strlen($sEmail) && 0 < \strlen($sLogin) && 0 < \strlen($sPassword)) { @@ -887,7 +879,7 @@ class Actions if ($oDomain) { if ($oDomain->ValidateWhiteList($sEmail, $sLogin)) { $oAccount = new Model\Account($sEmail, $sLogin, $sPassword, $oDomain, $sSignMeToken, '', '', $sClientCert); - $this->Plugins()->RunHook('filter.acount', array($oAccount)); + $this->Plugins()->RunHook('filter.account', array($oAccount)); if ($bThrowProvideException && !$oAccount) { throw new Exceptions\ClientException(Notifications::AuthError); @@ -1013,8 +1005,8 @@ class Actions 'faviconStatus' => (bool)$oConfig->Get('labs', 'favicon_status', true), 'listPermanentFiltered' => '' !== \trim(Api::Config()->Get('labs', 'imap_message_list_permanent_filter', '')), 'themes' => $this->GetThemes(), - 'languages' => $this->GetLanguages(false), - 'languagesAdmin' => $this->GetLanguages(true), + 'languages' => \SnappyMail\L10n::getLanguages(false), + 'languagesAdmin' => \SnappyMail\L10n::getLanguages(true), 'attachmentsActions' => $aAttachmentsActions ), $bAdmin ? array( 'adminHostUse' => '' !== $oConfig->Get('security', 'admin_panel_host', ''), @@ -1063,7 +1055,6 @@ class Actions 'StartupUrl' => \trim(\ltrim(\trim($oConfig->Get('labs', 'startup_url', '')), '#/')), 'SieveAllowFileintoInbox' => (bool)$oConfig->Get('labs', 'sieve_allow_fileinto_inbox', false), 'ContactsIsAllowed' => false, - 'RequireTwoFactor' => false, 'Admin' => array(), 'Capa' => array(), 'Plugins' => array(), @@ -1090,7 +1081,7 @@ class Actions 'AllowDraftAutosave' => (bool) $oConfig->Get('defaults', 'allow_draft_autosave', true), 'ReplySameFolder' => (bool) $oConfig->Get('defaults', 'mail_reply_same_folder', false), 'ContactsAutosave' => (bool) $oConfig->Get('defaults', 'contacts_autosave', true), - 'EnableTwoFactor' => false, + 'HideUnsubscribed' => (bool) $oConfig->Get('labs', 'use_imap_list_subscribe', true), 'ParentEmail' => '', 'InterfaceAnimation' => true, 'UserBackgroundName' => '', @@ -1103,6 +1094,16 @@ class Actions $oSettings = null; + $passfile = APP_PRIVATE_DATA.'admin_password.txt'; + $sPassword = $oConfig->Get('security', 'admin_password', ''); + if (!$sPassword) { + $sPassword = \substr(\base64_encode(\random_bytes(16)), 0, 12); + \file_put_contents($passfile, $sPassword); + \chmod($passfile, 0600); + $oConfig->SetPassword($sPassword); + $oConfig->Save(); + } + if (!$bAdmin) { $oAccount = $this->getAccountFromToken(false); if ($oAccount) { @@ -1163,18 +1164,6 @@ class Actions } $aResult['Capa'] = $this->Capa(false, $oAccount); - - if ($aResult['Auth'] && !$aResult['RequireTwoFactor']) { - if ($this->GetCapa(false, Enumerations\Capa::TWO_FACTOR, $oAccount) && - $this->GetCapa(false, Enumerations\Capa::TWO_FACTOR_FORCE, $oAccount) && - $this->TwoFactorAuthProvider()->IsActive()) { - $aData = $this->getTwoFactorInfo($oAccount, true); - - $aResult['RequireTwoFactor'] = !$aData || - !isset($aData['User'], $aData['IsSet'], $aData['Enable']) || - !($aData['IsSet'] && $aData['Enable']); - } - } } else { $aResult['Auth'] = $this->IsAdminLoggined(false); if ($aResult['Auth']) { @@ -1186,7 +1175,7 @@ class Actions $aResult['VerifySslCertificate'] = (bool)$oConfig->Get('ssl', 'verify_certificate', false); $aResult['AllowSelfSigned'] = (bool)$oConfig->Get('ssl', 'allow_self_signed', true); - $aResult['supportedPdoDrivers'] = \class_exists('PDO') ? \PDO::getAvailableDrivers() : []; + $aResult['supportedPdoDrivers'] = \RainLoop\Common\PdoAbstract::getAvailableDrivers(); $aResult['ContactsEnable'] = (bool)$oConfig->Get('contacts', 'enable', false); $aResult['ContactsSync'] = (bool)$oConfig->Get('contacts', 'allow_sync', false); @@ -1196,7 +1185,7 @@ class Actions $aResult['ContactsPdoUser'] = (string)$oConfig->Get('contacts', 'pdo_user', ''); $aResult['ContactsPdoPassword'] = (string)APP_DUMMY; - $aResult['WeakPassword'] = (bool)$oConfig->ValidatePassword('12345'); + $aResult['WeakPassword'] = \is_file($passfile); $aResult['PhpUploadSizes'] = array( 'upload_max_filesize' => \ini_get('upload_max_filesize'), @@ -1224,7 +1213,7 @@ class Actions $aResult['SpamFolder'] = (string)$oSettingsLocal->GetConf('SpamFolder', ''); $aResult['TrashFolder'] = (string)$oSettingsLocal->GetConf('TrashFolder', ''); $aResult['ArchiveFolder'] = (string)$oSettingsLocal->GetConf('ArchiveFolder', ''); - $aResult['NullFolder'] = (string)$oSettingsLocal->GetConf('NullFolder', ''); + $aResult['HideUnsubscribed'] = (bool)$oSettingsLocal->GetConf('HideUnsubscribed', $aResult['HideUnsubscribed']); } if ($this->GetCapa(false, Enumerations\Capa::SETTINGS, $oAccount)) { @@ -1253,8 +1242,6 @@ class Actions $aResult['UserBackgroundName'] = (string)$oSettings->GetConf('UserBackgroundName', $aResult['UserBackgroundName']); $aResult['UserBackgroundHash'] = (string)$oSettings->GetConf('UserBackgroundHash', $aResult['UserBackgroundHash']); } - - $aResult['EnableTwoFactor'] = (bool)$oSettings->GetConf('EnableTwoFactor', $aResult['EnableTwoFactor']); } if ($oSettingsLocal instanceof Settings) { @@ -1428,12 +1415,11 @@ class Actions /** * @throws \RainLoop\Exceptions\ClientException */ - public function LoginProcess(string &$sEmail, string &$sPassword, string $sSignMeToken = '', - string $sAdditionalCode = '', bool $bAdditionalCodeSignMe = false, bool $bSkipTwoFactorAuth = false): Model\Account + public function LoginProcess(string &$sEmail, string &$sPassword, string $sSignMeToken = ''): Model\Account { $sInputEmail = $sEmail; - $this->Plugins()->RunHook('filter.login-credentials.step-1', array(&$sEmail, &$sPassword)); + $this->Plugins()->RunHook('login.credentials.step-1', array(&$sEmail)); $sEmail = \MailSo\Base\Utils::Trim($sEmail); if ($this->Config()->Get('login', 'login_lowercase', true)) { @@ -1500,7 +1486,7 @@ class Actions } } - $this->Plugins()->RunHook('filter.login-credentials.step-2', array(&$sEmail, &$sPassword)); + $this->Plugins()->RunHook('login.credentials.step-2', array(&$sEmail, &$sPassword)); if (false === \strpos($sEmail, '@') || 0 === \strlen($sPassword)) { $this->loginErrorDelay(); @@ -1515,12 +1501,10 @@ class Actions $sLogin = \MailSo\Base\Utils::StrToLowerIfAscii($sLogin); } - $this->Plugins()->RunHook('filter.login-credentials', array(&$sEmail, &$sLogin, &$sPassword)); + $this->Plugins()->RunHook('login.credentials', array(&$sEmail, &$sLogin, &$sPassword)); $this->Logger()->AddSecret($sPassword); - $this->Plugins()->RunHook('event.login-pre-login-provide', array()); - $oAccount = null; $sClientCert = \trim($this->Config()->Get('ssl', 'client_cert', '')); try { @@ -1529,57 +1513,12 @@ class Actions if (!$oAccount) { throw new Exceptions\ClientException(Notifications::AuthError); } - - $this->Plugins()->RunHook('event.login-post-login-provide', array($oAccount)); } catch (\Throwable $oException) { $this->loginErrorDelay(); $this->LoggerAuthHelper($oAccount, $this->getAdditionalLogParamsByUserLogin($sInputEmail)); throw $oException; } - // 2FA - if (!$bSkipTwoFactorAuth && $this->TwoFactorAuthProvider()->IsActive()) { - $aData = $this->getTwoFactorInfo($oAccount); - if ($aData && isset($aData['IsSet'], $aData['Enable']) && !empty($aData['Secret']) && $aData['IsSet'] && $aData['Enable']) { - $sSecretHash = \md5(APP_SALT . $aData['Secret'] . Utils::Fingerprint()); - $sSecretCookieHash = Utils::GetCookie(self::AUTH_TFA_SIGN_ME_TOKEN_KEY, ''); - - if (empty($sSecretCookieHash) || $sSecretHash !== $sSecretCookieHash) { - $sAdditionalCode = \trim($sAdditionalCode); - if (empty($sAdditionalCode)) { - $this->Logger()->Write('TFA: Required Code for ' . $oAccount->ParentEmailHelper() . ' account.'); - - throw new Exceptions\ClientException(Notifications::AccountTwoFactorAuthRequired); - } else { - $this->Logger()->Write('TFA: Verify Code for ' . $oAccount->ParentEmailHelper() . ' account.'); - - $bUseBackupCode = false; - if (6 < \strlen($sAdditionalCode) && !empty($aData['BackupCodes'])) { - $aBackupCodes = \explode(' ', \trim(\preg_replace('/[^\d]+/', ' ', $aData['BackupCodes']))); - $bUseBackupCode = \in_array($sAdditionalCode, $aBackupCodes); - - if ($bUseBackupCode) { - $this->removeBackupCodeFromTwoFactorInfo($oAccount->ParentEmailHelper(), $sAdditionalCode); - } - } - - if (!$bUseBackupCode && !$this->TwoFactorAuthProvider()->VerifyCode($aData['Secret'], $sAdditionalCode)) { - $this->loginErrorDelay(); - - $this->LoggerAuthHelper($oAccount); - - throw new Exceptions\ClientException(Notifications::AccountTwoFactorAuthError); - } - - if ($bAdditionalCodeSignMe) { - Utils::SetCookie(self::AUTH_TFA_SIGN_ME_TOKEN_KEY, $sSecretHash, - \time() + 60 * 60 * 24 * 14); - } - } - } - } - } - try { $this->CheckMailConnection($oAccount, true); } catch (\Throwable $oException) { @@ -2077,16 +2016,6 @@ class Actions } } - if ($oConfig->Get('security', 'allow_two_factor_auth', false) && - ($bAdmin || ($oAccount && !$oAccount->IsAdditionalAccount()))) { - $aResult[] = Enumerations\Capa::TWO_FACTOR; - - if ($oConfig->Get('security', 'force_two_factor_auth', false) && - ($bAdmin || ($oAccount && !$oAccount->IsAdditionalAccount()))) { - $aResult[] = Enumerations\Capa::TWO_FACTOR_FORCE; - } - } - if ($oConfig->Get('capa', 'help', true)) { $aResult[] = Enumerations\Capa::HELP; } @@ -2216,52 +2145,48 @@ class Actions public function ValidateLanguage(string $sLanguage, string $sDefault = '', bool $bAdmin = false, bool $bAllowEmptyResult = false): string { - $sResult = ''; - $aLang = $this->GetLanguages($bAdmin); + $aLang = \SnappyMail\L10n::getLanguages($bAdmin); - $aHelper = array('en' => 'en_us', 'ar' => 'ar_sa', 'cs' => 'cs_cz', 'no' => 'nb_no', 'ua' => 'uk_ua', - 'cn' => 'zh_cn', 'zh' => 'zh_cn', 'tw' => 'zh_tw', 'fa' => 'fa_ir'); + $aHelper = array( + 'ar' => 'ar-SA', + 'cs' => 'cs-CZ', + 'no' => 'nb-NO', + 'ua' => 'uk-UA', + 'cn' => 'zh-CN', + 'zh' => 'zh-CN', + 'tw' => 'zh-TW', + 'fa' => 'fa-IR' + ); - $sLanguage = isset($aHelper[$sLanguage]) ? $aHelper[$sLanguage] : $sLanguage; - $sDefault = isset($aHelper[$sDefault]) ? $aHelper[$sDefault] : $sDefault; - - $sLanguage = \strtolower(\str_replace('-', '_', $sLanguage)); - if (2 === strlen($sLanguage)) { - $sLanguage = $sLanguage . '_' . $sLanguage; - } - - $sDefault = \strtolower(\str_replace('-', '_', $sDefault)); - if (2 === strlen($sDefault)) { - $sDefault = $sDefault . '_' . $sDefault; - } - - $sLanguage = \preg_replace_callback('/_([a-zA-Z0-9]{2})$/', function ($aData) { - return \strtoupper($aData[0]); - }, $sLanguage); - - $sDefault = \preg_replace_callback('/_([a-zA-Z0-9]{2})$/', function ($aData) { - return \strtoupper($aData[0]); - }, $sDefault); + $sLanguage = isset($aHelper[$sLanguage]) ? $aHelper[$sLanguage] : \strtr($sLanguage, '_', '-'); + $sDefault = isset($aHelper[$sDefault]) ? $aHelper[$sDefault] : \strtr($sDefault, '_', '-'); if (\in_array($sLanguage, $aLang)) { - $sResult = $sLanguage; + return $sLanguage; } - if (empty($sResult) && !empty($sDefault) && \in_array($sDefault, $aLang)) { - $sResult = $sDefault; + $sLangCountry = \preg_replace_callback('/-([a-zA-Z]{2})$/', function ($aData) { + return \strtoupper($aData[0]); + }, $sLanguage); + if (\in_array($sLangCountry, $aLang)) { + return $sLangCountry; } - if (empty($sResult) && !$bAllowEmptyResult) { - $sResult = $this->Config()->Get('webmail', $bAdmin ? 'language_admin' : 'language', 'en_US'); - $sResult = \in_array($sResult, $aLang) ? $sResult : 'en_US'; + if (\in_array($sDefault, $aLang)) { + return $sDefault; } - return $sResult; + if ($bAllowEmptyResult) { + return ''; + } + + $sResult = $this->Config()->Get('webmail', $bAdmin ? 'language_admin' : 'language', 'en'); + return \in_array($sResult, $aLang) ? $sResult : 'en'; } public function ValidateContactPdoType(string $sType): string { - return \in_array($sType, array('mysql', 'pgsql', 'sqlite')) ? $sType : 'sqlite'; + return \in_array($sType, \RainLoop\Common\PdoAbstract::getAvailableDrivers()) ? $sType : 'sqlite'; } /** @@ -2324,44 +2249,6 @@ class Actions return $aCache; } - /** - * @staticvar array $aCache - */ - public function GetLanguages(bool $bAdmin = false): array - { - static $aCache = array(); - $sDir = APP_VERSION_ROOT_PATH . 'app/localization/' . ($bAdmin ? 'admin' : 'webmail') . '/'; - - if (isset($aCache[$sDir])) { - return $aCache[$sDir]; - } - - $aTop = array(); - $aList = array(); - - if (\is_dir($sDir)) { - $rDirH = \opendir($sDir); - if ($rDirH) { - while (($sFile = \readdir($rDirH)) !== false) { - if ('.' !== $sFile[0] && \is_file($sDir . '/' . $sFile) && '.yml' === \substr($sFile, -4)) { - $sLang = \substr($sFile, 0, -4); - if (0 < \strlen($sLang) && 'always' !== $sLang && '_source.en' !== $sLang) { - \array_push($aList, $sLang); - } - } - } - - \closedir($rDirH); - } - } - - \sort($aTop); - \sort($aList); - - $aCache[$sDir] = \array_merge($aTop, $aList); - return $aCache[$sDir]; - } - public function ProcessTemplate(string $sName, string $sHtml): string { $sHtml = \preg_replace('/