1&&void 0!==arguments[1]&&arguments[1];return n(10).i18n("LANGS_NAMES"+(!0===t?"_EN":"")+"/LANG_"+e.toUpperCase().replace(/[^a-zA-Z0-9]+/g,"_"),null,e)}function x(){return ue()('
').appendTo("#rl-hidden")}function P(e,t){t&&!_e(t.disabled)&&e&&ue()(e).toggleClass("disabled",t.disabled).prop("disabled",t.disabled)}function k(e){e.find("blockquote.rl-bq-switcher").removeClass("rl-bq-switcher hidden-bq"),e.find(".rlBlockquoteSwitcher").off(".rlBlockquoteSwitcher").remove(),e.find("[data-html-editor-font-wrapper]").removeAttr("data-html-editor-font-wrapper")}function L(e,t,i,o){var a=e.title,r=e.subject,s=e.date,c=e.fromCreds,l=e.toCreds,u=e.toLabel,d=e.ccClass,p=e.ccCreds,f=e.ccLabel,m=ce.a.open(""),h=m.document,g=t.clone(),v=i?"html":"plain";k(g);var S=g?g.html():"";h.write(n(170).replace("{{title}}",b(a)).replace("{{subject}}",b(r)).replace("{{date}}",b(s)).replace("{{fromCreds}}",b(c)).replace("{{toCreds}}",b(l)).replace("{{toLabel}}",b(u)).replace("{{ccClass}}",b(d)).replace("{{ccCreds}}",b(p)).replace("{{ccLabel}}",b(f)).replace("{{bodyClass}}",v).replace("{{html}}",S)),h.close(),o&&ce.a.setTimeout(function(){return m.print()},100)}function M(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:1e3;return i=r(i),function(o,a,r,s,c){t.call(n,a&&a.Result?be.SaveSettingsStep.TrueResult:be.SaveSettingsStep.FalseResult),e&&e.call(n,o,a,r,s,c),pe.a.delay(function(){t.call(n,be.SaveSettingsStep.Idle)},i)}}function F(e,t){return M(null,e,t,1e3)}function U(e,t,n,i){return function(o){if(e){switch(n){case"bool":case"boolean":o=o?"1":"0";break;case"int":case"integer":case"number":o=r(o);break;case"trim":o=we(o);break;default:o=s(o)}var a={};a[t]=o,e.saveAdminConfig?e.saveAdminConfig(i||null,a):e.saveSettings&&e.saveSettings(i||null,a)}}}function H(e){return he.a?he.a.link(e,{newWindow:!0,stripPrefix:!1,urls:!0,email:!0,mention:!1,phone:!1,hashtag:!1,replaceFn:function(e){return!(e&&"url"===e.getType()&&e.matchedText&&0!==e.matchedText.indexOf("http"))}}):e}function G(e){var t,n=0,i=0,o=0,a=0,r=0,s="";for(s=e.replace(/]*><\/p>/gi,"").replace(/
]*>([\s\S\r\n\t]*)<\/pre>/gim,function(){for(var e=arguments.length,t=Array(e),n=0;n ").replace(/[\r]/gm,""):""}).replace(/[\s]+/gm," ").replace(/((?:href|data)\s?=\s?)("[^"]+?"|'[^']+?')/gim,function(){for(var e=arguments.length,t=Array(e),n=0;n]*>/gim,"\n").replace(/<\/h[\d]>/gi,"\n").replace(/<\/p>/gi,"\n\n").replace(/]*>/gim,"\n").replace(/<\/ul>/gi,"\n").replace(/]*>/gim," * ").replace(/<\/li>/gi,"\n").replace(/<\/td>/gi,"\n").replace(/<\/tr>/gi,"\n").replace(/ ]*>/gim,"\n_______________________________\n\n").replace(/]*>([\s\S\r\n]*)<\/div>/gim,function e(){for(var t=arguments.length,n=Array(t),i=0;i
]*>([\s\S\r\n]*)<\/div>/gim,e),o="\n"+we(o)+"\n"),o}return""}).replace(/]*>/gim,"\n__bq__start__\n").replace(/<\/blockquote>/gim,"\n__bq__end__\n").replace(/]*>([\s\S\r\n]*?)<\/a>/gim,function(){for(var e=arguments.length,t=Array(e),n=0;n/gi,"\n").replace(/ /gi," ").replace(/"/gi,'"').replace(/<[^>]*>/gm,""),s=v(s=(s=ge.$div.html(s).text()).replace(/\n[ \t]+/gm,"\n").replace(/[\n]{3,}/gm,"\n\n").replace(/>/gi,">").replace(/</gi,"<").replace(/&/gi,"&")),n=0,i=800;0 "+we(t).replace(/\n/gm,"\n> ")).replace(/(^|\n)([> ]+)/gm,function(){for(var e=arguments.length,t=Array(e),n=0;n1&&void 0!==arguments[1]&&arguments[1],n=!1,i=!0,o=!0,a=[],r="",s=0,c=(e=(e=e.toString().replace(/\r/g,"")).replace(/^>[> ]>+/gm,function(e){var t=e[0];return t?t.replace(/[ ]+/g,""):t})).split("\n");do{for(i=!1,a=[],s=0;s"===(r=c[s]).substr(0,1))&&!n?(i=!0,n=!0,a.push("~~~blockquote~~~"),a.push(r.substr(1))):!o&&n?""!==r?(n=!1,a.push("~~~/blockquote~~~"),a.push(r)):a.push(r):o&&n?a.push(r.substr(1)):a.push(r);n&&(n=!1,a.push("~~~/blockquote~~~")),c=a}while(i);return e=(e=c.join("\n")).replace(/&/g,"&").replace(/>/g,">").replace(/").replace(/[\s]*~~~\/blockquote~~~/g," ").replace(/\n/g," "),t?H(e):e}function V(e,t,n,i,a,r,s,c,l,u){var d=null,p=!1,f=0,m=0,h=[];for(u=!_e(u)&&!!u,l=o(l)?l:00&&void 0!==arguments[0]&&arguments[0]?pe.a.delay(e,100):e()}function K(e){Me[e]||(Me[e]=ue()('script[type="application/json"][data-configuration="'+e+'"]'));try{return JSON.parse(Me[e].text())}catch(e){}return{}}function W(e,t){var n=t||e;n&&"function"==typeof n.dispose&&n.dispose()}function Y(e){e&&(Oe(e.disposables)&&pe.a.each(e.disposables,W),fe.a.utils.objectForEach(e,W))}function $(e){e&&(Oe(e)?pe.a.each(e,function(e){$(e)}):e&&e.onDestroy&&e.onDestroy())}function J(e,t){return!(!e||!e[0]||(e[0].styleSheet&&!_e(e[0].styleSheet.cssText)?e[0].styleSheet.cssText=t:e.text(t),0))}function X(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:je,n=ue()("#app-theme-link"),i=function(){Fe=ce.a.setTimeout(function(){return t(be.SaveSettingsStep.Idle)},1e3),Ue=null},o=ue()("#app-theme-style"),a=n.attr("href");a||(a=o.attr("data-href")),a&&("Json/"!==(a=(a=(a=a.toString().replace(/\/-\/[^\/]+\/\-\//,"/-/"+e+"/-/")).replace(/\/Css\/[^\/]+\/User\//,"/Css/0/User/")).replace(/\/Hash\/[^\/]+\//,"/Hash/-/")).substring(a.length-5,a.length)&&(a+="Json/"),ce.a.clearTimeout(Fe),t(be.SaveSettingsStep.Animate),Ue&&Ue.abort&&Ue.abort(),Ue=ue.a.ajax({url:a,dataType:"json"}).then(function(e){e&&Oe(e)&&2===e.length&&(!n||!n[0]||o&&o[0]||(o=ue()(''),n.after(o),n.remove()),o&&o[0]&&J(o,e[1])&&o.attr("data-href",a).attr("data-theme",e[0]),t(be.SaveSettingsStep.TrueResult))}).then(i,i))}function Q(e,t){return function(){var n=e(),i=t(),o=[],a=function(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",a={current:e===n,name:""===i?e.toString():i.toString(),custom:""!==i,title:""===i?"":e.toString(),value:e.toString()};t?o.push(a):o.unshift(a)},r=0,s=0,c=2;if(1=n||i-2<=n)&&(c+=2),a(n),r=n,s=n);0=s)a(s,!0),c-=1;else if(0>=r)break;3===r?a(2,!1):3s&&a(Math.round((i+s)/2),!0,"..."),1s&&a(i,!0)}return o}}function Z(e){var t=(e=we(e).toLowerCase()).split(".").pop();return t===e?"":t}function ee(e){var t,n="application/octet-stream";return"winmail.dat"===(e=we(e).toLowerCase())?"application/ms-tnef":((t=Z(e))&&0this.height?[this.width-this.height,0]:[0,this.height-this.width],o.fillStyle="#fff",o.fillRect(0,0,t,t),o.drawImage(this,e[0]/2,e[1]/2,this.width-e[0],this.height-e[1],0,0,t,t),n(i.toDataURL("image/jpeg"))},i.src=e}function oe(e,t){if(e&&"mailto:"===e.toString().substr(0,7).toLowerCase()){if(!t)return!0;var i,o=[],a=null,r=null,c=(e=e.toString().substr(7)).replace(/\?.+$/,""),l=e.replace(/^[^\?]*\?/,""),u=n(44).default;return i=h(l),_e(i.to)?o=u.parseEmailLine(c):(o=u.parseEmailLine(p(c+","+i.to)),o=pe.a.values(o.reduce(function(e,t){return t&&(e[t.email]&&e[t.email].name||(e[t.email]=t)),e},{}))),_e(i.cc)||(a=u.parseEmailLine(p(i.cc))),_e(i.bcc)||(r=u.parseEmailLine(p(i.bcc))),n(9).showScreenPopup(t,[be.ComposeType.Empty,null,o,a,r,_e(i.subject)?null:s(p(i.subject)),_e(i.body)?null:B(s(p(i.body)))]),!0}return!1}function ae(e){ue()(function(){return e()})}function re(){He()}n.r(t);var se=n(3),ce=n.n(se),le=n(7),ue=n.n(le),de=n(4),pe=n.n(de),fe=n(1),me=n(96),he=n.n(me),ge=n(6),be=n(0),ve={eml:"message/rfc822",mime:"message/rfc822",txt:"text/plain",text:"text/plain",def:"text/plain",list:"text/plain",in:"text/plain",ini:"text/plain",log:"text/plain",sql:"text/plain",cfg:"text/plain",conf:"text/plain",asc:"text/plain",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:"application/json",swf:"application/x-shockwave-flash",hlp:"application/winhlp",wgt:"application/widget",chm:"application/vnd.ms-htmlhelp",p10:"application/pkcs10",p7c:"application/pkcs7-mime",p7m:"application/pkcs7-mime",p7s:"application/pkcs7-signature",torrent:"application/x-bittorrent",js:"application/javascript",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",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",jpe:"image/jpeg",jfif:"image/jpeg",gif:"image/gif",bmp:"image/bmp",cgm:"image/cgm",ief:"image/ief",ico:"image/x-icon",tif:"image/tiff",tiff:"image/tiff",svg:"image/svg+xml",svgz:"image/svg+xml",djv:"image/vnd.djvu",djvu:"image/vnd.djvu",webp:"image/webp",zip:"application/zip","7z":"application/x-7z-compressed",rar:"application/x-rar-compressed",exe:"application/x-msdownload",dll:"application/x-msdownload",scr:"application/x-msdownload",com:"application/x-msdownload",bat:"application/x-msdownload",msi:"application/x-msdownload",cab:"application/vnd.ms-cab-compressed",gz:"application/x-gzip",tgz:"application/x-gzip",bz:"application/x-bzip",bz2:"application/x-bzip2",deb:"application/x-debian-package",psf:"application/x-font-linux-psf",otf:"application/x-font-otf",pcf:"application/x-font-pcf",snf:"application/x-font-snf",ttf:"application/x-font-ttf",ttc:"application/x-font-ttf",mp3:"audio/mpeg",amr:"audio/amr",aac:"audio/x-aac",aif:"audio/x-aiff",aifc:"audio/x-aiff",aiff:"audio/x-aiff",wav:"audio/x-wav",wma:"audio/x-ms-wma",wax:"audio/x-ms-wax",midi:"audio/midi",mp4a:"audio/mp4",ogg:"audio/ogg",weba:"audio/webm",ra:"audio/x-pn-realaudio",ram:"audio/x-pn-realaudio",rmp:"audio/x-pn-realaudio-plugin",m3u:"audio/x-mpegurl",flv:"video/x-flv",qt:"video/quicktime",mov:"video/quicktime",wmv:"video/windows-media",avi:"video/x-msvideo",mpg:"video/mpeg",mpeg:"video/mpeg",mpe:"video/mpeg",m1v:"video/mpeg",m2v:"video/mpeg","3gp":"video/3gpp","3g2":"video/3gpp2",h261:"video/h261",h263:"video/h263",h264:"video/h264",jpgv:"video/jpgv",mp4:"video/mp4",mp4v:"video/mp4",mpg4:"video/mp4",ogv:"video/ogg",webm:"video/webm",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",pdf:"application/pdf",psd:"image/vnd.adobe.photoshop",ai:"application/postscript",eps:"application/postscript",ps:"application/postscript",doc:"application/msword",dot:"application/msword",rtf:"application/rtf",xls:"application/vnd.ms-excel",ppt:"application/vnd.ms-powerpoint",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",dotx:"application/vnd.openxmlformats-officedocument.wordprocessingml.template",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",odt:"application/vnd.oasis.opendocument.text",ods:"application/vnd.oasis.opendocument.spreadsheet"},Se=n(59);n.d(t,"trim",function(){return we}),n.d(t,"inArray",function(){return Ae}),n.d(t,"isArray",function(){return Oe}),n.d(t,"isObject",function(){return Te}),n.d(t,"isFunc",function(){return Ce}),n.d(t,"isUnd",function(){return _e}),n.d(t,"isNull",function(){return Ee}),n.d(t,"has",function(){return De}),n.d(t,"bind",function(){return Ne}),n.d(t,"noop",function(){return je}),n.d(t,"noopTrue",function(){return Re}),n.d(t,"noopFalse",function(){return Ie}),n.d(t,"silentTryCatch",function(){return i}),n.d(t,"isNormal",function(){return o}),n.d(t,"isPosNumeric",function(){return a}),n.d(t,"pInt",function(){return r}),n.d(t,"pString",function(){return s}),n.d(t,"pBool",function(){return c}),n.d(t,"boolToAjax",function(){return l}),n.d(t,"isNonEmptyArray",function(){return u}),n.d(t,"encodeURIComponent",function(){return d}),n.d(t,"decodeURIComponent",function(){return p}),n.d(t,"decodeURI",function(){return f}),n.d(t,"encodeURI",function(){return m}),n.d(t,"simpleQueryParser",function(){return h}),n.d(t,"fakeMd5",function(){return g}),n.d(t,"encodeHtml",function(){return b}),n.d(t,"splitPlainText",function(){return v}),n.d(t,"timeOutAction",function(){return xe}),n.d(t,"timeOutActionSecond",function(){return Pe}),n.d(t,"inFocus",function(){return S}),n.d(t,"removeInFocus",function(){return y}),n.d(t,"removeSelection",function(){return w}),n.d(t,"replySubjectAdd",function(){return A}),n.d(t,"roundNumber",function(){return O}),n.d(t,"friendlySize",function(){return T}),n.d(t,"log",function(){return C}),n.d(t,"delegateRun",function(){return _}),n.d(t,"killCtrlACtrlS",function(){return E}),n.d(t,"createCommandLegacy",function(){return D}),n.d(t,"convertThemeName",function(){return ke}),n.d(t,"quoteName",function(){return N}),n.d(t,"microtime",function(){return j}),n.d(t,"timestamp",function(){return R}),n.d(t,"convertLangName",function(){return I}),n.d(t,"draggablePlace",function(){return x}),n.d(t,"defautOptionsAfterRender",function(){return P}),n.d(t,"clearBqSwitcher",function(){return k}),n.d(t,"previewMessage",function(){return L}),n.d(t,"settingsSaveHelperFunction",function(){return M}),n.d(t,"settingsSaveHelperSimpleFunction",function(){return F}),n.d(t,"settingsSaveHelperSubscribeFunction",function(){return U}),n.d(t,"findEmailAndLinks",function(){return H}),n.d(t,"htmlToPlain",function(){return G}),n.d(t,"plainToHtml",function(){return B}),n.d(t,"folderListOptionsBuilder",function(){return V}),n.d(t,"selectElement",function(){return q}),n.d(t,"detectDropdownVisibility",function(){return Le}),n.d(t,"triggerAutocompleteInputChange",function(){return z}),n.d(t,"getConfigurationFromScriptTag",function(){return K}),n.d(t,"disposeOne",function(){return W}),n.d(t,"disposeObject",function(){return Y}),n.d(t,"delegateRunOnDestroy",function(){return $}),n.d(t,"appendStyles",function(){return J}),n.d(t,"changeTheme",function(){return X}),n.d(t,"computedPagenatorHelper",function(){return Q}),n.d(t,"getFileExtension",function(){return Z}),n.d(t,"mimeContentType",function(){return ee}),n.d(t,"isTransparent",function(){return te}),n.d(t,"getRealHeight",function(){return ne}),n.d(t,"resizeAndCrop",function(){return ie}),n.d(t,"mailToHelper",function(){return oe}),n.d(t,"domReady",function(){return ae}),n.d(t,"windowResize",function(){return He}),n.d(t,"windowResizeCallback",function(){return re}),n.d(t,"jassl",function(){return Se.a});var ye,we=ue.a.trim,Ae=ue.a.inArray,Oe=pe.a.isArray,Te=pe.a.isObject,Ce=pe.a.isFunction,_e=pe.a.isUndefined,Ee=pe.a.isNull,De=pe.a.has,Ne=pe.a.bind,je=function(){},Re=function(){return!0},Ie=function(){return!1},xe=(ye={},function(e,t,n){ye[e]=_e(ye[e])?0:ye[e],ce.a.clearTimeout(ye[e]),ye[e]=ce.a.setTimeout(t,n)}),Pe=function(){var e={};return function(t,n,i){e[t]||(e[t]=ce.a.setTimeout(function(){n(),e[t]=0},i))}}(),ke=pe.a.memoize(function(e){return"@custom"===e.substr(-7)&&(e=we(e.substring(0,e.length-7))),we(e.replace(/[^a-zA-Z0-9]+/g," ").replace(/([A-Z])/g," $1").replace(/[\s]+/g," "))});ce.a.rainloop_Utils_htmlToPlain=G,ce.a.rainloop_Utils_plainToHtml=B;var Le=pe.a.debounce(function(){Object(ge.dropdownVisibility)(!!pe.a.find(ge.data.aBootstrapDropdowns,function(e){return e.hasClass("open")}))},50),Me={},Fe=0,Ue=null,He=pe.a.debounce(function(e){_e(e)||Ee(e)?ge.$win.resize():ce.a.setTimeout(function(){ge.$win.resize()},e)},50),Ge=ce.a.String.substr;"b"!=="ab".substr(-1)&&(Ge=function(e,t,n){return t=0>t?e.length+t:t,e.substr(t,n)},ce.a.String.substr=Ge)},function(e,t){e.exports=window},function(e,t){e.exports=window._},function(e,t,n){"use strict";function i(e){return Object(l.isUnd)(u[e])?null:u[e]}function o(e,t){u[e]=t}function a(e){return Object(l.isUnd)(d[e])?null:d[e]}function r(e){var t=i("Capa");return Object(l.isArray)(t)&&Object(l.isNormal)(e)&&-1 "),v=c()("
");v.attr("area","hidden").css({position:"absolute",left:-5e3}).appendTo(g);var S=(new o.a.Date).getTime(),y=!0,w=d.a.observable(!1).extend({rateLimit:0}),A=d.a.observable(!0),O="navigator"in o.a&&"userAgent"in o.a.navigator&&o.a.navigator.userAgent.toLowerCase()||"",T=-11&&void 0!==arguments[1])||arguments[1];return Object(M.createCommandLegacy)(null,e,t)}function a(e,t,n,i){var o=arguments.length>4&&void 0!==arguments[4]&&arguments[4];e.__rlSettingsData={Label:n,Template:t,Route:i,IsDefault:!!o},L.VIEW_MODELS.settings.push(e)}function r(e){L.VIEW_MODELS["settings-removed"].push(e)}function s(e){L.VIEW_MODELS["settings-disabled"].push(e)}function c(){R.a.changed.active=!1}function l(){R.a.changed.active=!0}function u(e){return""===e||Object(M.isUnd)(H[e])?null:H[e]}function d(e){var t=null;return e&&(t=e,e.default&&(t=e.default)),t}function p(e){var t=d(e);t&&t.__vm&&t.__dom&&t.__vm.modalVisibility(!1)}function f(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;_.a.each(t.__names,function(i){Object(k.f)(e,[i,t.__vm,n])})}function m(e,t){if(e&&!e.__builded){var n=null,i=new e(t),a=e.__type||"",r=a?D()("#rl-content #rl-"+a.toLowerCase()):null;e.__builded=!0,e.__vm=i,i.onShowTrigger=N.a.observable(!1),i.onHideTrigger=N.a.observable(!1),i.viewModelName=e.__name,i.viewModelNames=e.__names,i.viewModelTemplateID=e.__templateID,i.viewModelPosition=e.__type,r&&1===r.length?((n=D()("
").addClass("rl-view-model").addClass("RL-"+i.viewModelTemplateID).hide()).appendTo(r),i.viewModelDom=n,e.__dom=n,G.Popup===a&&(i.cancelCommand=i.closeCommand=o(function(){p(e)}),i.modalVisibility.subscribe(function(t){t?(i.viewModelDom.show(),i.storeAndSetKeyScope(),L.popupVisibilityNames.push(i.viewModelName),i.viewModelDom.css("z-index",3e3+Object(L.popupVisibilityNames)().length+10),i.onShowTrigger&&i.onShowTrigger(!i.onShowTrigger()),Object(M.delegateRun)(i,"onShowWithDelay",[],500)):(Object(M.delegateRun)(i,"onHide"),Object(M.delegateRun)(i,"onHideWithDelay",[],500),i.onHideTrigger&&i.onHideTrigger(!i.onHideTrigger()),i.restoreKeyScope(),f("view-model-on-hide",e),L.popupVisibilityNames.remove(i.viewModelName),i.viewModelDom.css("z-index",2e3),_.a.delay(function(){return i.viewModelDom.hide()},300))})),f("view-model-pre-build",e,n),N.a.applyBindingAccessorsToNode(n[0],{translatorInit:!0,template:function(){return{name:i.viewModelTemplateID}}},i),Object(M.delegateRun)(i,"onBuild",[n]),i&&G.Popup===a&&i.registerPopupKeyDown(),f("view-model-post-build",e,n)):Object(M.log)("Cannot find view model position: "+a)}return e?e.__vm:null}function h(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=d(e);n&&(m(n),n.__vm&&n.__dom&&(Object(M.delegateRun)(n.__vm,"onBeforeShow",t||[]),n.__vm.modalVisibility(!0),Object(M.delegateRun)(n.__vm,"onShow",t||[]),f("view-model-on-show",n,t||[])))}function g(e){var t=d(e);t&&(m(t),t.__vm&&t.__dom&&Object(M.delegateRun)(t.__vm,"onWarmUp"))}function b(e){var t=d(e);return!(!t||!t.__vm)&&t.__vm.modalVisibility()}function v(e,t){var n=null,i=!1,o=null;""===Object(M.pString)(e)&&(e=U),""!==e&&((n=u(e))||(n=u(U))&&(t=e+"/"+t,e=U),n&&n.__started&&(i=F&&n===F,n.__builded||(n.__builded=!0,Object(M.isNonEmptyArray)(n.viewModels())&&_.a.each(n.viewModels(),function(e){m(e,n)}),Object(M.delegateRun)(n,"onBuild")),_.a.defer(function(){F&&!i&&(Object(M.delegateRun)(F,"onHide"),Object(M.delegateRun)(F,"onHideWithDelay",[],500),F.onHideTrigger&&F.onHideTrigger(!F.onHideTrigger()),Object(M.isNonEmptyArray)(F.viewModels())&&_.a.each(F.viewModels(),function(e){e.__vm&&e.__dom&&G.Popup!==e.__vm.viewModelPosition&&(e.__dom.hide(),e.__vm.viewModelVisibility(!1),Object(M.delegateRun)(e.__vm,"onHide"),Object(M.delegateRun)(e.__vm,"onHideWithDelay",[],500),e.__vm.onHideTrigger&&e.__vm.onHideTrigger(!e.__vm.onHideTrigger()))})),(F=n)&&!i&&(Object(M.delegateRun)(F,"onShow"),F.onShowTrigger&&F.onShowTrigger(!F.onShowTrigger()),Object(k.f)("screen-on-show",[F.screenName(),F]),Object(M.isNonEmptyArray)(F.viewModels())&&_.a.each(F.viewModels(),function(e){e.__vm&&e.__dom&&G.Popup!==e.__vm.viewModelPosition&&(Object(M.delegateRun)(e.__vm,"onBeforeShow"),e.__dom.show(),e.__vm.viewModelVisibility(!0),Object(M.delegateRun)(e.__vm,"onShow"),e.__vm.onShowTrigger&&e.__vm.onShowTrigger(!e.__vm.onShowTrigger()),Object(M.delegateRun)(e.__vm,"onShowWithDelay",[],200),f("view-model-on-show",e))})),(o=n&&n.__cross?n.__cross():null)&&o.parse(t)})))}function S(e){_.a.each(e,function(e){if(e){var t=new e,n=t?t.screenName():"";t&&""!==n&&(""===U&&(U=n),H[n]=t)}}),_.a.each(H,function(e){e&&!e.__started&&e.__start&&(e.__started=!0,e.__start(),Object(k.f)("screen-pre-start",[e.screenName(),e]),Object(M.delegateRun)(e,"onStart"),Object(k.f)("screen-post-start",[e.screenName(),e]))});var t=x.a.create();t.addRoute(/^([a-zA-Z0-9\-]*)\/?(.*)$/,v),R.a.initialized.add(t.parse,t),R.a.changed.add(t.parse,t),R.a.init(),_.a.delay(function(){return L.$html.removeClass("rl-started-trigger").addClass("rl-started")},100),_.a.delay(function(){return L.$html.addClass("rl-started-delay")},200)}function y(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];e="/"===(e="#"===e.substr(0,1)?e.substr(1):e).substr(0,1)?e.substr(1):e;var i=n?"replaceHash":"setHash";t?(R.a.changed.active=!1,R.a[i](e),R.a.changed.active=!0):(R.a.changed.active=!0,R.a[i](e),R.a.setHash(e))}function w(e){var t=e.name,n=e.type,i=e.templateID;return function(e){e&&(t&&(Object(M.isArray)(t)?e.__names=t:e.__names=[t],e.__name=e.__names[0]),n&&(e.__type=n),i&&(e.__templateID=i))}}function A(e){var t=e.name,n=e.templateID;return w({name:t,type:G.Popup,templateID:n})}function O(){var e=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];return function(t,n,i){if(!n||!n.match(/Command$/))throw new Error('name "'+n+'" should end with Command suffix');var o=i.value||i.initializer(),a=Object(M.isFunc)(e)?e:function(){return!!e};return i.value=function(){if(a.call(this,this)){for(var e=arguments.length,t=Array(e),n=0;n1&&void 0!==arguments[1]&&arguments[1];m.a.defer(function(){g()("[data-i18n]",e).each(function(e,t){E(t)}),t&&y.bAnimationSupported&&g()(".i18n-animation[data-i18n]",e).letterfx({fx:"fall fade",backwards:!1,timing:50,fx_duration:"50ms",letter_end:"restore",element_end:"restore"})})}function a(){C.forEach(function(e){T[e[0]]=i(e[1])})}function r(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;e&&e(),t?_.subscribe(function(){e&&e(),t&&t()}):e&&_.subscribe(e)}function s(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;return e=p.a.parseInt(e,10)||0,v.Notification.ClientViewError===e&&t?t:(n=n&&p.a.parseInt(n,10)||0,Object(S.isUnd)(T[e])?n&&Object(S.isUnd)(T[n])?T[n]:"":T[e])}function c(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:v.Notification.UnknownNotification;return e&&e.ErrorCode?s(Object(S.pInt)(e.ErrorCode),e.ErrorMessage||""):s(t)}function l(e){var t="";switch(p.a.parseInt(e,10)||0){case v.UploadErrorCode.FileIsTooBig:t=i("UPLOAD/ERROR_FILE_IS_TOO_BIG");break;case v.UploadErrorCode.FilePartiallyUploaded:t=i("UPLOAD/ERROR_FILE_PARTIALLY_UPLOADED");break;case v.UploadErrorCode.FileNoUploaded:t=i("UPLOAD/ERROR_NO_FILE_UPLOADED");break;case v.UploadErrorCode.MissingTempFolder:t=i("UPLOAD/ERROR_MISSING_TEMP_FOLDER");break;case v.UploadErrorCode.FileOnSaveingError:t=i("UPLOAD/ERROR_ON_SAVING_FILE");break;case v.UploadErrorCode.FileType:t=i("UPLOAD/ERROR_FILE_TYPE");break;default:t=i("UPLOAD/ERROR_UNKNOWN")}return t}function u(e,t){var n=Object(S.microtime)();return y.$html.addClass("rl-changing-language"),new p.a.Promise(function(i,o){g.a.ajax({url:Object(A.n)(t,e),dataType:"script",cache:!0}).then(function(){m.a.delay(function(){D();var e=-10&&void 0!==arguments[0]?arguments[0]:"";return W+Object(q.pString)(e)}function r(){return ee?K:Y+te}function s(){return K}function c(e,t,n){return n=Object(q.isUnd)(n)?ne:n,Y+"/Raw/"+$+"/"+n+"/"+e+"/"+$+"/"+t}function l(e,t){return c("Download",e,t)}function u(e,t){return c("View",e,t)}function d(e,t){return c("ViewThumbnail",e,t)}function p(e,t){return c("ViewAsPlain",e,t)}function f(e,t){return c("FramedView",e,t)}function m(e){return Y+"/"+e+"/"+$+"/"+ne+"/"}function h(){return m("Upload")}function g(){return m("UploadContacts")}function b(){return m("UploadBackground")}function v(){return m("Append")}function S(e){return m("Change")+Object(q.encodeURIComponent)(e)+"/"}function y(e){return m("Ajax")+e}function w(e){return Y+"/Raw/"+$+"/"+ne+"/ViewAsPlain/"+$+"/"+e}function A(e){return Y+"/Raw/"+$+"/"+ne+"/Download/"+$+"/"+e}function O(e){return Y+"/Raw/0/Avatar/"+Object(q.encodeURIComponent)(e)+"/"}function T(e){return Y+"/Raw/"+$+"/"+ne+"/UserBackground/"+$+"/"+e}function C(){return Y+"/Info"}function _(e,t){return Y+"/Lang/0/"+(t?"Admin":"App")+"/"+V.a.encodeURI(e)+"/"+J+"/"}function E(){return Y+"/Raw/"+$+"/"+ne+"/ContactsVcf/"}function D(){return Y+"/Raw/"+$+"/"+ne+"/ContactsCsv/"}function N(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];return Y+"SocialGoogle"+(""!==ne?"/"+$+"/"+ne+"/":"")+(e?"&xauth=1":"")}function j(){return Y+"SocialTwitter"+(""!==ne?"/"+$+"/"+ne+"/":"")}function R(){return Y+"SocialFacebook"+(""!==ne?"/"+$+"/"+ne+"/":"")}function I(e){return Z+e}function x(){return I("css/images/empty-contact.png")}function P(e){return I("sounds/"+e)}function k(){return I("css/images/icom-message-notification.png")}function L(){return I("js/min/openpgp.min.js")}function M(){return I("js/min/openpgp.worker.min.js")}function F(e){var t=Q;return"@custom"===e.substr(-7)&&(e=Object(q.trim)(e.substring(0,e.length-7)),t=X),t+"themes/"+V.a.encodeURI(e)+"/images/preview.png"}function U(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"INBOX";return W+"mailbox/"+e}function H(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";return W+"settings"+(e?"/"+e:"")}function G(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"";t=Object(q.isNormal)(t)?Object(q.pInt)(t):1,n=Object(q.pString)(n);var o=W+"mailbox/";if(""!==e){var a=Object(q.pInt)(i);o+=V.a.encodeURI(e)+(01&&void 0!==arguments[1])||arguments[1];this.defaultRequest(e,"AdminDomainList",{IncludeAliases:t?"1":"0"})},t.prototype.pluginList=function(e){this.defaultRequest(e,"AdminPluginList")},t.prototype.packagesList=function(e){this.defaultRequest(e,"AdminPackagesList")},t.prototype.coreData=function(e){this.defaultRequest(e,"AdminCoreData")},t.prototype.updateCoreData=function(e){this.defaultRequest(e,"AdminUpdateCoreData",{},9e4)},t.prototype.packageInstall=function(e,t){this.defaultRequest(e,"AdminPackageInstall",{Id:t.id,Type:t.type,File:t.file},6e4)},t.prototype.packageDelete=function(e,t){this.defaultRequest(e,"AdminPackageDelete",{Id:t.id})},t.prototype.domain=function(e,t){this.defaultRequest(e,"AdminDomainLoad",{Name:t})},t.prototype.plugin=function(e,t){this.defaultRequest(e,"AdminPluginLoad",{Name:t})},t.prototype.domainDelete=function(e,t){this.defaultRequest(e,"AdminDomainDelete",{Name:t})},t.prototype.domainDisable=function(e,t,n){return this.defaultRequest(e,"AdminDomainDisable",{Name:t,Disabled:n?"1":"0"})},t.prototype.pluginSettingsUpdate=function(e,t){return this.defaultRequest(e,"AdminPluginSettingsUpdate",t)},t.prototype.licensing=function(e,t){return this.defaultRequest(e,"AdminLicensing",{Force:t?"1":"0"})},t.prototype.licensingActivate=function(e,t,n){return this.defaultRequest(e,"AdminLicensingActivate",{Domain:t,Key:n})},t.prototype.pluginDisable=function(e,t,n){return this.defaultRequest(e,"AdminPluginDisable",{Name:t,Disabled:n?"1":"0"})},t.prototype.createDomainAlias=function(e,t,n){this.defaultRequest(e,"AdminDomainAliasSave",{Name:t,Alias:n})},t.prototype.createOrUpdateDomain=function(e,t,n,i,o,a,r,s,c,l,u,d,p,f,m,h,g,b,v){this.defaultRequest(e,"AdminDomainSave",{Create:t?"1":"0",Name:n,IncHost:i,IncPort:o,IncSecure:a,IncShortLogin:r?"1":"0",UseSieve:s?"1":"0",SieveAllowRaw:c?"1":"0",SieveHost:l,SievePort:u,SieveSecure:d,OutHost:p,OutPort:f,OutSecure:m,OutShortLogin:h?"1":"0",OutAuth:g?"1":"0",OutUsePhpMail:b?"1":"0",WhiteList:v})},t.prototype.testConnectionForDomain=function(e,t,n,i,o,a,r,s,c,l,u,d,p,f){this.defaultRequest(e,"AdminDomainTest",{Name:t,IncHost:n,IncPort:i,IncSecure:o,UseSieve:a?"1":"0",SieveHost:r,SievePort:s,SieveSecure:c,OutHost:l,OutPort:u,OutSecure:d,OutAuth:p?"1":"0",OutUsePhpMail:f?"1":"0"})},t.prototype.testContacts=function(e,t){this.defaultRequest(e,"AdminContactsTest",t)},t.prototype.saveNewAdminPassword=function(e,t){this.defaultRequest(e,"AdminPasswordUpdate",t)},t.prototype.adminPing=function(e){this.defaultRequest(e,"AdminPing")},t}(n(115).a);t.a=new l},function(e,t,n){"use strict";function i(e,t,n){Object(s.isObject)(e)?(n=t||null,t=null,r.a.each(e,function(e,t){i(t,e,n)})):(Object(s.isUnd)(l[e])&&(l[e]=[]),l[e].push([t,n]))}function o(e,t){c.f("rl-pub",[e,t]),Object(s.isUnd)(l[e])||r.a.each(l[e],function(e){e[0]&&e[0].apply(e[1]||null,t||[])})}n.d(t,"b",function(){return i}),n.d(t,"a",function(){return o});var a=n(4),r=n.n(a),s=n(2),c=n(29),l={}},function(e,t,n){"use strict";n.d(t,"i",function(){return i}),n.d(t,"j",function(){return o}),n.d(t,"c",function(){return a}),n.d(t,"g",function(){return r}),n.d(t,"m",function(){return s}),n.d(t,"n",function(){return c}),n.d(t,"l",function(){return l}),n.d(t,"d",function(){return u}),n.d(t,"r",function(){return d}),n.d(t,"b",function(){return p}),n.d(t,"h",function(){return f}),n.d(t,"p",function(){return m}),n.d(t,"o",function(){return h}),n.d(t,"k",function(){return g}),n.d(t,"a",function(){return b}),n.d(t,"q",function(){return v}),n.d(t,"f",function(){return S}),n.d(t,"e",function(){return y});var i=20,o=[10,20,30,50,100],a=50,r=3e4,s=3e5,c=3e5,l=2e5,u=2e5,d="__UNUSE__",p="rlcsc",f=143,m=25,h=4190,g=15,b=7,v=10,S="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC4AAAAuCAYAAABXuSs3AAAHHklEQVRoQ7VZW08bVxCeXRuwIbTGXIwNtBBaqjwgVUiR8lDlbza9qe1DpVZ9aNQ/0KpPeaJK07SpcuEeCEmUAObm21bfrL9lONjexSYrWfbunj37zXdmvpkz9oIgCKTD0Wg0xPd94TDP83Q0zvWa50vzklSrdanVanqf4/D84GBGr+F+Op3S8fqoJxLOdnZgTvsO/nYhenHA+UC7CWF1uXwkb9++ldPTUwVerVbVqFQqpR8YPjQ0JCMjI5LNDijoRgP3PQVu5+5Eor2XGLg7IV4GkIdHJ/LmzRs5ODiIwNbrdR0O0GCcq4Xz4eFhmZyclP7+tDQaIik/BG5XKQn4SwG3zJTLZXn9+rUclI8UHD5YVoDDN8bSzXhONwL48fFxGR4eilzFZT1uFRIB5yT8BqCdnR3Z3d0VP9Un6XRawYJpggVrZBv38ME4XKtUKnLt2jUplUoy1PR/l3U7T6sVSAQcgMAkj8PDQ9ne3pajoyMRL7zeKsYZWHgWYDGmv78/mmdwcFA+mJlSgziHDWrERrsjEXDXegTi1tZW+DLxI2bxIrqFNYTXyDyCFweMAHCwb8e4RnTNuOsqe3t7sra21pTD0Kct666E8XlcZyzw9/RUUXK5nK5oUinUQI6TQ3cynO/v78vq6qrKXCNwlTiJJpyNGc3nZHp6uqV2dwrQWOCtZBDAV1ZWwsQk7f0wiQn5kffbAu/0/KWBYzIC1+XukfGx0RGZmppKlC2tIV0Bh4aDcZW7HhkfH8urLLZL7T2pihvlkMNnz56FiadHxicL41IsFpN41bkxsYxbRdFo9jwB8KdPn14J8KnSpBQKhQs63nPmbCVRcBUAR2Lq1VVmpksyMTFxAXjcEsQybiegESionjx5osCZOeNe1O4+EhCAX7bQSgQcxRHTMgAgcz5+/Dis/hL4uHU3/B4YGNASGHIKxuEql0k+l05AeIAF1vPnz5VxFFmdDlaJrMtZITJeSsXCOTlMunKxjLtMYOKNjQ158eJFuAuKkUOb5sEwgff19SkJUBVkThZUbnXZrtCKBQ6gbnWIkjZpyne3ejAWoGnA7Icz6irvBLgbOMicCM6TkxPx/LAkbXfgWcsazuE2kFRsKD5Z+CiqDumKncpZvieWcS6dDVD8xiYCNflpJdwcdwJOf9airLmVQ7DPzMxIYWLsXGXoVqLt5k0M3K3JUVPDZdbWNzsCp48TPFdvdnZWUz32nDha7bJ63kgAJPzSdRks9/Kf9xMJAQ1gq2NpaUmy2Yz4zar4nQC3xb99AQwCcGzLAAwuhG8YiWvcOKts+r4GOe5nMhm5efOm9lUA3E3vSZJRrKvE0fnPv//Jy5cvo5cTHIPQbSjhOoqq69evS19f6lxDKK4+sVhigZPtKJqbrQeqxd5+WR4+fKgqgT0k2XX3nhiPgETWXFhYkFzuPZ2yVq1GTSOXpE47/VjgNnD4m4GG7/LhsTx69EiwD4Vr2MwIIxgbAH18fKx1yfz8vEogNvGtWnCuhLZa9UTAreVWFsHy/b/+Vrbdl7E5REMQD2jDoUbByty+/ZnU64GkU2HzyJLhktU1cLv8nARgkYS2d3ajAgwG8qU2oLmDZ92CMaOjo7K4uCiZgbDWaRWgnZhPxLhrMUCvr69riwKZk1LHF7XqrWAO9hJxH6ozNzcnCx/PqztZg9mf6SQMscCtm2C5ke4BGMlHWTUp36036AJajDVrFMzBrhhWslQsSrFYiOqVpMriNYIgqFRq2j3FAb/zffT6zuxFXxsNzs3NTXn16lW4gYiW96w1FyedF+83xG/2FNGCRpU4NjamMsn+OZ9xE5RXqdaDdPpib6RWCzuwKF9RxqI2AVNQBwQYJoK0wdBejnqtEikP3pfP51XjUTESl12FqJEKxsEorARYDD44ONTeID7YpsEnrRvQfWAI2e8WfDaTUSIwJ0iBCmFOtOUAHvVMPp/TPwvYFVYFIuP8l+DBgwdaa2Miqwa0GgYwfeMltovbDfh6c1vIgMYcliSsKv4IWFr6VDHxvldvBAH+1sA+cnl5WYOPmmr9ir+1l9I0Cgz0yjhXjfJJ0JROnmezWbl165ayr/5fqwcBNr7IfhjMqKcvESSM4eRcCasQ3bDNObmKPLdGUGpZsN24cUNLBm9zazu4d++e6qpNBFaTuUS26U5dpuR1CxyA7J9ddrMRqlz4pwLLYawymPd++/2PADt2ugcGwq9gCCdhQ96C6xWwa6j1ceuq+I0EhW0i8MAIVJfeL3d/DVD8EKi12P6/2S2jV/EccVB54O/ejz/9HGCpoBBMta5rXMXLu53D1XAwjhXwvvv+h4BAXVe4bOu3O3ChxF08LiZFG3fel199G9CH3fLyqv24NcB44MRhpdK788U3CpyKwsCw590xmfSpzsBt0Fqc3ud3vtZigxWcVZCklVpSiN0w3q5E/h9TGMIUuA3+EQAAAABJRU5ErkJggg==",y="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC"},function(e,t,n){"use strict";n.d(t,"a",function(){return l});var i=n(8),o=n.n(i),a=n(1),r=n(2),s=n(0),c=n(6),l=function(){function e(){o()(this,e),this.bDisabeCloseOnEsc=!1,this.sDefaultKeyScope=s.KeyState.None,this.sCurrentKeyScope=s.KeyState.None,this.viewModelVisibility=a.a.observable(!1),this.modalVisibility=a.a.observable(!1).extend({rateLimit:0}),this.viewModelName="",this.viewModelNames=[],this.viewModelDom=null}return e.prototype.storeAndSetKeyScope=function(){this.sCurrentKeyScope=Object(c.keyScope)(),Object(c.keyScope)(this.sDefaultKeyScope)},e.prototype.restoreKeyScope=function(){Object(c.keyScope)(this.sCurrentKeyScope)},e.prototype.registerPopupKeyDown=function(){var e=this;c.$win.on("keydown",function(t){if(t&&e.modalVisibility&&e.modalVisibility()){if(!e.bDisabeCloseOnEsc&&s.EventKeyCode.Esc===t.keyCode)return Object(r.delegateRun)(e,"cancelCommand"),!1;if(s.EventKeyCode.Backspace===t.keyCode&&!Object(r.inFocus)())return!1}return!0})},e.prototype.cancelCommand=function(){},e.prototype.closeCommand=function(){},e}()},function(e,t,n){"use strict";var i=n(8),o=n.n(i),a=n(3),r=n.n(a),s=n(1),c=n(7),l=n.n(c),u=n(5),d=function(){function e(){var t=this;o()(this,e),this.google={},this.twitter={},this.facebook={},this.dropbox={},this.google.enabled=s.a.observable(!1),this.google.clientID=s.a.observable(""),this.google.clientSecret=s.a.observable(""),this.google.apiKey=s.a.observable(""),this.google.loading=s.a.observable(!1),this.google.userName=s.a.observable(""),this.google.loggined=s.a.computed(function(){return""!==t.google.userName()}),this.google.capa={},this.google.capa.auth=s.a.observable(!1),this.google.capa.authFast=s.a.observable(!1),this.google.capa.drive=s.a.observable(!1),this.google.capa.preview=s.a.observable(!1),this.google.require={},this.google.require.clientSettings=s.a.computed(function(){return t.google.enabled()&&(t.google.capa.auth()||t.google.capa.drive())}),this.google.require.apiKeySettings=s.a.computed(function(){return t.google.enabled()&&t.google.capa.drive()}),this.facebook.enabled=s.a.observable(!1),this.facebook.appID=s.a.observable(""),this.facebook.appSecret=s.a.observable(""),this.facebook.loading=s.a.observable(!1),this.facebook.userName=s.a.observable(""),this.facebook.supported=s.a.observable(!1),this.facebook.loggined=s.a.computed(function(){return""!==t.facebook.userName()}),this.twitter.enabled=s.a.observable(!1),this.twitter.consumerKey=s.a.observable(""),this.twitter.consumerSecret=s.a.observable(""),this.twitter.loading=s.a.observable(!1),this.twitter.userName=s.a.observable(""),this.twitter.loggined=s.a.computed(function(){return""!==t.twitter.userName()}),this.dropbox.enabled=s.a.observable(!1),this.dropbox.apiKey=s.a.observable("")}return e.prototype.populate=function(){this.google.enabled(!!u.settingsGet("AllowGoogleSocial")),this.google.clientID(u.settingsGet("GoogleClientID")),this.google.clientSecret(u.settingsGet("GoogleClientSecret")),this.google.apiKey(u.settingsGet("GoogleApiKey")),this.google.capa.auth(!!u.settingsGet("AllowGoogleSocialAuth")),this.google.capa.authFast(!!u.settingsGet("AllowGoogleSocialAuthFast")),this.google.capa.drive(!!u.settingsGet("AllowGoogleSocialDrive")),this.google.capa.preview(!!u.settingsGet("AllowGoogleSocialPreview")),this.facebook.enabled(!!u.settingsGet("AllowFacebookSocial")),this.facebook.appID(u.settingsGet("FacebookAppID")),this.facebook.appSecret(u.settingsGet("FacebookAppSecret")),this.facebook.supported(!!u.settingsGet("SupportedFacebookSocial")),this.twitter.enabled=s.a.observable(!!u.settingsGet("AllowTwitterSocial")),this.twitter.consumerKey=s.a.observable(u.settingsGet("TwitterConsumerKey")),this.twitter.consumerSecret=s.a.observable(u.settingsGet("TwitterConsumerSecret")),this.dropbox.enabled(!!u.settingsGet("AllowDropboxSocial")),this.dropbox.apiKey(u.settingsGet("DropboxApiKey"))},e.prototype.appendDropbox=function(){if(!r.a.Dropbox&&this.dropbox.enabled()&&this.dropbox.apiKey()&&!r.a.document.getElementById("dropboxjs")){var e=r.a.document.createElement("script");e.type="text/javascript",e.src="https://www.dropbox.com/static/api/2/dropins.js",l()(e).attr("id","dropboxjs").attr("data-app-key",this.dropbox.apiKey()),r.a.document.body.appendChild(e)}},e}();t.a=new d},,function(e,t,n){"use strict";n.d(t,"a",function(){return u}),n.d(t,"b",function(){return d});var i=n(8),o=n.n(i),a=n(7),r=n.n(a),s=n(1),c=n(2),l=n(10),u=function(){function e(){o()(this,e),this.disposable=[]}return e.prototype.dispose=function(){this.disposable.forEach(function(e){e&&e.dispose&&e.dispose()})},e}(),d=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return{template:t?{element:t}:" ",viewModel:{createViewModel:function(t,n){return(t=t||{}).element=null,n&&n.element&&(t.component=n,t.element=r()(n.element),Object(l.i18nToNodes)(t.element),!Object(c.isUnd)(t.inline)&&s.a.unwrap(t.inline)&&t.element.css("display","inline-block")),new e(t)}}}}},,function(e,t,n){"use strict";function i(e,t){Object(f.isFunc)(t)&&(Object(f.isArray)(g[e])||(g[e]=[]),g[e].push(t))}function o(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[];Object(f.isArray)(g[e])&&p.a.each(g[e],function(e){e.apply(void 0,t)})}function a(e){return h.settingsGet(e)}function r(e,t,n,i){m.data.__APP__&&m.data.__APP__.remote().defaultRequest(e,"Plugin"+t,n,i)}function s(e,t,n,i){b.push([e,t,n,i])}function c(e,t,n,i){v.push([e,t,n,i])}function l(e){var t=n(9);p.a.each(e?v:b,function(e){t.addSettingsViewModel(e[0],e[1],e[2],e[3])})}function u(e,t){var n=h.settingsGet("Plugins");return(n=n&&!Object(f.isUnd)(n[e])?n[e]:null)?Object(f.isUnd)(n[t])?null:n[t]:null}n.d(t,"a",function(){return i}),n.d(t,"f",function(){return o}),n.d(t,"d",function(){return a}),n.d(t,"e",function(){return r}),n.d(t,"b",function(){return s}),n.d(t,"c",function(){return c}),n.d(t,"g",function(){return l}),n.d(t,"h",function(){return u});var d=n(4),p=n.n(d),f=n(2),m=n(6),h=n(5),g={},b=[],v=[]},,,function(e,t,n){"use strict";var i=n(8),o=n.n(i),a=n(1),r=n(2),s=n(5),c=function(){function e(){o()(this,e),this.languages=a.a.observableArray([]),this.languagesAdmin=a.a.observableArray([]),this.language=a.a.observable("").extend({limitedList:this.languages}).extend({reversible:!0}),this.languageAdmin=a.a.observable("").extend({limitedList:this.languagesAdmin}).extend({reversible:!0}),this.userLanguage=a.a.observable(""),this.userLanguageAdmin=a.a.observable("")}return e.prototype.populate=function(){var e=s.appSettingsGet("languages"),t=s.appSettingsGet("languagesAdmin");this.languages(Object(r.isArray)(e)?e:[]),this.languagesAdmin(Object(r.isArray)(t)?t:[]),this.language(s.settingsGet("Language")),this.languageAdmin(s.settingsGet("LanguageAdmin")),this.userLanguage(s.settingsGet("UserLanguage")),this.userLanguageAdmin(s.settingsGet("UserLanguageAdmin"))},e}();t.a=new c},,function(e,t,n){"use strict";function i(){return y(),v||g()()}function o(){return w(),S||0}function a(e){return i().clone().subtract(e,"days").format("YYYY.MM.DD")}function r(e,t){var n=null,a="",r=o();if((n=0<(e=r<(e=0=t.diff(e,"hours"):return e.fromNow();case t.format("L")===e.format("L"):return Object(b.i18n)("MESSAGE_LIST/TODAY_AT",{TIME:e.format("LT")});case t.clone().subtract(1,"days").format("L")===e.format("L"):return Object(b.i18n)("MESSAGE_LIST/YESTERDAY_AT",{TIME:e.format("LT")});case t.year()===e.year():return e.format("D MMM.")}return e?e.format("LL"):""}(n);break;case"FULL":a=n.format("LLL");break;default:a=n.format(t)}return a}function s(e){var t,n="",i=m()(e);(t=i.data("moment-time"))&&((n=i.data("moment-format"))&&i.text(r(t,n)),(n=i.data("moment-format-title"))&&i.attr("title",r(t,n)))}function c(){p.a.defer(function(){m()(".moment",u.a.document).each(function(e,t){s(t)})})}n.r(t),n.d(t,"momentNow",function(){return i}),n.d(t,"momentNowUnix",function(){return o}),n.d(t,"searchSubtractFormatDateHelper",function(){return a}),n.d(t,"format",function(){return r}),n.d(t,"momentToNode",function(){return s}),n.d(t,"reload",function(){return c});var l=n(3),u=n.n(l),d=n(4),p=n.n(d),f=n(7),m=n.n(f),h=n(54),g=n.n(h),b=n(10),v=null,S=0,y=p.a.debounce(function(){v=g()()},500,!0),w=p.a.debounce(function(){S=g()().unix()},500,!0)},function(e,t){e.exports=window.hasher},,function(e,t,n){"use strict";function i(){return n(172).default}n.d(t,"a",function(){return i})},function(e,t,n){"use strict";var i=n(8),o=n.n(i),a=n(12),r=n.n(a),s=n(11),c=n.n(s),l=n(3),u=n.n(l),d=n(7),p=n.n(d),f=n(1),m=n(5),h=function(e){function t(){o()(this,t);var n=r()(this,e.call(this));return n.determineUserLanguage=f.a.observable(!1),n.determineUserDomain=f.a.observable(!1),n.weakPassword=f.a.observable(!1),n.useLocalProxyForExternalImages=f.a.observable(!1),n.dataFolderAccess=f.a.observable(!1),n}return c()(t,e),t.prototype.populate=function(){var t=this;e.prototype.populate.call(this),this.determineUserLanguage(!!Object(m.settingsGet)("DetermineUserLanguage")),this.determineUserDomain(!!Object(m.settingsGet)("DetermineUserDomain")),this.weakPassword(!!Object(m.settingsGet)("WeakPassword")),this.useLocalProxyForExternalImages(!!Object(m.settingsGet)("UseLocalProxyForExternalImages")),Object(m.settingsGet)("Auth")&&p.a.get("./data/VERSION?"+u.a.Math.random()).then(function(){return t.dataFolderAccess(!0)})},t}(n(116).a);t.a=new h},function(e,t,n){"use strict";var i=n(8),o=n.n(i),a=n(1),r=n(2),s=n(5),c=function(){function e(){o()(this,e),this.themes=a.a.observableArray([]),this.themeBackgroundName=a.a.observable(""),this.themeBackgroundHash=a.a.observable(""),this.theme=a.a.observable("").extend({limitedList:this.themes})}return e.prototype.populate=function(){var e=s.appSettingsGet("themes");this.themes(Object(r.isArray)(e)?e:[]),this.theme(s.settingsGet("Theme")),this.themeBackgroundName(s.settingsGet("UserBackgroundName")),this.themeBackgroundHash(s.settingsGet("UserBackgroundHash"))},e}();t.a=new c},function(e,t){var n=e.exports={version:"2.5.1"};"number"==typeof __e&&(__e=n)},function(e,t){var n=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},function(e,t,n){e.exports=!n(51)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(e,t,n){var i=n(109),o=n(73);e.exports=function(e){return i(o(e))}},function(e,t,n){"use strict";n.r(t),n.d(t,"EmailModel",function(){return u}),n.d(t,"default",function(){return u});var i=n(8),o=n.n(i),a=n(4),r=n.n(a),s=n(76),c=n.n(s),l=n(2),u=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"none",a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"";o()(this,e),this.email="",this.name="",this.dkimStatus="",this.dkimValue="",this.email=t,this.name=n,this.dkimStatus=i,this.dkimValue=a,this.clearDuplicateName()}return e.newInstanceFromJson=function(t){var n=new e;return n.initByJson(t)?n:null},e.prototype.clear=function(){this.email="",this.name="",this.dkimStatus="none",this.dkimValue=""},e.prototype.validate=function(){return""!==this.name||""!==this.email},e.prototype.hash=function(){return"#"+(arguments.length>0&&void 0!==arguments[0]&&arguments[0]?"":this.name)+"#"+this.email+"#"},e.prototype.clearDuplicateName=function(){this.name===this.email&&(this.name="")},e.prototype.search=function(e){return-1<(this.name+" "+this.email).toLowerCase().indexOf(e.toLowerCase())},e.prototype.initByJson=function(e){var t=!1;return e&&"Object/Email"===e["@Object"]&&(this.name=Object(l.trim)(e.Name),this.email=Object(l.trim)(e.Email),this.dkimStatus=Object(l.trim)(e.DkimStatus||""),this.dkimValue=Object(l.trim)(e.DkimValue||""),t=""!==this.email,this.clearDuplicateName()),t},e.prototype.toLine=function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],i="";return""!==this.email&&(e&&""!==this.name?i=t?'")+'" target="_blank" tabindex="-1">'+Object(l.encodeHtml)(this.name)+" ":n?Object(l.encodeHtml)(this.name):this.name:(i=this.email,""!==this.name?t?i=Object(l.encodeHtml)('"'+this.name+'" <')+'")+'" target="_blank" tabindex="-1">'+Object(l.encodeHtml)(i)+" "+Object(l.encodeHtml)(">"):(i='"'+this.name+'" <'+i+">",n&&(i=Object(l.encodeHtml)(i))):t&&(i=''+Object(l.encodeHtml)(this.email)+" "))),i},e.splitEmailLine=function(t){var n=c()(t);if(Object(l.isNonEmptyArray)(n)){var i=[],o=!1;return n.forEach(function(t){var n=t.address?new e(t.address.replace(/^[<]+(.*)[>]+$/g,"$1"),t.name||""):null;n&&n.email&&(o=!0),i.push(n?n.toLine(!1):t.name)}),o?i:null}return null},e.parseEmailLine=function(t){var n=c()(t);return Object(l.isNonEmptyArray)(n)?r.a.compact(n.map(function(t){return t.address?new e(t.address.replace(/^[<]+(.*)[>]+$/g,"$1"),t.name||""):null})):[]},e.prototype.parse=function(e){if(""===(e=Object(l.trim)(e)))return!1;var t=c()(e);return!(!Object(l.isNonEmptyArray)(t)||!t[0]||(this.name=t[0].name||"",this.email=t[0].address||"",this.clearDuplicateName(),0))},e}()},,function(e,t){var n={}.hasOwnProperty;e.exports=function(e,t){return n.call(e,t)}},function(e,t,n){"use strict";n.d(t,"a",function(){return p});var i=n(8),o=n.n(i),a=n(12),r=n.n(a),s=n(11),c=n.n(s),l=n(1),u=n(2),d=n(0),p=function(e){function t(n){o()(this,t);var i=r()(this,e.call(this));return i.value=n.value||"",i.size=n.size||0,i.label=n.label||"",i.preLabel=n.preLabel||"",i.enable=!!Object(u.isUnd)(n.enable)||n.enable,i.trigger=n.trigger&&n.trigger.subscribe?n.trigger:null,i.placeholder=n.placeholder||"",i.labeled=!Object(u.isUnd)(n.label),i.preLabeled=!Object(u.isUnd)(n.preLabel),i.triggered=!Object(u.isUnd)(n.trigger)&&!!i.trigger,i.classForTrigger=l.a.observable(""),i.className=l.a.computed(function(){var e=l.a.unwrap(i.size),t=i.trigger?" "+Object(u.trim)("settings-saved-trigger-input "+i.classForTrigger()):"";return(01&&void 0!==arguments[1]&&arguments[1];if(!a.a.Promise||!a.a.Promise.all)throw new Error("Promises are not available your environment.");if(!e)throw new Error("src should not be empty.");return new a.a.Promise(function(n,i){var o=a.a.document.createElement("script");o.onload=function(){n(e)},o.onerror=function(){i(new Error(e))},o.async=!0===t,o.src=e,a.a.document.body.appendChild(o)})}n.d(t,"a",function(){return i});var o=n(3),a=n.n(o)},function(e,t,n){var i=n(85)("wks"),o=n(70),a=n(41).Symbol,r="function"==typeof a;(e.exports=function(e){return i[e]||(i[e]=r&&a[e]||(r?a:o)("Symbol."+e))}).store=i},function(e,t,n){var i=n(52);e.exports=function(e){if(!i(e))throw TypeError(e+" is not an object!");return e}},,,function(e,t){e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},function(e,t,n){"use strict";n.d(t,"a",function(){return u});var i=n(8),o=n.n(i),a=n(4),r=n.n(a),s=n(75),c=n.n(s),l=n(2),u=function(){function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[];o()(this,e),this.oCross=null,this.sScreenName=t,this.aViewModels=Object(l.isArray)(n)?n:[]}return e.prototype.viewModels=function(){return this.aViewModels},e.prototype.screenName=function(){return this.sScreenName},e.prototype.routes=function(){return null},e.prototype.__cross=function(){return this.oCross},e.prototype.__start=function(){var e=null,t=null,n=this.routes();Object(l.isNonEmptyArray)(n)&&(t=r.a.bind(this.onRoute||l.noop,this),e=c.a.create(),n.forEach(function(n){n&&e&&(e.addRoute(n[0],t).rules=n[1])}),this.oCross=e)},e}()},function(e,t){e.exports=window.ssm},function(e,t,n){var i=n(52);e.exports=function(e,t){if(!i(e))return e;var n,o;if(t&&"function"==typeof(n=e.toString)&&!i(o=n.call(e)))return o;if("function"==typeof(n=e.valueOf)&&!i(o=n.call(e)))return o;if(!t&&"function"==typeof(n=e.toString)&&!i(o=n.call(e)))return o;throw TypeError("Can't convert object to primitive value")}},function(e,t,n){"use strict";var i=n(8),o=n.n(i),a=n(1);t.a=new function e(){o()(this,e),this.domains=a.a.observableArray([]),this.domains.loading=a.a.observable(!1).extend({throttle:100}),this.domainsWithoutAliases=this.domains.filter(function(e){return e&&!e.alias})}},,function(e,t){var n=0,i=Math.random();e.exports=function(e){return"Symbol(".concat(void 0===e?"":e,")_",(++n+i).toString(36))}},function(e,t){t.f={}.propertyIsEnumerable},function(e,t,n){var i=n(71),o=n(64),a=n(43),r=n(67),s=n(46),c=n(77),l=Object.getOwnPropertyDescriptor;t.f=n(42)?l:function(e,t){if(e=a(e),t=r(t,!0),c)try{return l(e,t)}catch(e){}if(s(e,t))return o(!i.f.call(e,t),e[t])}},function(e,t){e.exports=function(e){if(void 0==e)throw TypeError("Can't call method on "+e);return e}},function(e,t,n){"use strict";n.d(t,"a",function(){return d});var i=n(8),o=n.n(i),a=n(12),r=n.n(a),s=n(11),c=n.n(s),l=n(1),u=n(2),d=function(e){function t(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};o()(this,t);var i=r()(this,e.call(this));return i.value=n.value,!Object(u.isUnd)(i.value)&&i.value.subscribe||(i.value=l.a.observable(!Object(u.isUnd)(i.value)&&!!i.value)),i.enable=n.enable,!Object(u.isUnd)(i.enable)&&i.enable.subscribe||(i.enable=l.a.observable(!!Object(u.isUnd)(i.enable)||!!i.enable)),i.disable=n.disable,!Object(u.isUnd)(i.disable)&&i.disable.subscribe||(i.disable=l.a.observable(!Object(u.isUnd)(i.disable)&&!!i.disable)),i.label=n.label||"",i.inline=!Object(u.isUnd)(n.inline)&&n.inline,i.readOnly=!Object(u.isUnd)(n.readOnly)&&!!n.readOnly,i.inverted=!Object(u.isUnd)(n.inverted)&&!!n.inverted,i.labeled=!Object(u.isUnd)(n.label),i.labelAnimated=!!n.labelAnimated,i}return c()(t,e),t.prototype.click=function(){this.readOnly||!this.enable()||this.disable()||this.value(!this.value())},t}(n(27).a)},function(e,t){e.exports=window.crossroads},function(e,t,n){"use strict";function i(e){var t=[],n=[],o=[];return new r(e).tokenize().forEach(function(e){"operator"!==e.type||","!==e.value&&";"!==e.value?n.push(e):(n.length&&t.push(n),n=[])}),n.length&&t.push(n),t.forEach(function(e){(e=function(e){for(var t=!1,n="text",o=void 0,a=[],r={address:[],comment:[],group:[],text:[]},s=0,c=e.length;s=0;u--)if(r.text[u].match(/^[^@\s]+@[^@\s]+$/)){r.address=r.text.splice(u,1);break}if(!r.address.length)for(var d=r.text.length-1;d>=0&&(r.text[d]=r.text[d].replace(/\s*\b[^@\s]+@[^@\s]+\b\s*/,function(e){return r.address.length?e:(r.address=[e.trim()]," ")}).trim(),!r.address.length);d--);}if(!r.text.length&&r.comment.length&&(r.text=r.comment,r.comment=[]),r.address.length>1&&(r.text=r.text.concat(r.address.splice(1))),r.text=r.text.join(" "),r.address=r.address.join(" "),!r.address&&t)return[];(o={address:r.address||r.text||"",name:r.text||r.address||""}).address===o.name&&((o.address||"").match(/@/)?o.name="":o.address=""),a.push(o)}return a}(e)).length&&(o=o.concat(e))}),o}Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e,t){for(var n=0;n",",":"",":":";",";":""},r=function(){function e(t){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.str=(t||"").toString(),this.operatorCurrent="",this.operatorExpecting="",this.node=null,this.escaped=!1,this.list=[]}return o(e,[{key:"tokenize",value:function(){for(var e=void 0,t=[],n=0,i=this.str.length;ndocument.F=Object<\/script>"),e.close(),c=e.F;i--;)delete c.prototype[a[i]];return c()};e.exports=Object.create||function(e,t){var n;return null!==e?(s.prototype=i(e),n=new s,s.prototype=null,n[r]=e):n=c(),void 0===t?n:o(n,t)}},function(e,t){e.exports={}},function(e,t){e.exports=!0},function(e,t){var n=Math.ceil,i=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?i:n)(e)}},function(e,t){var n={}.toString;e.exports=function(e){return n.call(e).slice(8,-1)}},function(e,t,n){var i=n(52),o=n(41).document,a=i(o)&&i(o.createElement);e.exports=function(e){return a?o.createElement(e):{}}},function(e,t,n){var i=n(112);e.exports=function(e,t,n){if(i(e),void 0===t)return e;switch(n){case 1:return function(n){return e.call(t,n)};case 2:return function(n,i){return e.call(t,n,i)};case 3:return function(n,i,o){return e.call(t,n,i,o)}}return function(){return e.apply(t,arguments)}}},function(e,t,n){"use strict";n.r(t),n.d(t,"HtmlEditor",function(){return m}),n.d(t,"default",function(){return m});var i=n(8),o=n.n(i),a=n(3),r=n.n(a),s=n(4),c=n.n(s),l=n(7),u=n.n(l),d=n(6),p=n(0),f=n(5),m=function(){function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null;o()(this,e),this.blurTimer=0,this.__resizable=!1,this.__inited=!1,this.onBlur=null,this.onReady=null,this.onModeChange=null,this.onBlur=n,this.onReady=i,this.onModeChange=a,this.element=t,this.$element=u()(t),this.resize=c.a.throttle(c.a.bind(this.resizeEditor,this),100),this.init()}return e.prototype.runOnBlur=function(){this.onBlur&&this.onBlur()},e.prototype.blurTrigger=function(){var e=this;this.onBlur&&(r.a.clearTimeout(this.blurTimer),this.blurTimer=r.a.setTimeout(function(){e.runOnBlur()},p.Magics.Time200ms))},e.prototype.focusTrigger=function(){this.onBlur&&r.a.clearTimeout(this.blurTimer)},e.prototype.isHtml=function(){return!!this.editor&&"wysiwyg"===this.editor.mode},e.prototype.clearCachedSignature=function(){this.editor&&this.editor.execCommand("insertSignature",{clearCache:!0})},e.prototype.setSignature=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];this.editor&&this.editor.execCommand("insertSignature",{isHtml:t,insertBefore:n,signature:e})},e.prototype.checkDirty=function(){return!!this.editor&&this.editor.checkDirty()},e.prototype.resetDirty=function(){this.editor&&this.editor.resetDirty()},e.prototype.getData=function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0],t="";if(this.editor)try{t="plain"===this.editor.mode&&this.editor.plugins.plain&&this.editor.__plain?this.editor.__plain.getRawData():e?' '+this.editor.getData()+"
":this.editor.getData()}catch(e){}return t},e.prototype.getDataWithHtmlMark=function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];return(this.isHtml()?":HTML:":"")+this.getData(e)},e.prototype.modeToggle=function(e,t){if(this.editor){try{e?"plain"===this.editor.mode&&this.editor.setMode("wysiwyg"):"wysiwyg"===this.editor.mode&&this.editor.setMode("plain")}catch(e){}t&&this.resize()}},e.prototype.setHtmlOrPlain=function(e,t){":HTML:"===e.substr(0,6)?this.setHtml(e.substr(6),t):this.setPlain(e,t)},e.prototype.setHtml=function(e,t){if(this.editor&&this.__inited){this.clearCachedSignature(),this.modeToggle(!0),e=e.replace(/]*><\/p>/gi,"");try{this.editor.setData(e)}catch(e){}t&&this.focus()}},e.prototype.replaceHtml=function(e,t){if(this.editor&&this.__inited&&"wysiwyg"===this.editor.mode)try{this.editor.setData(this.editor.getData().replace(e,t))}catch(e){}},e.prototype.setPlain=function(e,t){if(this.editor&&this.__inited){if(this.clearCachedSignature(),this.modeToggle(!1),"plain"===this.editor.mode&&this.editor.plugins.plain&&this.editor.__plain)this.editor.__plain.setRawData(e);else try{this.editor.setData(e)}catch(e){}t&&this.focus()}},e.prototype.init=function(){var e=this;if(this.element&&!this.editor){var t=function(){var t=d.htmlEditorDefaultConfig,n=f.settingsGet("Language"),i=!!f.appSettingsGet("allowHtmlEditorSourceButton"),o=!!f.appSettingsGet("allowHtmlEditorBitiButtons");!i&&o||t.toolbarGroups.__cfgInited||(t.toolbarGroups.__cfgInited=!0,i&&(t.removeButtons=t.removeButtons.replace(",Source","")),o||(t.removePlugins+=(t.removePlugins?",":"")+"bidi")),t.enterMode=r.a.CKEDITOR.ENTER_BR,t.shiftEnterMode=r.a.CKEDITOR.ENTER_P,t.language=d.htmlEditorLangsMap[(n||"en").toLowerCase()]||"en",r.a.CKEDITOR.env&&(r.a.CKEDITOR.env.isCompatible=!0),e.editor=r.a.CKEDITOR.appendTo(e.element,t),e.editor.on("key",function(e){return!e||!e.data||p.EventKeyCode.Tab!==e.data.keyCode}),e.editor.on("blur",function(){e.blurTrigger()}),e.editor.on("mode",function(){e.blurTrigger(),e.onModeChange&&e.onModeChange("plain"!==e.editor.mode)}),e.editor.on("focus",function(){e.focusTrigger()}),r.a.FileReader&&e.editor.on("drop",function(t){if(0 ')},o.readAsDataURL(n),t.data.dataTransfer.setData("text/html",i)}}}),e.editor.on("instanceReady",function(){e.editor.removeMenuItem&&(e.editor.removeMenuItem("cut"),e.editor.removeMenuItem("copy"),e.editor.removeMenuItem("paste")),e.__resizable=!0,e.__inited=!0,e.resize(),e.onReady&&e.onReady()})};r.a.CKEDITOR?t():r.a.__initEditor=t}},e.prototype.focus=function(){if(this.editor)try{this.editor.focus()}catch(e){}},e.prototype.hasFocus=function(){if(this.editor)try{return!!this.editor.focusManager.hasFocus}catch(e){}return!1},e.prototype.blur=function(){if(this.editor)try{this.editor.focusManager.blur(!0)}catch(e){}},e.prototype.resizeEditor=function(){if(this.editor&&this.__resizable)try{this.editor.resize(this.$element.width(),this.$element.innerHeight())}catch(e){}},e.prototype.setReadOnly=function(e){if(this.editor)try{this.editor.setReadOnly(!!e)}catch(e){}},e.prototype.clear=function(e){this.setHtml("",e)},e}()},function(e,t){e.exports=window.Autolinker},function(e,t,n){!function(t,i){"use strict";var o;try{o=n(54)}catch(e){}e.exports=function(e){var t="function"==typeof e,n=!!window.addEventListener,i=window.document,o=window.setTimeout,a=function(e,t,i,o){n?e.addEventListener(t,i,!!o):e.attachEvent("on"+t,i)},r=function(e,t,i,o){n?e.removeEventListener(t,i,!!o):e.detachEvent("on"+t,i)},s=function(e,t){return-1!==(" "+e.className+" ").indexOf(" "+t+" ")},c=function(e){return/Array/.test(Object.prototype.toString.call(e))},l=function(e){return/Date/.test(Object.prototype.toString.call(e))&&!isNaN(e.getTime())},u=function(e){var t=e.getDay();return 0===t||6===t},d=function(e,t){return[31,function(e){return e%4==0&&e%100!=0||e%400==0}(e)?29:28,31,30,31,30,31,31,30,31,30,31][t]},p=function(e){l(e)&&e.setHours(0,0,0,0)},f=function(e,t){return e.getTime()===t.getTime()},m=function(e,t,n){var i,o;for(i in t)(o=void 0!==e[i])&&"object"==typeof t[i]&&null!==t[i]&&void 0===t[i].nodeName?l(t[i])?n&&(e[i]=new Date(t[i].getTime())):c(t[i])?n&&(e[i]=t[i].slice(0)):e[i]=m({},t[i],n):!n&&o||(e[i]=t[i]);return e},h=function(e,t,n){var o;i.createEvent?((o=i.createEvent("HTMLEvents")).initEvent(t,!0,!1),o=m(o,n),e.dispatchEvent(o)):i.createEventObject&&(o=i.createEventObject(),o=m(o,n),e.fireEvent("on"+t,o))},g=function(e){return e.month<0&&(e.year-=Math.ceil(Math.abs(e.month)/12),e.month+=12),e.month>11&&(e.year+=Math.floor(Math.abs(e.month)/12),e.month-=12),e},b={field:null,bound:void 0,position:"bottom left",reposition:!0,format:"YYYY-MM-DD",toString:null,parse:null,defaultDate:null,setDefaultDate:!1,firstDay:0,formatStrict:!1,minDate:null,maxDate:null,yearRange:10,showWeekNumber:!1,pickWholeWeek:!1,minYear:0,maxYear:9999,minMonth:void 0,maxMonth:void 0,startRange:null,endRange:null,isRTL:!1,yearSuffix:"",showMonthAfterYear:!1,showDaysInNextAndPreviousMonths:!1,enableSelectionDaysInNextAndPreviousMonths:!1,numberOfMonths:1,mainCalendar:"left",container:void 0,blurFieldOnSelect:!0,i18n:{previousMonth:"Previous Month",nextMonth:"Next Month",months:["January","February","March","April","May","June","July","August","September","October","November","December"],weekdays:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],weekdaysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]},theme:null,events:[],onSelect:null,onOpen:null,onClose:null,onDraw:null,keyboardInput:!0},v=function(e,t,n){for(t+=e.firstDay;t>=7;)t-=7;return n?e.i18n.weekdaysShort[t]:e.i18n.weekdays[t]},S=function(e){var t=[],n="false";if(e.isEmpty){if(!e.showDaysInNextAndPreviousMonths)return'
';t.push("is-outside-current-month"),e.enableSelectionDaysInNextAndPreviousMonths||t.push("is-selection-disabled")}return e.isDisabled&&t.push("is-disabled"),e.isToday&&t.push("is-today"),e.isSelected&&(t.push("is-selected"),n="true"),e.hasEvent&&t.push("has-event"),e.isInRange&&t.push("is-inrange"),e.isStartRange&&t.push("is-startrange"),e.isEndRange&&t.push("is-endrange"),''+e.day+" "},y=function(e,t,n,i){return''+(t?e.reverse():e).join("")+" "},w=function(e,t,n,i,o,a){var r,s,l,u,d,p=e._o,f=n===p.minYear,m=n===p.maxYear,h='',g=!0,b=!0;for(l=[],r=0;r<12;r++)l.push('
p.maxMonth?'disabled="disabled"':"")+">"+p.i18n.months[r]+" ");for(u='
'+p.i18n.months[i]+''+l.join("")+"
",c(p.yearRange)?(r=p.yearRange[0],s=p.yearRange[1]+1):(r=n-p.yearRange,s=1+n+p.yearRange),l=[];r
=p.minYear&&l.push('"+r+" ");return d=' '+n+p.yearSuffix+''+l.join("")+"
",p.showMonthAfterYear?h+=d+u:h+=u+d,f&&(0===i||p.minMonth>=i)&&(g=!1),m&&(11===i||p.maxMonth<=i)&&(b=!1),0===t&&(h+=''+p.i18n.previousMonth+" "),t===e._o.numberOfMonths-1&&(h+=''+p.i18n.nextMonth+" "),h+=" "},A=function(r){var c=this,u=c.config(r);c._onMouseDown=function(e){if(c._v){var t=(e=e||window.event).target||e.srcElement;if(t)if(s(t,"is-disabled")||(!s(t,"pika-button")||s(t,"is-empty")||s(t.parentNode,"is-disabled")?s(t,"pika-prev")?c.prevMonth():s(t,"pika-next")&&c.nextMonth():(c.setDate(new Date(t.getAttribute("data-pika-year"),t.getAttribute("data-pika-month"),t.getAttribute("data-pika-day"))),u.bound&&o(function(){c.hide(),u.blurFieldOnSelect&&u.field&&u.field.blur()},100))),s(t,"pika-select"))c._c=!0;else{if(!e.preventDefault)return e.returnValue=!1,!1;e.preventDefault()}}},c._onChange=function(e){var t=(e=e||window.event).target||e.srcElement;t&&(s(t,"pika-select-month")?c.gotoMonth(t.value):s(t,"pika-select-year")&&c.gotoYear(t.value))},c._onKeyChange=function(e){if(e=e||window.event,c.isVisible())switch(e.keyCode){case 13:case 27:u.field&&u.field.blur();break;case 37:e.preventDefault(),c.adjustDate("subtract",1);break;case 38:c.adjustDate("subtract",7);break;case 39:c.adjustDate("add",1);break;case 40:c.adjustDate("add",7)}},c._onInputChange=function(n){var i;n.firedBy!==c&&(i=u.parse?u.parse(u.field.value,u.format):t?(i=e(u.field.value,u.format,u.formatStrict))&&i.isValid()?i.toDate():null:new Date(Date.parse(u.field.value)),l(i)&&c.setDate(i),c._v||c.show())},c._onInputFocus=function(){c.show()},c._onInputClick=function(){c.show()},c._onInputBlur=function(){var e=i.activeElement;do{if(s(e,"pika-single"))return}while(e=e.parentNode);c._c||(c._b=o(function(){c.hide()},50)),c._c=!1},c._onClick=function(e){var t=(e=e||window.event).target||e.srcElement,i=t;if(t){!n&&s(t,"pika-select")&&(t.onchange||(t.setAttribute("onchange","return;"),a(t,"change",c._onChange)));do{if(s(i,"pika-single")||i===u.trigger)return}while(i=i.parentNode);c._v&&t!==u.trigger&&i!==u.trigger&&c.hide()}},c.el=i.createElement("div"),c.el.className="pika-single"+(u.isRTL?" is-rtl":"")+(u.theme?" "+u.theme:""),a(c.el,"mousedown",c._onMouseDown,!0),a(c.el,"touchend",c._onMouseDown,!0),a(c.el,"change",c._onChange),u.keyboardInput&&a(i,"keydown",c._onKeyChange),u.field&&(u.container?u.container.appendChild(c.el):u.bound?i.body.appendChild(c.el):u.field.parentNode.insertBefore(c.el,u.field.nextSibling),a(u.field,"change",c._onInputChange),u.defaultDate||(t&&u.field.value?u.defaultDate=e(u.field.value,u.format).toDate():u.defaultDate=new Date(Date.parse(u.field.value)),u.setDefaultDate=!0));var d=u.defaultDate;l(d)?u.setDefaultDate?c.setDate(d,!0):c.gotoDate(d):c.gotoDate(new Date),u.bound?(this.hide(),c.el.className+=" is-bound",a(u.trigger,"click",c._onInputClick),a(u.trigger,"focus",c._onInputFocus),a(u.trigger,"blur",c._onInputBlur)):this.show()};return A.prototype={config:function(e){this._o||(this._o=m({},b,!0));var t=m(this._o,e,!0);t.isRTL=!!t.isRTL,t.field=t.field&&t.field.nodeName?t.field:null,t.theme="string"==typeof t.theme&&t.theme?t.theme:null,t.bound=!!(void 0!==t.bound?t.field&&t.bound:t.field),t.trigger=t.trigger&&t.trigger.nodeName?t.trigger:t.field,t.disableWeekends=!!t.disableWeekends,t.disableDayFn="function"==typeof t.disableDayFn?t.disableDayFn:null;var n=parseInt(t.numberOfMonths,10)||1;if(t.numberOfMonths=n>4?4:n,l(t.minDate)||(t.minDate=!1),l(t.maxDate)||(t.maxDate=!1),t.minDate&&t.maxDate&&t.maxDate100&&(t.yearRange=100);return t},toString:function(n){return n=n||this._o.format,l(this._d)?this._o.toString?this._o.toString(this._d,n):t?e(this._d).format(n):this._d.toDateString():""},getMoment:function(){return t?e(this._d):null},setMoment:function(n,i){t&&e.isMoment(n)&&this.setDate(n.toDate(),i)},getDate:function(){return l(this._d)?new Date(this._d.getTime()):null},setDate:function(e,t){if(!e)return this._d=null,this._o.field&&(this._o.field.value="",h(this._o.field,"change",{firedBy:this})),this.draw();if("string"==typeof e&&(e=new Date(Date.parse(e))),l(e)){var n=this._o.minDate,i=this._o.maxDate;l(n)&&ei&&(e=i),this._d=new Date(e.getTime()),p(this._d),this.gotoDate(this._d),this._o.field&&(this._o.field.value=this.toString(),h(this._o.field,"change",{firedBy:this})),t||"function"!=typeof this._o.onSelect||this._o.onSelect.call(this,this.getDate())}},gotoDate:function(e){var t=!0;if(l(e)){if(this.calendars){var n=new Date(this.calendars[0].year,this.calendars[0].month,1),i=new Date(this.calendars[this.calendars.length-1].year,this.calendars[this.calendars.length-1].month,1),o=e.getTime();i.setMonth(i.getMonth()+1),i.setDate(i.getDate()-1),t=o=a&&(this._y=a,!isNaN(s)&&this._m>s&&(this._m=s)),t="pika-title-"+Math.random().toString(36).replace(/[^a-z]+/g,"").substr(0,2);for(var l=0;l'+w(this,l,this.calendars[l].year,this.calendars[l].month,this.calendars[0].year,t)+this.render(this.calendars[l].year,this.calendars[l].month,t)+"";this.el.innerHTML=c,n.bound&&"hidden"!==n.field.type&&o(function(){n.trigger.focus()},1),"function"==typeof this._o.onDraw&&this._o.onDraw(this),n.bound&&n.field.setAttribute("aria-label","Use the arrow keys to pick a date")}},adjustPosition:function(){var e,t,n,o,a,r,s,c,l,u;if(!this._o.container){if(this.el.style.position="absolute",t=e=this._o.trigger,n=this.el.offsetWidth,o=this.el.offsetHeight,a=window.innerWidth||i.documentElement.clientWidth,r=window.innerHeight||i.documentElement.clientHeight,s=window.pageYOffset||i.body.scrollTop||i.documentElement.scrollTop,"function"==typeof e.getBoundingClientRect)c=(u=e.getBoundingClientRect()).left+window.pageXOffset,l=u.bottom+window.pageYOffset;else for(c=t.offsetLeft,l=t.offsetTop+t.offsetHeight;t=t.offsetParent;)c+=t.offsetLeft,l+=t.offsetTop;(this._o.reposition&&c+n>a||this._o.position.indexOf("right")>-1&&c-n+e.offsetWidth>0)&&(c=c-n+e.offsetWidth),(this._o.reposition&&l+o>r+s||this._o.position.indexOf("top")>-1&&l-o-e.offsetHeight>0)&&(l=l-o-e.offsetHeight),this.el.style.left=c+"px",this.el.style.top=l+"px"}},render:function(e,t,n){var i=this._o,o=new Date,a=d(e,t),r=new Date(e,t,1).getDay(),s=[],c=[];p(o),i.firstDay>0&&(r-=i.firstDay)<0&&(r+=7);for(var m=0===t?11:t-1,h=11===t?0:t+1,g=0===t?e-1:e,b=11===t?e+1:e,w=d(g,m),A=a+r,O=A;O>7;)O-=7;A+=7-O;for(var T,C,_,E,D=!1,N=0,j=0;N=a+r,L=N-r+1,M=t,F=e,U=i.startRange&&f(i.startRange,R),H=i.endRange&&f(i.endRange,R),G=i.startRange&&i.endRange&&i.startRangei.maxDate||i.disableWeekends&&u(R)||i.disableDayFn&&i.disableDayFn(R);k&&(N'+Math.ceil(((new Date(_,C,T)-E)/864e5+E.getDay()+1)/7)+"")),s.push(y(c,i.isRTL,i.pickWholeWeek,D)),c=[],j=0,D=!1)}return function(e,t,n){return''+function(e){var t,n=[];for(e.showWeekNumber&&n.push(" "),t=0;t<7;t++)n.push(''+v(e,t,!0)+" ");return""+(e.isRTL?n.reverse():n).join("")+" "}(i)+""+t.join("")+"
"}(0,s,n)},isVisible:function(){return this._v},show:function(){var e,t,n;this.isVisible()||(this._v=!0,this.draw(),e=this.el,t="is-hidden",e.className=(n=(" "+e.className+" ").replace(" "+t+" "," ")).trim?n.trim():n.replace(/^\s+|\s+$/g,""),this._o.bound&&(a(i,"click",this._onClick),this.adjustPosition()),"function"==typeof this._o.onOpen&&this._o.onOpen.call(this))},hide:function(){var e,t,n=this._v;!1!==n&&(this._o.bound&&r(i,"click",this._onClick),this.el.style.position="static",this.el.style.left="auto",this.el.style.top="auto",e=this.el,s(e,t="is-hidden")||(e.className=""===e.className?t:e.className+" "+t),this._v=!1,void 0!==n&&"function"==typeof this._o.onClose&&this._o.onClose.call(this))},destroy:function(){var e=this._o;this.hide(),r(this.el,"mousedown",this._onMouseDown,!0),r(this.el,"touchend",this._onMouseDown,!0),r(this.el,"change",this._onChange),e.keyboardInput&&r(i,"keydown",this._onKeyChange),e.field&&(r(e.field,"change",this._onInputChange),e.bound&&(r(e.trigger,"click",this._onInputClick),r(e.trigger,"focus",this._onInputFocus),r(e.trigger,"blur",this._onInputBlur))),this.el.parentNode&&this.el.parentNode.removeChild(this.el)}},A}(o)}()},,function(e,t,n){"use strict";n.r(t),n.d(t,"AskPopupView",function(){return v}),n.d(t,"default",function(){return v});var i,o=n(8),a=n.n(o),r=n(12),s=n.n(r),c=n(11),l=n.n(c),u=n(1),d=n(19),p=n.n(d),f=n(0),m=n(2),h=n(10),g=n(9),b=n(24),v=Object(g.popup)({name:"View/Popup/Ask",templateID:"PopupsAsk"})(i=function(e){function t(){a()(this,t);var n=s()(this,e.call(this));return n.askDesc=u.a.observable(""),n.yesButton=u.a.observable(""),n.noButton=u.a.observable(""),n.yesFocus=u.a.observable(!1),n.noFocus=u.a.observable(!1),n.fYesAction=null,n.fNoAction=null,n.bFocusYesOnShow=!0,n.bDisabeCloseOnEsc=!0,n.sDefaultKeyScope=f.KeyState.PopupAsk,n}return l()(t,e),t.prototype.clearPopup=function(){this.askDesc(""),this.yesButton(Object(h.i18n)("POPUPS_ASK/BUTTON_YES")),this.noButton(Object(h.i18n)("POPUPS_ASK/BUTTON_NO")),this.yesFocus(!1),this.noFocus(!1),this.fYesAction=null,this.fNoAction=null},t.prototype.yesClick=function(){this.cancelCommand(),Object(m.isFunc)(this.fYesAction)&&this.fYesAction.call(null)},t.prototype.noClick=function(){this.cancelCommand(),Object(m.isFunc)(this.fNoAction)&&this.fNoAction.call(null)},t.prototype.onShow=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"",o=arguments.length>4&&void 0!==arguments[4]?arguments[4]:"",a=!(arguments.length>5&&void 0!==arguments[5])||arguments[5];this.clearPopup(),this.fYesAction=t||null,this.fNoAction=n||null,this.askDesc(e||""),i&&this.yesButton(i),o&&this.noButton(o),this.bFocusYesOnShow=!!a},t.prototype.onShowWithDelay=function(){this.bFocusYesOnShow&&this.yesFocus(!0)},t.prototype.onBuild=function(){var e=this;p()("tab, shift+tab, right, left",f.KeyState.PopupAsk,function(){return e.yesFocus()?e.noFocus(!0):e.yesFocus(!0),!1}),p()("esc",f.KeyState.PopupAsk,function(){return e.noClick(),!1})},t}(b.a))||i},,function(e,t,n){"use strict";n.r(t),n.d(t,"LanguagesPopupView",function(){return g}),n.d(t,"default",function(){return g});var i,o=n(8),a=n.n(o),r=n(12),s=n.n(r),c=n(11),l=n.n(c),u=n(4),d=n.n(u),p=n(1),f=n(2),m=n(9),h=n(24),g=Object(m.popup)({name:"View/Popup/Languages",templateID:"PopupsLanguages"})(i=function(e){function t(){a()(this,t);var n=s()(this,e.call(this));return n.fLang=null,n.userLanguage=p.a.observable(""),n.langs=p.a.observableArray([]),n.languages=p.a.computed(function(){var e=n.userLanguage();return d.a.map(n.langs(),function(t){return{key:t,user:t===e,selected:p.a.observable(!1),fullName:Object(f.convertLangName)(t)}})}),n.langs.subscribe(function(){n.setLanguageSelection()}),n}return l()(t,e),t.prototype.languageTooltipName=function(e){var t=Object(f.convertLangName)(e,!0);return Object(f.convertLangName)(e,!1)===t?"":t},t.prototype.setLanguageSelection=function(){var e=this.fLang?p.a.unwrap(this.fLang):"";d.a.each(this.languages(),function(t){t.selected(t.key===e)})},t.prototype.onBeforeShow=function(){this.fLang=null,this.userLanguage(""),this.langs([])},t.prototype.onShow=function(e,t,n){this.fLang=e,this.userLanguage(n||""),this.langs(t)},t.prototype.changeLanguage=function(e){this.fLang&&this.fLang(e),this.cancelCommand()},t}(h.a))||i},function(e,t,n){var i=n(104),o=n(84).concat("length","prototype");t.f=Object.getOwnPropertyNames||function(e){return i(e,o)}},function(e,t){t.f=Object.getOwnPropertySymbols},function(e,t,n){var i=n(46),o=n(43),a=n(163)(!1),r=n(86)("IE_PROTO");e.exports=function(e,t){var n,s=o(e),c=0,l=[];for(n in s)n!=r&&i(s,n)&&l.push(n);for(;t.length>c;)i(s,n=t[c++])&&(~a(l,n)||l.push(n));return l}},function(e,t,n){e.exports=n(53)},function(e,t,n){"use strict";var i=n(90),o=n(58),a=n(105),r=n(53),s=n(46),c=n(89),l=n(165),u=n(83),d=n(159),p=n(60)("iterator"),f=!([].keys&&"next"in[].keys()),m=function(){return this};e.exports=function(e,t,n,h,g,b,v){l(n,t,h);var S,y,w,A=function(e){if(!f&&e in _)return _[e];switch(e){case"keys":case"values":return function(){return new n(this,e)}}return function(){return new n(this,e)}},O=t+" Iterator",T="values"==g,C=!1,_=e.prototype,E=_[p]||_["@@iterator"]||g&&_[g],D=E||A(g),N=g?T?A("entries"):D:void 0,j="Array"==t&&_.entries||E;if(j&&(w=d(j.call(new e)))!==Object.prototype&&w.next&&(u(w,O,!0),i||s(w,p)||r(w,p,m)),T&&E&&"values"!==E.name&&(C=!0,D=function(){return E.call(this)}),i&&!v||!f&&!C&&_[p]||r(_,p,D),c[t]=D,c[O]=m,g)if(S={values:T?D:A("values"),keys:b?D:A("keys"),entries:N},v)for(y in S)y in _||a(_,y,S[y]);else o(o.P+o.F*(f||C),t,S);return S}},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var o=i(n(169)),a=i(n(153)),r="function"==typeof a.default&&"symbol"==typeof o.default?function(e){return typeof e}:function(e){return e&&"function"==typeof a.default&&e.constructor===a.default&&e!==a.default.prototype?"symbol":typeof e};t.default="function"==typeof a.default&&"symbol"===r(o.default)?function(e){return void 0===e?"undefined":r(e)}:function(e){return e&&"function"==typeof a.default&&e.constructor===a.default&&e!==a.default.prototype?"symbol":void 0===e?"undefined":r(e)}},function(e,t,n){var i=n(58),o=n(40),a=n(51);e.exports=function(e,t){var n=(o.Object||{})[e]||Object[e],r={};r[e]=t(n),i(i.S+i.F*a(function(){n(1)}),"Object",r)}},function(e,t,n){var i=n(92);e.exports=Object("z").propertyIsEnumerable(0)?Object:function(e){return"String"==i(e)?e.split(""):Object(e)}},function(e,t,n){var i=n(43),o=n(72).f;n(108)("getOwnPropertyDescriptor",function(){return function(e,t){return o(i(e),t)}})},function(e,t,n){n(110);var i=n(40).Object;e.exports=function(e,t){return i.getOwnPropertyDescriptor(e,t)}},function(e,t){e.exports=function(e){if("function"!=typeof e)throw TypeError(e+" is not a function!");return e}},function(e,t,n){"use strict";function i(){var e;null===N&&((N=f()("
")).appendTo(w.$body),e=N,j||(j=new R(e),g.a.applyBindingAccessorsToNode(e[0],{translatorInit:!0,template:function(){return{name:"Cmd"}}},j)))}var o=n(8),a=n.n(o),r=n(12),s=n.n(r),c=n(11),l=n.n(c),u=n(3),d=n.n(u),p=n(7),f=n.n(p),m=n(4),h=n.n(m),g=n(1),b=n(19),v=n.n(b),S=n(66),y=n.n(S),w=n(6),A=n(2),O=n(0),T=n(16),C=n(10),_=n(5),E=n(39),D=n(32),N=null,j=null,R=function(){function e(t){a()(this,e),this.dom=null,this.opened=g.a.observable(!1),this.cmd=g.a.observable(""),this.focused=g.a.observable(!1),this.themes=E.a.themes,this.cmdHistory=[],this.cmdHistoryShift=0,this.cmdHelper=g.a.observable(""),this.cmds=["help","version","clear","theme","lang"],this.cmdsWithParameters=["theme","lang"],this.isAdmin=!1,this.dom=t,this.isAdmin=!!_.appSettingsGet("admin")}return e.prototype.runCmd=function(e,t,i){var o,a,r,s="",c=null;if(this.cmdHelper(""),i){switch(e){case"lang":c=(this.isAdmin?D.a.languagesAdmin():D.a.languages()).filter(function(e){return 0===e.lastIndexOf(t,0)});break;case"theme":c=E.a.themes().filter(function(e){return 0===e.lastIndexOf(t,0)})}if(e&&c)if(1===c.length&&c[0])this.cmd(e+" "+c[0]);else if(1").html(n(129).replace("{{ cmd }}",i))),c&&l.append(f()("
").html(c)),h.a.delay(function(){t.dom.find(".rl-cmd-history").scrollTop(l.height())},50))}return!0},e.prototype.onEsc=function(){return this.opened(!1),!1},e.prototype.onTab=function(){return this.onCmd(!0),!1},e.prototype.onEnter=function(){return this.onCmd(!1),this.cmd(""),!1},e.prototype.onKeyDown=function(e){if(e&&e.keyCode&&!e.metaKey&&!e.ctrlKey&&!e.shiftKey&&0 ').appendTo("body"),w.$win.on("error",function(e){if(e&&e.originalEvent&&e.originalEvent.message&&-1===Object(A.inArray)(e.originalEvent.message,["Script error.","Uncaught Error: Error calling method on NPObject."])){var t=Object(A.timestamp)();if(o.lastErrorTime>=t)return;o.lastErrorTime=t,n.jsError(A.noop,e.originalEvent.message,e.originalEvent.filename,e.originalEvent.lineno,d.a.location&&d.a.location.toString?d.a.location.toString():"",w.$html.attr("class"),Object(A.microtime)()-w.startMicrotime)}}),w.$win.on("resize",function(){I.a("window.resize")}),I.b("window.resize",h.a.throttle(function(){var e=w.$win.height(),t=w.$win.height();w.$win.__sizes[0]===e&&w.$win.__sizes[1]===t||(w.$win.__sizes[0]=e,w.$win.__sizes[1]=t,I.a("window.resize.real"))},O.Magics.Time50ms)),w.$doc.on("keydown",function(e){e&&e.ctrlKey&&w.$html.addClass("rl-ctrl-key-pressed")}).on("keyup",function(e){e&&!e.ctrlKey&&w.$html.removeClass("rl-ctrl-key-pressed")}),w.$doc.on("mousemove keypress click",h.a.debounce(function(){I.a("rl.auto-logout-refresh")},O.Magics.Time5s)),v()("esc, enter",O.KeyState.All,function(){Object(A.detectDropdownVisibility)()}),_.appSettingsGet("allowCmdInterface")&&v()("ctrl+shift+`",O.KeyState.All,function(){_.appSettingsGet("allowCmdInterface")&&(i(),h.a.delay(function(){j&&(j.opened(!j.opened()),j.opened()&&h.a.delay(function(){j&&j.focused&&j.focused(!0)},O.Magics.Time50ms))},O.Magics.Time50ms))}),o}return l()(t,e),t.prototype.remote=function(){return null},t.prototype.data=function(){return null},t.prototype.getApplicationConfiguration=function(e,t){return this.applicationConfiguration[e]||t},t.prototype.download=function(e){if(w.sUserAgent&&(-10&&void 0!==arguments[0]&&arguments[0],t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],i=!!_.appSettingsGet("inIframe"),o=Object(A.pString)(_.appSettingsGet("customLogoutLink"));t&&this.clearClientSideToken(),t&&n&&d.a.close&&d.a.close(),o=o||(e?Object(T.x)():Object(T.y)()),t&&d.a.location.href!==o?h.a.delay(function(){i&&d.a.parent?d.a.parent.location.href=o:d.a.location.href=o,w.$win.trigger("rl.tooltips.diactivate")},O.Magics.Time100ms):(Object(P.routeOff)(),Object(P.setHash)(Object(T.w)(),!0),Object(P.routeOff)(),h.a.delay(function(){i&&d.a.parent?d.a.parent.location.reload():d.a.location.reload(),w.$win.trigger("rl.tooltips.diactivate")},O.Magics.Time100ms))},t.prototype.historyBack=function(){d.a.history.back()},t.prototype.bootstart=function(){I.a("rl.bootstart");var e=_.appSettingsGet("mobile");g.a.components.register("SaveTrigger",n(128).default),g.a.components.register("Input",n(127).default),g.a.components.register("Select",n(126).default),g.a.components.register("Radio",n(121).default),g.a.components.register("TextArea",n(125).default),g.a.components.register("Date",n(124).default),g.a.components.register("x-script",n(123).default),_.appSettingsGet("materialDesign")&&w.bAnimationSupported?(g.a.components.register("Checkbox",n(122).default),g.a.components.register("CheckboxSimple",n(80).default)):(g.a.components.register("Checkbox",n(80).default),g.a.components.register("CheckboxSimple",n(80).default)),Object(C.initOnStartOrLangChange)(C.initNotificationLanguage),h.a.delay(A.windowResizeCallback,O.Magics.Time1s),I.b("ssm.mobile-enter",function(){Object(w.leftPanelDisabled)(!0)}),I.b("ssm.mobile-leave",function(){Object(w.leftPanelDisabled)(!1)}),e?(w.$html.addClass("ssm-state-mobile").addClass("rl-mobile"),I.a("ssm.mobile-enter")):(w.$html.addClass("rl-desktop"),y.a.addState({id:"mobile",query:"(max-width: 767px)",onEnter:function(){w.$html.addClass("ssm-state-mobile"),I.a("ssm.mobile-enter")},onLeave:function(){w.$html.removeClass("ssm-state-mobile"),I.a("ssm.mobile-leave")}}),y.a.addState({id:"tablet",query:"(min-width: 768px) and (max-width: 999px)",onEnter:function(){w.$html.addClass("ssm-state-tablet")},onLeave:function(){w.$html.removeClass("ssm-state-tablet")}}),y.a.addState({id:"desktop",query:"(min-width: 1000px) and (max-width: 1400px)",onEnter:function(){w.$html.addClass("ssm-state-desktop")},onLeave:function(){w.$html.removeClass("ssm-state-desktop")}}),y.a.addState({id:"desktop-large",query:"(min-width: 1401px)",onEnter:function(){w.$html.addClass("ssm-state-desktop-large")},onLeave:function(){w.$html.removeClass("ssm-state-desktop-large")}})),w.leftPanelDisabled.subscribe(function(e){w.$html.toggleClass("rl-left-panel-disabled",e),w.$html.toggleClass("rl-left-panel-enabled",!e)}),w.leftPanelType.subscribe(function(e){w.$html.toggleClass("rl-left-panel-none","none"===e),w.$html.toggleClass("rl-left-panel-short","short"===e)}),w.leftPanelDisabled.valueHasMutated(),D.a.populate(),E.a.populate(),x.a.populate()},t}(k)},function(e,t,n){"use strict";n.d(t,"a",function(){return v});var i=n(8),o=n.n(i),a=n(12),r=n.n(a),s=n(11),c=n.n(s),l=n(4),u=n.n(l),d=n(7),p=n.n(d),f=n(1),m=n(6),h=n(2),g=n(16),b=n(9),v=function(e){function t(n){o()(this,t);var i=r()(this,e.call(this,"settings",n));return i.menu=f.a.observableArray([]),i.oCurrentSubScreen=null,i.oViewModelPlace=null,i.setupSettings(),i}return c()(t,e),t.prototype.setupSettings=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;e&&e()},t.prototype.onRoute=function(e){var t=this,n=null,i=null,o=null,a=null;if((i=u.a.find(m.VIEW_MODELS.settings,function(t){return t&&t.__rlSettingsData&&e===t.__rlSettingsData.Route}))&&(u.a.find(m.VIEW_MODELS["settings-removed"],function(e){return e&&e===i})&&(i=null),i&&u.a.find(m.VIEW_MODELS["settings-disabled"],function(e){return e&&e===i})&&(i=null)),i){if(i.__builded&&i.__vm)n=i.__vm;else if((o=this.oViewModelPlace)&&1===o.length){n=new i,(a=p()("
").addClass("rl-settings-view-model").hide()).appendTo(o),n.viewModelDom=a,n.__rlSettingsData=i.__rlSettingsData,i.__dom=a,i.__builded=!0,i.__vm=n;var r={name:i.__rlSettingsData.Template};f.a.applyBindingAccessorsToNode(a[0],{translatorInit:!0,template:function(){return r}},n),Object(h.delegateRun)(n,"onBuild",[a])}else Object(h.log)("Cannot find sub settings view model position: SettingsSubScreen");n&&u.a.defer(function(){t.oCurrentSubScreen&&(Object(h.delegateRun)(t.oCurrentSubScreen,"onHide"),t.oCurrentSubScreen.viewModelDom.hide()),t.oCurrentSubScreen=n,t.oCurrentSubScreen&&(Object(h.delegateRun)(t.oCurrentSubScreen,"onBeforeShow"),t.oCurrentSubScreen.viewModelDom.show(),Object(h.delegateRun)(t.oCurrentSubScreen,"onShow"),Object(h.delegateRun)(t.oCurrentSubScreen,"onShowWithDelay",[],200),u.a.each(t.menu(),function(e){e.selected(n&&n.__rlSettingsData&&e.route===n.__rlSettingsData.Route)}),p()("#rl-content .b-settings .b-content .content").scrollTop(0)),Object(h.windowResize)()})}else Object(b.setHash)(Object(g.z)(),!1,!0)},t.prototype.onHide=function(){this.oCurrentSubScreen&&this.oCurrentSubScreen.viewModelDom&&(Object(h.delegateRun)(this.oCurrentSubScreen,"onHide"),this.oCurrentSubScreen.viewModelDom.hide())},t.prototype.onBuild=function(){var e=this;u.a.each(m.VIEW_MODELS.settings,function(t){t&&t.__rlSettingsData&&!u.a.find(m.VIEW_MODELS["settings-removed"],function(e){return e&&e===t})&&e.menu.push({route:t.__rlSettingsData.Route,label:t.__rlSettingsData.Label,selected:f.a.observable(!1),disabled:!!u.a.find(m.VIEW_MODELS["settings-disabled"],function(e){return e&&e===t})})}),this.oViewModelPlace=p()("#rl-content #rl-settings-subscreen")},t.prototype.routes=function(){var e=u.a.find(m.VIEW_MODELS.settings,function(e){return e&&e.__rlSettingsData&&e.__rlSettingsData.IsDefault}),t=e&&e.__rlSettingsData?e.__rlSettingsData.Route:"general",n={subname:/^(.*)$/,normalize_:function(e,n){return n.subname=Object(h.isUnd)(n.subname)?t:Object(h.pString)(n.subname),[n.subname]}};return[["{subname}/",n],["{subname}",n],["",n]]},t}(n(65).a)},function(e,t,n){"use strict";n.d(t,"a",function(){return v});var i=n(8),o=n.n(i),a=n(3),r=n.n(a),s=n(4),c=n.n(s),l=n(7),u=n.n(l),d=n(23),p=n(0),f=n(2),m=n(6),h=n(16),g=n(29),b=n(5),v=function(){function e(){o()(this,e),this.oRequests={}}return e.prototype.defaultResponse=function(e,t,n,i,o,a){var r=function(){p.StorageResultType.Success!==n&&m.data.bUnload&&(n=p.StorageResultType.Unload),p.StorageResultType.Success===n&&i&&!i.Result?(i&&-12&&void 0!==arguments[2]?arguments[2]:2e4,o=this,a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"",s=arguments.length>4&&void 0!==arguments[4]?arguments[4]:[],l=""===a,d=(new r.a.Date).getTime();(n=(t=t||{}).Action||"")&&0(new r.a.Date).getTime()-d),n&&o.oRequests[n]&&(o.oRequests[n].__aborted&&(a="abort"),o.oRequests[n]=null),o.defaultResponse(e,n,a,i,s,t)}),n&&03&&void 0!==arguments[3]&&arguments[3];this.defaultRequest(e,"JsInfo",{Type:t,Data:n,IsError:i?"1":"0"})},e.prototype.getPublicKey=function(e){this.defaultRequest(e,"GetPublicKey")},e.prototype.jsVersion=function(e,t){this.defaultRequest(e,"Version",{Version:t})},e}()},function(e,t,n){"use strict";n.d(t,"a",function(){return c});var i=n(8),o=n.n(i),a=n(1),r=n(6),s=n(5),c=function(){function e(){o()(this,e),this.allowLanguagesOnSettings=a.a.observable(!0),this.allowLanguagesOnLogin=a.a.observable(!0),this.newMoveToFolder=a.a.observable(!0),this.interfaceAnimation=a.a.observable(!0),this.interfaceAnimation.subscribe(function(e){var t=r.bMobileDevice||!e;r.$html.toggleClass("rl-anim",!t).toggleClass("no-rl-anim",t)}),this.interfaceAnimation.valueHasMutated(),this.prem=a.a.observable(!1),this.community=a.a.observable(!0)}return e.prototype.populate=function(){this.allowLanguagesOnLogin(!!s.settingsGet("AllowLanguagesOnLogin")),this.allowLanguagesOnSettings(!!s.settingsGet("AllowLanguagesOnSettings")),this.newMoveToFolder(!!s.settingsGet("NewMoveToFolder")),this.interfaceAnimation(!!s.settingsGet("InterfaceAnimation")),this.prem(!!s.settingsGet("PremType")),this.community(!!s.settingsGet("Community"))},e}()},function(e,t,n){"use strict";var i=n(3),o=n.n(i),a=n(2),r=n(6),s=n(0),c=n(29),l=n(10),u=n(44);t.a=function(e){r.data.__APP__=e,r.$win.on("keydown",a.killCtrlACtrlS).on("unload",function(){r.data.bUnload=!0}),r.$html.addClass(r.bMobileDevice?"mobile":"no-mobile").on("click.dropdown.data-api",a.detectDropdownVisibility);var t=o.a.rl||{};t.i18n=l.i18n,t.createCommand=a.createCommandLegacy,t.addSettingsViewModel=c.b,t.addSettingsViewModelForAdmin=c.c,t.addHook=c.a,t.settingsGet=c.d,t.pluginSettingsGet=c.h,t.pluginRemoteRequest=c.e,t.EmailModel=u.EmailModel,t.Enums=s,o.a.rl=t,o.a.__APP_BOOT=function(t){Object(a.domReady)(function(){o.a.setTimeout(function(){o.a.rainloopTEMPLATES&&o.a.rainloopTEMPLATES[0]?(o.a.document.getElementById("rl-templates").innerHTML=o.a.rainloopTEMPLATES[0],o.a.setTimeout(function(){r.$html.removeClass("no-js rl-booted-trigger").addClass("rl-booted"),e.bootstart()},s.Magics.Time10ms)):t(),o.a.__APP_BOOT=null},s.Magics.Time10ms)})}}},,,,function(e,t,n){"use strict";n.r(t);var i=n(8),o=n.n(i),a=n(12),r=n.n(a),s=n(11),c=n.n(s),l=n(27),u=n(4),d=n.n(u),p=n(1),f=n(2),m=function(e){function t(){return o()(this,t),r()(this,e.apply(this,arguments))}return c()(t,e),t}(function(e){function t(n){o()(this,t);var i=r()(this,e.call(this));return i.values=p.a.observableArray([]),i.value=n.value,!Object(f.isUnd)(i.value)&&i.value.subscribe||(i.value=p.a.observable("")),i.inline=!Object(f.isUnd)(n.inline)&&n.inline,i.readOnly=!Object(f.isUnd)(n.readOnly)&&!!n.readOnly,n.values&&i.values(d.a.map(n.values,function(e,t){return{label:e,value:t}})),i.click=d.a.bind(i.click,i),i}return c()(t,e),t.prototype.click=function(e){!this.readOnly&&e&&this.value(e.value)},t}(l.a));t.default=Object(l.b)(m,"RadioComponent")},function(e,t,n){"use strict";n.r(t);var i=n(8),o=n.n(i),a=n(12),r=n.n(a),s=n(11),c=n.n(s),l=n(4),u=n.n(l),d=n(1),p=n(27),f=function(e){function t(n){o()(this,t);var i=r()(this,e.call(this,n));return i.animationBox=d.a.observable(!1).extend({falseTimeout:200}),i.animationCheckmark=d.a.observable(!1).extend({falseTimeout:200}),i.animationBoxSetTrue=u.a.bind(i.animationBoxSetTrue,i),i.animationCheckmarkSetTrue=u.a.bind(i.animationCheckmarkSetTrue,i),i.disposable.push(i.value.subscribe(function(e){i.triggerAnimation(e)},i)),i}return c()(t,e),t.prototype.animationBoxSetTrue=function(){this.animationBox(!0)},t.prototype.animationCheckmarkSetTrue=function(){this.animationCheckmark(!0)},t.prototype.triggerAnimation=function(e){e?(this.animationBoxSetTrue(),u.a.delay(this.animationCheckmarkSetTrue,200)):(this.animationCheckmarkSetTrue(),u.a.delay(this.animationBoxSetTrue,200))},t}(n(74).a);t.default=Object(p.b)(f,"CheckboxMaterialDesignComponent")},function(e,t,n){"use strict";n.r(t);var i=n(8),o=n.n(i),a=n(12),r=n.n(a),s=n(11),c=n.n(s),l=n(7),u=n.n(l),d=n(27),p=function(e){function t(n){o()(this,t);var i=r()(this,e.call(this));if(n.component&&n.component.templateNodes&&n.element&&n.element[0]&&n.element[0].outerHTML){var a=n.element[0].outerHTML;(a=a?a.replace(/<\/b><\/x-script>/i,"<\/script>"):"")?(n.element.text(""),n.element.replaceWith(u()(a).text(n.component.templateNodes[0]&&n.component.templateNodes[0].nodeValue?n.component.templateNodes[0].nodeValue:""))):n.element.remove()}return i}return c()(t,e),t}(d.a);t.default=Object(d.b)(p,"ScriptComponent")},function(e,t,n){"use strict";n.r(t);var i=n(8),o=n.n(i),a=n(12),r=n.n(a),s=n(11),c=n.n(s),l=n(27),u=function(e){function t(){return o()(this,t),r()(this,e.apply(this,arguments))}return c()(t,e),t}(n(47).a);t.default=Object(l.b)(u,"DateComponent")},function(e,t,n){"use strict";n.r(t);var i=n(8),o=n.n(i),a=n(12),r=n.n(a),s=n(11),c=n.n(s),l=n(2),u=n(27),d=5,p=function(e){function t(n){o()(this,t);var i=r()(this,e.call(this,n));return i.rows=n.rows||d,i.spellcheck=!Object(l.isUnd)(n.spellcheck)&&!!n.spellcheck,i}return c()(t,e),t}(n(47).a);t.default=Object(u.b)(p,"TextAreaComponent")},function(e,t,n){"use strict";n.r(t);var i=n(8),o=n.n(i),a=n(12),r=n.n(a),s=n(11),c=n.n(s),l=n(10),u=n(2),d=n(27),p=function(e){function t(n){o()(this,t);var i=r()(this,e.call(this,n));return i.options=n.options||"",i.optionsText=n.optionsText||null,i.optionsValue=n.optionsValue||null,i.optionsCaption=n.optionsCaption||null,i.optionsCaption&&(i.optionsCaption=Object(l.i18n)(i.optionsCaption)),i.defautOptionsAfterRender=u.defautOptionsAfterRender,i}return c()(t,e),t}(n(47).a);t.default=Object(d.b)(p,"SelectComponent")},function(e,t,n){"use strict";n.r(t);var i=n(8),o=n.n(i),a=n(12),r=n.n(a),s=n(11),c=n.n(s),l=n(27),u=function(e){function t(){return o()(this,t),r()(this,e.apply(this,arguments))}return c()(t,e),t}(n(47).a);t.default=Object(l.b)(u,"InputComponent")},function(e,t,n){"use strict";n.r(t);var i=n(8),o=n.n(i),a=n(12),r=n.n(a),s=n(11),c=n.n(s),l=n(2),u=n(0),d=n(27),p=function(e){function t(n){o()(this,t);var i=r()(this,e.call(this));return i.element=n.element||null,i.value=n.value&&n.value.subscribe?n.value:null,i.element&&(i.value?(i.element.css("display","inline-block"),n.verticalAlign&&i.element.css("vertical-align",n.verticalAlign),i.setState(i.value()),i.disposable.push(i.value.subscribe(i.setState,i))):i.element.hide()),i}return c()(t,e),t.prototype.setState=function(e){switch(Object(l.pInt)(e)){case u.SaveSettingsStep.TrueResult:this.element.find(".animated,.error").hide().removeClass("visible").end().find(".success").show().addClass("visible");break;case u.SaveSettingsStep.FalseResult:this.element.find(".animated,.success").hide().removeClass("visible").end().find(".error").show().addClass("visible");break;case u.SaveSettingsStep.Animate:this.element.find(".error,.success").hide().removeClass("visible").end().find(".animated").show().addClass("visible");break;case u.SaveSettingsStep.Idle:default:this.element.find(".animated").hide().end().find(".error,.success").removeClass("visible")}},t}(d.a);t.default=Object(d.b)(p,"SaveTriggerComponent")},function(e,t){e.exports='> {{ cmd }}'},function(e,t){e.exports=' version: {{ version }}'},function(e,t){e.exports='lang [{{ langs }}] '},function(e,t){e.exports='theme [{{ themes }}] '},function(e,t){e.exports=' commands: {{ commands }}'},function(e,t){e.exports='Command not found: {{ cmd }}'},,,function(e,t,n){var i=n(58);i(i.S,"Object",{create:n(88)})},function(e,t,n){n(137);var i=n(40).Object;e.exports=function(e,t){return i.create(e,t)}},function(e,t,n){e.exports={default:n(138),__esModule:!0}},function(e,t,n){var i=n(52),o=n(61),a=function(e,t){if(o(e),!i(t)&&null!==t)throw TypeError(t+": can't set as prototype!")};e.exports={set:Object.setPrototypeOf||("__proto__"in{}?function(e,t,i){try{(i=n(94)(Function.call,n(72).f(Object.prototype,"__proto__").set,2))(e,[]),t=!(e instanceof Array)}catch(e){t=!0}return function(e,n){return a(e,n),t?e.__proto__=n:i(e,n),e}}({},!1):void 0),check:a}},function(e,t,n){var i=n(58);i(i.S,"Object",{setPrototypeOf:n(140).set})},function(e,t,n){n(141),e.exports=n(40).Object.setPrototypeOf},function(e,t,n){e.exports={default:n(142),__esModule:!0}},function(e,t,n){n(81)("observable")},function(e,t,n){n(81)("asyncIterator")},function(e,t){},function(e,t,n){var i=n(43),o=n(102).f,a={}.toString,r="object"==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[];e.exports.f=function(e){return r&&"[object Window]"==a.call(e)?function(e){try{return o(e)}catch(e){return r.slice()}}(e):o(i(e))}},function(e,t,n){var i=n(92);e.exports=Array.isArray||function(e){return"Array"==i(e)}},function(e,t,n){var i=n(87),o=n(103),a=n(71);e.exports=function(e){var t=i(e),n=o.f;if(n)for(var r,s=n(e),c=a.f,l=0;s.length>l;)c.call(e,r=s[l++])&&t.push(r);return t}},function(e,t,n){var i=n(70)("meta"),o=n(52),a=n(46),r=n(49).f,s=0,c=Object.isExtensible||function(){return!0},l=!n(51)(function(){return c(Object.preventExtensions({}))}),u=function(e){r(e,i,{value:{i:"O"+ ++s,w:{}}})},d=e.exports={KEY:i,NEED:!1,fastKey:function(e,t){if(!o(e))return"symbol"==typeof e?e:("string"==typeof e?"S":"P")+e;if(!a(e,i)){if(!c(e))return"F";if(!t)return"E";u(e)}return e[i].i},getWeak:function(e,t){if(!a(e,i)){if(!c(e))return!0;if(!t)return!1;u(e)}return e[i].w},onFreeze:function(e){return l&&d.NEED&&c(e)&&!a(e,i)&&u(e),e}}},function(e,t,n){"use strict";var i=n(41),o=n(46),a=n(42),r=n(58),s=n(105),c=n(150).KEY,l=n(51),u=n(85),d=n(83),p=n(70),f=n(60),m=n(82),h=n(81),g=n(149),b=n(148),v=n(61),S=n(43),y=n(67),w=n(64),A=n(88),O=n(147),T=n(72),C=n(49),_=n(87),E=T.f,D=C.f,N=O.f,j=i.Symbol,R=i.JSON,I=R&&R.stringify,x=f("_hidden"),P=f("toPrimitive"),k={}.propertyIsEnumerable,L=u("symbol-registry"),M=u("symbols"),F=u("op-symbols"),U=Object.prototype,H="function"==typeof j,G=i.QObject,B=!G||!G.prototype||!G.prototype.findChild,V=a&&l(function(){return 7!=A(D({},"a",{get:function(){return D(this,"a",{value:7}).a}})).a})?function(e,t,n){var i=E(U,t);i&&delete U[t],D(e,t,n),i&&e!==U&&D(U,t,i)}:D,q=function(e){var t=M[e]=A(j.prototype);return t._k=e,t},z=H&&"symbol"==typeof j.iterator?function(e){return"symbol"==typeof e}:function(e){return e instanceof j},K=function(e,t,n){return e===U&&K(F,t,n),v(e),t=y(t,!0),v(n),o(M,t)?(n.enumerable?(o(e,x)&&e[x][t]&&(e[x][t]=!1),n=A(n,{enumerable:w(0,!1)})):(o(e,x)||D(e,x,w(1,{})),e[x][t]=!0),V(e,t,n)):D(e,t,n)},W=function(e,t){v(e);for(var n,i=g(t=S(t)),o=0,a=i.length;a>o;)K(e,n=i[o++],t[n]);return e},Y=function(e){var t=k.call(this,e=y(e,!0));return!(this===U&&o(M,e)&&!o(F,e))&&(!(t||!o(this,e)||!o(M,e)||o(this,x)&&this[x][e])||t)},$=function(e,t){if(e=S(e),t=y(t,!0),e!==U||!o(M,t)||o(F,t)){var n=E(e,t);return!n||!o(M,t)||o(e,x)&&e[x][t]||(n.enumerable=!0),n}},J=function(e){for(var t,n=N(S(e)),i=[],a=0;n.length>a;)o(M,t=n[a++])||t==x||t==c||i.push(t);return i},X=function(e){for(var t,n=e===U,i=N(n?F:S(e)),a=[],r=0;i.length>r;)!o(M,t=i[r++])||n&&!o(U,t)||a.push(M[t]);return a};H||(s((j=function(){if(this instanceof j)throw TypeError("Symbol is not a constructor!");var e=p(arguments.length>0?arguments[0]:void 0),t=function(n){this===U&&t.call(F,n),o(this,x)&&o(this[x],e)&&(this[x][e]=!1),V(this,e,w(1,n))};return a&&B&&V(U,e,{configurable:!0,set:t}),q(e)}).prototype,"toString",function(){return this._k}),T.f=$,C.f=K,n(102).f=O.f=J,n(71).f=Y,n(103).f=X,a&&!n(90)&&s(U,"propertyIsEnumerable",Y,!0),m.f=function(e){return q(f(e))}),r(r.G+r.W+r.F*!H,{Symbol:j});for(var Q="hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables".split(","),Z=0;Q.length>Z;)f(Q[Z++]);for(var ee=_(f.store),te=0;ee.length>te;)h(ee[te++]);r(r.S+r.F*!H,"Symbol",{for:function(e){return o(L,e+="")?L[e]:L[e]=j(e)},keyFor:function(e){if(!z(e))throw TypeError(e+" is not a symbol!");for(var t in L)if(L[t]===e)return t},useSetter:function(){B=!0},useSimple:function(){B=!1}}),r(r.S+r.F*!H,"Object",{create:function(e,t){return void 0===t?A(e):W(A(e),t)},defineProperty:K,defineProperties:W,getOwnPropertyDescriptor:$,getOwnPropertyNames:J,getOwnPropertySymbols:X}),R&&r(r.S+r.F*(!H||l(function(){var e=j();return"[null]"!=I([e])||"{}"!=I({a:e})||"{}"!=I(Object(e))})),"JSON",{stringify:function(e){if(void 0!==e&&!z(e)){for(var t,n,i=[e],o=1;arguments.length>o;)i.push(arguments[o++]);return"function"==typeof(t=i[1])&&(n=t),!n&&b(t)||(t=function(e,t){if(n&&(t=n.call(this,e,t)),!z(t))return t}),i[1]=t,I.apply(R,i)}}}),j.prototype[P]||n(53)(j.prototype,P,j.prototype.valueOf),d(j,"Symbol"),d(Math,"Math",!0),d(i.JSON,"JSON",!0)},function(e,t,n){n(151),n(146),n(145),n(144),e.exports=n(40).Symbol},function(e,t,n){e.exports={default:n(152),__esModule:!0}},function(e,t){e.exports=function(e,t){return{value:t,done:!!e}}},function(e,t){e.exports=function(){}},function(e,t,n){"use strict";var i=n(155),o=n(154),a=n(89),r=n(43);e.exports=n(106)(Array,"Array",function(e,t){this._t=r(e),this._i=0,this._k=t},function(){var e=this._t,t=this._k,n=this._i++;return!e||n>=e.length?(this._t=void 0,o(1)):o(0,"keys"==t?n:"values"==t?e[n]:[n,e[n]])},"values"),a.Arguments=a.Array,i("keys"),i("values"),i("entries")},function(e,t,n){n(156);for(var i=n(41),o=n(53),a=n(89),r=n(60)("toStringTag"),s="CSSRuleList,CSSStyleDeclaration,CSSValueList,ClientRectList,DOMRectList,DOMStringList,DOMTokenList,DataTransferItemList,FileList,HTMLAllCollection,HTMLCollection,HTMLFormElement,HTMLSelectElement,MediaList,MimeTypeArray,NamedNodeMap,NodeList,PaintRequestList,Plugin,PluginArray,SVGLengthList,SVGNumberList,SVGPathSegList,SVGPointList,SVGStringList,SVGTransformList,SourceBufferList,StyleSheetList,TextTrackCueList,TextTrackList,TouchList".split(","),c=0;c0?o(i(e),9007199254740991):0}},function(e,t,n){var i=n(43),o=n(162),a=n(161);e.exports=function(e){return function(t,n,r){var s,c=i(t),l=o(c.length),u=a(r,l);if(e&&n!=n){for(;l>u;)if((s=c[u++])!=s)return!0}else for(;l>u;u++)if((e||u in c)&&c[u]===n)return e||u||0;return!e&&-1}}},function(e,t,n){var i=n(49),o=n(61),a=n(87);e.exports=n(42)?Object.defineProperties:function(e,t){o(e);for(var n,r=a(t),s=r.length,c=0;s>c;)i.f(e,n=r[c++],t[n]);return e}},function(e,t,n){"use strict";var i=n(88),o=n(64),a=n(83),r={};n(53)(r,n(60)("iterator"),function(){return this}),e.exports=function(e,t,n){e.prototype=i(r,{next:o(1,n)}),a(e,t+" Iterator")}},function(e,t,n){var i=n(91),o=n(73);e.exports=function(e){return function(t,n){var a,r,s=String(o(t)),c=i(n),l=s.length;return c<0||c>=l?e?"":void 0:(a=s.charCodeAt(c))<55296||a>56319||c+1===l||(r=s.charCodeAt(c+1))<56320||r>57343?e?s.charAt(c):a:e?s.slice(c,c+2):r-56320+(a-55296<<10)+65536}}},function(e,t,n){"use strict";var i=n(166)(!0);n(106)(String,"String",function(e){this._t=String(e),this._i=0},function(){var e,t=this._t,n=this._i;return n>=t.length?{value:void 0,done:!0}:(e=i(t,n),this._i+=e.length,{value:e,done:!1})})},function(e,t,n){n(167),n(157),e.exports=n(82).f("iterator")},function(e,t,n){e.exports={default:n(168),__esModule:!0}},function(e,t){e.exports='\n\n\t \n\t \n\t \n\t \n\t{{title}} \n\t\n\n\n\t\n\t\n\t\t
{{date}}
\n\t\t
{{fromCreds}}
\n\t\t
{{toLabel}}: {{toCreds}}
\n\t\t
{{ccLabel}}: {{ccCreds}}
\n\t
\n\t{{html}}
\n\n'},,function(e,t,n){"use strict";n.r(t);var i,o,a,r,s,c,l,u,d,p,f,m,h,g,b,v,S=n(8),y=n.n(S),w=n(12),A=n.n(w),O=n(11),T=n.n(O),C=n(3),_=n.n(C),E=n(4),D=n.n(E),N=n(1),j=n(55),R=n.n(j),I=n(16),x=n(10),P=n(0),k=n(2),L=n(5),M=n(38),F=n(48),U=n(68),H=new function e(){y()(this,e),this.plugins=N.a.observableArray([]),this.plugins.loading=N.a.observable(!1).extend({throttle:100}),this.plugins.error=N.a.observable("")},G=new function e(){y()(this,e),this.licensing=N.a.observable(!1),this.licensingProcess=N.a.observable(!1),this.licenseValid=N.a.observable(!1),this.licenseExpired=N.a.observable(0),this.licenseError=N.a.observable(""),this.licenseTrigger=N.a.observable(!1)},B=new function e(){y()(this,e),this.packages=N.a.observableArray([]),this.packages.loading=N.a.observable(!1).extend({throttle:100}),this.packagesReal=N.a.observable(!0),this.packagesMainUpdatable=N.a.observable(!0)},V=new function e(){y()(this,e),this.coreReal=N.a.observable(!0),this.coreChannel=N.a.observable("stable"),this.coreType=N.a.observable("stable"),this.coreUpdatable=N.a.observable(!0),this.coreAccess=N.a.observable(!0),this.coreWarning=N.a.observable(!1),this.coreChecking=N.a.observable(!1).extend({throttle:100}),this.coreUpdating=N.a.observable(!1).extend({throttle:100}),this.coreVersion=N.a.observable(""),this.coreRemoteVersion=N.a.observable(""),this.coreRemoteRelease=N.a.observable(""),this.coreVersionCompare=N.a.observable(-2)},q=n(21),z=n(9),K=n(29),W=n(114),Y=n(39),$=n(32),J=function(){function e(){var t=this;y()(this,e),this.language=$.a.language,this.languages=$.a.languages,this.languageAdmin=$.a.languageAdmin,this.languagesAdmin=$.a.languagesAdmin,this.theme=Y.a.theme,this.themes=Y.a.themes,this.capaThemes=F.a.themes,this.capaUserBackground=F.a.userBackground,this.capaGravatar=F.a.gravatar,this.capaAdditionalAccounts=F.a.additionalAccounts,this.capaIdentities=F.a.identities,this.capaAttachmentThumbnails=F.a.attachmentThumbnails,this.capaTemplates=F.a.templates,this.allowLanguagesOnSettings=M.a.allowLanguagesOnSettings,this.weakPassword=M.a.weakPassword,this.newMoveToFolder=M.a.newMoveToFolder,this.dataFolderAccess=M.a.dataFolderAccess,this.mainAttachmentLimit=N.a.observable(Object(k.pInt)(Object(L.settingsGet)("AttachmentLimit"))/(P.Magics.BitLength1024*P.Magics.BitLength1024)).extend({posInterer:25}),this.uploadData=Object(L.settingsGet)("PhpUploadSizes"),this.uploadDataDesc=this.uploadData&&(this.uploadData.upload_max_filesize||this.uploadData.post_max_size)?[this.uploadData.upload_max_filesize?"upload_max_filesize = "+this.uploadData.upload_max_filesize+"; ":"",this.uploadData.post_max_size?"post_max_size = "+this.uploadData.post_max_size:""].join(""):"",this.themesOptions=N.a.computed(function(){return D.a.map(t.themes(),function(e){return{optValue:e,optText:Object(k.convertThemeName)(e)}})}),this.languageFullName=N.a.computed(function(){return Object(k.convertLangName)(t.language())}),this.languageAdminFullName=N.a.computed(function(){return Object(k.convertLangName)(t.languageAdmin())}),this.attachmentLimitTrigger=N.a.observable(P.SaveSettingsStep.Idle),this.languageTrigger=N.a.observable(P.SaveSettingsStep.Idle),this.languageAdminTrigger=N.a.observable(P.SaveSettingsStep.Idle).extend({throttle:P.Magics.Time100ms}),this.themeTrigger=N.a.observable(P.SaveSettingsStep.Idle)}return e.prototype.onBuild=function(){var e=this;D.a.delay(function(){var t=Object(k.settingsSaveHelperSimpleFunction)(e.attachmentLimitTrigger,e),n=Object(k.settingsSaveHelperSimpleFunction)(e.languageTrigger,e),i=Object(k.settingsSaveHelperSimpleFunction)(e.themeTrigger,e),o=function(t){return function(){e.languageAdminTrigger(t),D.a.delay(function(){return e.languageAdminTrigger(P.SaveSettingsStep.Idle)},P.Magics.Time1s)}};e.mainAttachmentLimit.subscribe(function(e){q.a.saveAdminConfig(t,{AttachmentLimit:Object(k.pInt)(e)})}),e.language.subscribe(function(e){q.a.saveAdminConfig(n,{Language:Object(k.trim)(e)})}),e.languageAdmin.subscribe(function(t){e.languageAdminTrigger(P.SaveSettingsStep.Animate),Object(x.reload)(!0,t).then(o(P.SaveSettingsStep.TrueResult),o(P.SaveSettingsStep.FalseResult)).then(function(){q.a.saveAdminConfig(null,{LanguageAdmin:Object(k.trim)(t)})})}),e.theme.subscribe(function(t){Object(k.changeTheme)(t,e.themeTrigger),q.a.saveAdminConfig(i,{Theme:Object(k.trim)(t)})}),e.capaAdditionalAccounts.subscribe(function(e){q.a.saveAdminConfig(null,{CapaAdditionalAccounts:Object(k.boolToAjax)(e)})}),e.capaIdentities.subscribe(function(e){q.a.saveAdminConfig(null,{CapaIdentities:Object(k.boolToAjax)(e)})}),e.capaTemplates.subscribe(function(e){q.a.saveAdminConfig(null,{CapaTemplates:Object(k.boolToAjax)(e)})}),e.capaGravatar.subscribe(function(e){q.a.saveAdminConfig(null,{CapaGravatar:Object(k.boolToAjax)(e)})}),e.capaAttachmentThumbnails.subscribe(function(e){q.a.saveAdminConfig(null,{CapaAttachmentThumbnails:Object(k.boolToAjax)(e)})}),e.capaThemes.subscribe(function(e){q.a.saveAdminConfig(null,{CapaThemes:Object(k.boolToAjax)(e)})}),e.capaUserBackground.subscribe(function(e){q.a.saveAdminConfig(null,{CapaUserBackground:Object(k.boolToAjax)(e)})}),e.allowLanguagesOnSettings.subscribe(function(e){q.a.saveAdminConfig(null,{AllowLanguagesOnSettings:Object(k.boolToAjax)(e)})}),e.newMoveToFolder.subscribe(function(e){q.a.saveAdminConfig(null,{NewMoveToFolder:Object(k.boolToAjax)(e)})})},P.Magics.Time50ms)},e.prototype.selectLanguage=function(){Object(z.showScreenPopup)(n(101),[this.language,this.languages(),$.a.userLanguage()])},e.prototype.selectLanguageAdmin=function(){Object(z.showScreenPopup)(n(101),[this.languageAdmin,this.languagesAdmin(),$.a.userLanguageAdmin()])},e.prototype.phpInfoLink=function(){return Object(I.u)()},e}(),X=n(37),Q=function(){function e(){var t=this;y()(this,e),this.domains=U.a.domains,this.visibility=N.a.computed(function(){return t.domains.loading()?"visible":"hidden"}),this.domainForDeletion=N.a.observable(null).deleteAccessHelper(),this.onDomainListChangeRequest=D.a.bind(this.onDomainListChangeRequest,this),this.onDomainLoadRequest=D.a.bind(this.onDomainLoadRequest,this)}return e.prototype.createDomain=function(){Object(z.showScreenPopup)(n(176))},e.prototype.createDomainAlias=function(){Object(z.showScreenPopup)(n(190))},e.prototype.deleteDomain=function(e){this.domains.remove(e),q.a.domainDelete(this.onDomainListChangeRequest,e.name)},e.prototype.disableDomain=function(e){e.disabled(!e.disabled()),q.a.domainDisable(this.onDomainListChangeRequest,e.name,e.disabled())},e.prototype.onBuild=function(e){var t=this;e.on("click",".b-admin-domains-list-table .e-item .e-action",function(){var e=N.a.dataFor(this);e&&q.a.domain(t.onDomainLoadRequest,e.name)}),Object(X.a)().reloadDomainList()},e.prototype.onDomainLoadRequest=function(e,t){P.StorageResultType.Success===e&&t&&t.Result&&Object(z.showScreenPopup)(n(176),[t.Result])},e.prototype.onDomainListChangeRequest=function(){Object(X.a)().reloadDomainList()},e}(),Z=function(){function e(){y()(this,e),this.determineUserLanguage=M.a.determineUserLanguage,this.determineUserDomain=M.a.determineUserDomain,this.defaultDomain=N.a.observable(Object(L.settingsGet)("LoginDefaultDomain")).idleTrigger(),this.allowLanguagesOnLogin=M.a.allowLanguagesOnLogin,this.dummy=N.a.observable(!1)}return e.prototype.onBuild=function(){var e=this;D.a.delay(function(){var t=Object(k.settingsSaveHelperSimpleFunction)(e.defaultDomain.trigger,e);e.determineUserLanguage.subscribe(function(e){q.a.saveAdminConfig(null,{DetermineUserLanguage:Object(k.boolToAjax)(e)})}),e.determineUserDomain.subscribe(function(e){q.a.saveAdminConfig(null,{DetermineUserDomain:Object(k.boolToAjax)(e)})}),e.allowLanguagesOnLogin.subscribe(function(e){q.a.saveAdminConfig(null,{AllowLanguagesOnLogin:Object(k.boolToAjax)(e)})}),e.defaultDomain.subscribe(function(e){q.a.saveAdminConfig(t,{LoginDefaultDomain:Object(k.trim)(e)})})},50)},e}(),ee=n(18),te=n.n(ee),ne=(i=Object(z.command)(function(e){return""!==e.pdoDsn()&&""!==e.pdoUser()}),o=function(){function e(){var t=this;y()(this,e),this.defautOptionsAfterRender=k.defautOptionsAfterRender,this.enableContacts=N.a.observable(!!Object(L.settingsGet)("ContactsEnable")),this.contactsSync=N.a.observable(!!Object(L.settingsGet)("ContactsSync"));var n=[];Object(L.settingsGet)("SQLiteIsSupported")&&n.push("sqlite"),Object(L.settingsGet)("MySqlIsSupported")&&n.push("mysql"),Object(L.settingsGet)("PostgreSqlIsSupported")&&n.push("pgsql"),this.contactsSupported=00&&void 0!==arguments[0]?arguments[0]:null,t=null;t=n(188).default,Object(z.addSettingsViewModel)(J,"AdminSettingsGeneral","TABS_LABELS/LABEL_GENERAL_NAME","general",!0),Object(z.addSettingsViewModel)(Q,"AdminSettingsDomains","TABS_LABELS/LABEL_DOMAINS_NAME","domains"),Object(z.addSettingsViewModel)(Z,"AdminSettingsLogin","TABS_LABELS/LABEL_LOGIN_NAME","login"),t&&Object(z.addSettingsViewModel)(t,"AdminSettingsBranding","TABS_LABELS/LABEL_BRANDING_NAME","branding"),Object(z.addSettingsViewModel)(ne,"AdminSettingsContacts","TABS_LABELS/LABEL_CONTACTS_NAME","contacts"),Object(z.addSettingsViewModel)(ie,"AdminSettingsSecurity","TABS_LABELS/LABEL_SECURITY_NAME","security"),Object(z.addSettingsViewModel)(ae,"AdminSettingsSocial","TABS_LABELS/LABEL_INTEGRATION_NAME","integrations"),Object(z.addSettingsViewModel)(re,"AdminSettingsPlugins","TABS_LABELS/LABEL_PLUGINS_NAME","plugins"),Object(z.addSettingsViewModel)(se,"AdminSettingsPackages","TABS_LABELS/LABEL_PACKAGES_NAME","packages"),Object(z.addSettingsViewModel)(ce,"AdminSettingsAbout","TABS_LABELS/LABEL_ABOUT_NAME","about"),Object(K.g)(!0),e&&e()},t.prototype.onShow=function(){Object(X.a)().setWindowTitle("")},t}(W.a),ve=n(65),Se=(h=Object(z.view)({name:"View/Admin/Login",type:z.ViewType.Center,templateID:"AdminLogin"}),g=Object(z.command)(function(e){return!e.submitRequest()}),h((function(e,t,n,i,o){var a={};Object.keys(i).forEach(function(e){a[e]=i[e]}),a.enumerable=!!a.enumerable,a.configurable=!!a.configurable,("value"in a||a.initializer)&&(a.writable=!0),a=n.slice().reverse().reduce(function(n,i){return i(e,t,n)||n},a),o&&void 0!==a.initializer&&(a.value=a.initializer?a.initializer.call(o):void 0,a.initializer=void 0),void 0===a.initializer&&(Object.defineProperty(e,t,a),a=null)}((v=function(e){function t(){y()(this,t);var n=A()(this,e.call(this));return n.loginPowered=!!L.settingsGet("LoginPowered"),n.mobile=!!L.appSettingsGet("mobile"),n.mobileDevice=!!L.appSettingsGet("mobileDevice"),n.hideSubmitButton=!!L.appSettingsGet("hideSubmitButton"),n.login=N.a.observable(""),n.password=N.a.observable(""),n.loginError=N.a.observable(!1),n.passwordError=N.a.observable(!1),n.loginErrorAnimation=N.a.observable(!1).extend({falseTimeout:500}),n.passwordErrorAnimation=N.a.observable(!1).extend({falseTimeout:500}),n.loginFocus=N.a.observable(!1),n.formHidden=N.a.observable(!1),n.formError=N.a.computed(function(){return n.loginErrorAnimation()||n.passwordErrorAnimation()}),n.login.subscribe(function(){return n.loginError(!1)}),n.password.subscribe(function(){return n.passwordError(!1)}),n.loginError.subscribe(function(e){return n.loginErrorAnimation(!!e)}),n.passwordError.subscribe(function(e){n.passwordErrorAnimation(!!e)}),n.submitRequest=N.a.observable(!1),n.submitError=N.a.observable(""),n}return T()(t,e),t.prototype.submitCommand=function(){var e=this;return Object(k.triggerAutocompleteInputChange)(),this.loginError(!1),this.passwordError(!1),this.loginError(""===Object(k.trim)(this.login())),this.passwordError(""===Object(k.trim)(this.password())),!this.loginError()&&!this.passwordError()&&(this.submitRequest(!0),fe.$win.trigger("rl.tooltips.diactivate"),q.a.adminLogin(function(t,n){fe.$win.trigger("rl.tooltips.diactivate"),fe.$win.trigger("rl.tooltips.activate"),P.StorageResultType.Success===t&&n&&"AdminLogin"===n.Action?n.Result?Object(X.a)().loginAndLogoutReload(!0):n.ErrorCode&&(e.submitRequest(!1),e.submitError(Object(x.getNotification)(n.ErrorCode))):(e.submitRequest(!1),e.submitError(Object(x.getNotification)(P.Notification.UnknownError)))},this.login(),this.password()),!0)},t.prototype.onShow=function(){var e=this;Object(z.routeOff)(),D.a.delay(function(){e.loginFocus(!0)},P.Magics.Time100ms)},t.prototype.onHide=function(){this.loginFocus(!1)},t.prototype.onBuild=function(){Object(k.triggerAutocompleteInputChange)(!0)},t.prototype.submitForm=function(){this.submitCommand()},t}(me.a)).prototype,"submitCommand",[g],te()(v.prototype,"submitCommand"),v.prototype),b=v))||b),ye=function(e){function t(){return y()(this,t),A()(this,e.call(this,"login",[Se]))}return T()(t,e),t.prototype.onShow=function(){Object(X.a)().setWindowTitle("")},t}(ve.a),we=function(e){function t(){return y()(this,t),A()(this,e.call(this,q.a))}return T()(t,e),t.prototype.remote=function(){return q.a},t.prototype.reloadDomainList=function(){U.a.domains.loading(!0),q.a.domainList(function(e,t){U.a.domains.loading(!1),P.StorageResultType.Success===e&&t&&t.Result&&U.a.domains(D.a.map(t.Result,function(e,t){var n=e[0],i=e[1];return{name:t,disabled:N.a.observable(!n),alias:i,deleteAccess:N.a.observable(!1)}}))})},t.prototype.reloadPluginList=function(){H.plugins.loading(!0),q.a.pluginList(function(e,t){H.plugins.loading(!1),P.StorageResultType.Success===e&&t&&t.Result&&H.plugins(D.a.map(t.Result,function(e){return{name:e.Name,disabled:N.a.observable(!e.Enabled),configured:N.a.observable(!!e.Configured)}}))})},t.prototype.reloadPackagesList=function(){B.packages.loading(!0),B.packagesReal(!0),q.a.packagesList(function(e,t){if(B.packages.loading(!1),P.StorageResultType.Success===e&&t&&t.Result){B.packagesReal(!!t.Result.Real),B.packagesMainUpdatable(!!t.Result.MainUpdatable);var n=[],i={};D.a.each(B.packages(),function(e){e&&e.loading()&&(i[e.file]=e)}),Object(k.isArray)(t.Result.List)&&(n=D.a.compact(D.a.map(t.Result.List,function(e){return e?(e.loading=N.a.observable(!Object(k.isUnd)(i[e.file])),"core"!==e.type||e.canBeInstalled?e:null):null}))),B.packages(n)}else B.packagesReal(!1)})},t.prototype.updateCoreData=function(){V.coreUpdating(!0),q.a.updateCoreData(function(e,t){V.coreUpdating(!1),V.coreVersion(""),V.coreRemoteVersion(""),V.coreRemoteRelease(""),V.coreVersionCompare(-2),P.StorageResultType.Success===e&&t&&t.Result?(V.coreReal(!0),_.a.location.reload()):V.coreReal(!1)})},t.prototype.reloadCoreData=function(){V.coreChecking(!0),V.coreReal(!0),q.a.coreData(function(e,t){V.coreChecking(!1),P.StorageResultType.Success===e&&t&&t.Result?(V.coreReal(!!t.Result.Real),V.coreChannel(t.Result.Channel||"stable"),V.coreType(t.Result.Type||"stable"),V.coreUpdatable(!!t.Result.Updatable),V.coreAccess(!!t.Result.Access),V.coreWarning(!!t.Result.Warning),V.coreVersion(t.Result.Version||""),V.coreRemoteVersion(t.Result.RemoteVersion||""),V.coreRemoteRelease(t.Result.RemoteRelease||""),V.coreVersionCompare(Object(k.pInt)(t.Result.VersionCompare))):(V.coreReal(!1),V.coreChannel("stable"),V.coreType("stable"),V.coreWarning(!1),V.coreVersion(""),V.coreRemoteVersion(""),V.coreRemoteRelease(""),V.coreVersionCompare(-2))})},t.prototype.reloadLicensing=function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];G.licensingProcess(!0),G.licenseError(""),q.a.licensing(function(e,t){G.licensingProcess(!1),P.StorageResultType.Success===e&&t&&t.Result&&Object(k.isNormal)(t.Result.Expired)?(G.licenseValid(!0),G.licenseExpired(Object(k.pInt)(t.Result.Expired)),G.licenseError(""),G.licensing(!0),M.a.prem(!0)):t&&t.ErrorCode&&-10&&void 0!==arguments[0]?arguments[0]:null;R.a&&R.a.end(),e&&e()},t.prototype.bootstart=function(){e.prototype.bootstart.call(this),M.a.populate(),F.a.populate(),Object(z.hideLoading)(),L.appSettingsGet("allowAdminPanel")?L.settingsGet("Auth")?Object(z.startScreens)([be]):Object(z.startScreens)([ye]):(Object(z.routeOff)(),Object(z.setHash)(Object(I.w)(),!0),Object(z.routeOff)(),D.a.defer(function(){_.a.location.href="/"})),this.bootend()},t}(n(113).a);t.default=new we},,,,function(e,t,n){"use strict";function i(e,t,n,i,o){var a={};return Object.keys(i).forEach(function(e){a[e]=i[e]}),a.enumerable=!!a.enumerable,a.configurable=!!a.configurable,("value"in a||a.initializer)&&(a.writable=!0),a=n.slice().reverse().reduce(function(n,i){return i(e,t,n)||n},a),o&&void 0!==a.initializer&&(a.value=a.initializer?a.initializer.call(o):void 0,a.initializer=void 0),void 0===a.initializer&&(Object.defineProperty(e,t,a),a=null),a}n.r(t),n.d(t,"DomainPopupView",function(){return x}),n.d(t,"default",function(){return x});var o,a,r,s,c,l,u,d,p=n(18),f=n.n(p),m=n(8),h=n.n(m),g=n(12),b=n.n(g),v=n(11),S=n.n(v),y=n(4),w=n.n(y),A=n(1),O=n(0),T=n(23),C=n(6),_=n(2),E=n(10),D=n(48),N=n(21),j=n(37),R=n(9),I=n(24),x=(o=Object(R.popup)({name:"View/Popup/Domain",templateID:"PopupsDomain"}),a=Object(R.command)(function(e){return e.canBeSaved()}),r=Object(R.command)(function(e){return e.canBeTested()}),s=Object(R.command)(),c=Object(R.command)(),l=Object(R.command)(),o((i((d=function(e){function t(){h()(this,t);var n=b()(this,e.call(this));return n.edit=A.a.observable(!1),n.saving=A.a.observable(!1),n.savingError=A.a.observable(""),n.page=A.a.observable("main"),n.sieveSettings=A.a.observable(!1),n.testing=A.a.observable(!1),n.testingDone=A.a.observable(!1),n.testingImapError=A.a.observable(!1),n.testingSieveError=A.a.observable(!1),n.testingSmtpError=A.a.observable(!1),n.testingImapErrorDesc=A.a.observable(""),n.testingSieveErrorDesc=A.a.observable(""),n.testingSmtpErrorDesc=A.a.observable(""),n.testingImapError.subscribe(function(e){e||n.testingImapErrorDesc("")}),n.testingSieveError.subscribe(function(e){e||n.testingSieveErrorDesc("")}),n.testingSmtpError.subscribe(function(e){e||n.testingSmtpErrorDesc("")}),n.imapServerFocus=A.a.observable(!1),n.sieveServerFocus=A.a.observable(!1),n.smtpServerFocus=A.a.observable(!1),n.name=A.a.observable(""),n.name.focused=A.a.observable(!1),n.imapServer=A.a.observable(""),n.imapPort=A.a.observable(""+T.h),n.imapSecure=A.a.observable(O.ServerSecure.None),n.imapShortLogin=A.a.observable(!1),n.useSieve=A.a.observable(!1),n.sieveAllowRaw=A.a.observable(!1),n.sieveServer=A.a.observable(""),n.sievePort=A.a.observable(""+T.o),n.sieveSecure=A.a.observable(O.ServerSecure.None),n.smtpServer=A.a.observable(""),n.smtpPort=A.a.observable(""+T.p),n.smtpSecure=A.a.observable(O.ServerSecure.None),n.smtpShortLogin=A.a.observable(!1),n.smtpAuth=A.a.observable(!0),n.smtpPhpMail=A.a.observable(!1),n.whiteList=A.a.observable(""),n.aliasName=A.a.observable(""),n.enableSmartPorts=A.a.observable(!1),n.allowSieve=A.a.computed(function(){return D.a.filters()&&D.a.sieve()}),n.headerText=A.a.computed(function(){var e=n.name(),t=n.aliasName(),i="";return n.edit()?(i=Object(E.i18n)("POPUPS_DOMAIN/TITLE_EDIT_DOMAIN",{NAME:e}),t&&(i+=" ← "+t)):i=""===e?Object(E.i18n)("POPUPS_DOMAIN/TITLE_ADD_DOMAIN"):Object(E.i18n)("POPUPS_DOMAIN/TITLE_ADD_DOMAIN_WITH_NAME",{NAME:e}),i}),n.domainDesc=A.a.computed(function(){var e=n.name();return!n.edit()&&e?Object(E.i18n)("POPUPS_DOMAIN/NEW_DOMAIN_DESC",{NAME:"*@"+e}):""}),n.domainIsComputed=A.a.computed(function(){var e=n.smtpPhpMail(),t=n.allowSieve(),i=n.useSieve();return""!==n.name()&&""!==n.imapServer()&&""!==n.imapPort()&&(!t||!i||""!==n.sieveServer()&&""!==n.sievePort())&&(""!==n.smtpServer()&&""!==n.smtpPort()||e)}),n.canBeTested=A.a.computed(function(){return!n.testing()&&n.domainIsComputed()}),n.canBeSaved=A.a.computed(function(){return!n.saving()&&n.domainIsComputed()}),n.page.subscribe(function(){n.sieveSettings(!1)}),n.imapServerFocus.subscribe(function(e){e&&""!==n.name()&&""===n.imapServer()&&n.imapServer(n.name().replace(/[.]?[*][.]?/g,""))}),n.sieveServerFocus.subscribe(function(e){e&&""!==n.imapServer()&&""===n.sieveServer()&&n.sieveServer(n.imapServer())}),n.smtpServerFocus.subscribe(function(e){e&&""!==n.imapServer()&&""===n.smtpServer()&&n.smtpServer(n.imapServer().replace(/imap/gi,"smtp"))}),n.imapSecure.subscribe(function(e){if(n.enableSmartPorts()){var t=Object(_.pInt)(n.imapPort());switch(Object(_.pString)(e)){case"0":case"2":O.Ports.ImapSsl===t&&n.imapPort(Object(_.pString)(O.Ports.Imap));break;case"1":O.Ports.Imap===t&&n.imapPort(Object(_.pString)(O.Ports.ImapSsl))}}}),n.smtpSecure.subscribe(function(e){if(n.enableSmartPorts()){var t=Object(_.pInt)(n.smtpPort());switch(Object(_.pString)(e)){case"0":O.Ports.SmtpSsl!==t&&O.Ports.SmtpStartTls!==t||n.smtpPort(Object(_.pString)(O.Ports.Smtp));break;case"1":O.Ports.Smtp!==t&&O.Ports.SmtpStartTls!==t||n.smtpPort(Object(_.pString)(O.Ports.SmtpSsl));break;case"2":O.Ports.Smtp!==t&&O.Ports.SmtpSsl!==t||n.smtpPort(Object(_.pString)(O.Ports.SmtpStartTls))}}}),n}return S()(t,e),t.prototype.createOrAddCommand=function(){this.saving(!0),N.a.createOrUpdateDomain(w.a.bind(this.onDomainCreateOrSaveResponse,this),!this.edit(),this.name(),this.imapServer(),Object(_.pInt)(this.imapPort()),this.imapSecure(),this.imapShortLogin(),this.useSieve(),this.sieveAllowRaw(),this.sieveServer(),Object(_.pInt)(this.sievePort()),this.sieveSecure(),this.smtpServer(),Object(_.pInt)(this.smtpPort()),this.smtpSecure(),this.smtpShortLogin(),this.smtpAuth(),this.smtpPhpMail(),this.whiteList())},t.prototype.testConnectionCommand=function(){this.page("main"),this.testingDone(!1),this.testingImapError(!1),this.testingSieveError(!1),this.testingSmtpError(!1),this.testing(!0),N.a.testConnectionForDomain(w.a.bind(this.onTestConnectionResponse,this),this.name(),this.imapServer(),Object(_.pInt)(this.imapPort()),this.imapSecure(),this.useSieve(),this.sieveServer(),Object(_.pInt)(this.sievePort()),this.sieveSecure(),this.smtpServer(),Object(_.pInt)(this.smtpPort()),this.smtpSecure(),this.smtpAuth(),this.smtpPhpMail())},t.prototype.whiteListCommand=function(){this.page("white-list")},t.prototype.backCommand=function(){this.page("main")},t.prototype.sieveCommand=function(){this.sieveSettings(!this.sieveSettings()),this.clearTesting()},t.prototype.onTestConnectionResponse=function(e,t){if(this.testing(!1),O.StorageResultType.Success===e&&t.Result){var n=!1,i=!1;this.testingDone(!0),this.testingImapError(!0!==t.Result.Imap),this.testingSieveError(!0!==t.Result.Sieve),this.testingSmtpError(!0!==t.Result.Smtp),this.testingImapError()&&t.Result.Imap&&(n=!0,this.testingImapErrorDesc(""),this.testingImapErrorDesc(t.Result.Imap)),this.testingSieveError()&&t.Result.Sieve&&(i=!0,this.testingSieveErrorDesc(""),this.testingSieveErrorDesc(t.Result.Sieve)),this.testingSmtpError()&&t.Result.Smtp&&(this.testingSmtpErrorDesc(""),this.testingSmtpErrorDesc(t.Result.Smtp)),this.sieveSettings()?!i&&n&&this.sieveSettings(!1):i&&!n&&this.sieveSettings(!0)}else this.testingImapError(!0),this.testingSieveError(!0),this.testingSmtpError(!0),this.sieveSettings(!1)},t.prototype.onDomainCreateOrSaveResponse=function(e,t){this.saving(!1),O.StorageResultType.Success===e&&t?t.Result?(Object(j.a)().reloadDomainList(),this.closeCommand()):O.Notification.DomainAlreadyExists===t.ErrorCode&&this.savingError(Object(E.i18n)("ERRORS/DOMAIN_ALREADY_EXISTS")):this.savingError(Object(E.i18n)("ERRORS/UNKNOWN_ERROR"))},t.prototype.clearTesting=function(){this.testing(!1),this.testingDone(!1),this.testingImapError(!1),this.testingSieveError(!1),this.testingSmtpError(!1)},t.prototype.onHide=function(){this.page("main"),this.sieveSettings(!1)},t.prototype.onShow=function(e){this.saving(!1),this.page("main"),this.sieveSettings(!1),this.clearTesting(),this.clearForm(),e&&(this.enableSmartPorts(!1),this.edit(!0),this.name(Object(_.trim)(e.Name)),this.imapServer(Object(_.trim)(e.IncHost)),this.imapPort(""+Object(_.pInt)(e.IncPort)),this.imapSecure(Object(_.trim)(e.IncSecure)),this.imapShortLogin(!!e.IncShortLogin),this.useSieve(!!e.UseSieve),this.sieveAllowRaw(!!e.SieveAllowRaw),this.sieveServer(Object(_.trim)(e.SieveHost)),this.sievePort(""+Object(_.pInt)(e.SievePort)),this.sieveSecure(Object(_.trim)(e.SieveSecure)),this.smtpServer(Object(_.trim)(e.OutHost)),this.smtpPort(""+Object(_.pInt)(e.OutPort)),this.smtpSecure(Object(_.trim)(e.OutSecure)),this.smtpShortLogin(!!e.OutShortLogin),this.smtpAuth(!!e.OutAuth),this.smtpPhpMail(!!e.OutUsePhpMail),this.whiteList(Object(_.trim)(e.WhiteList)),this.aliasName(Object(_.trim)(e.AliasName)),this.enableSmartPorts(!0))},t.prototype.onShowWithDelay=function(){""!==this.name()||C.bMobileDevice||this.name.focused(!0)},t.prototype.clearForm=function(){this.edit(!1),this.page("main"),this.sieveSettings(!1),this.enableSmartPorts(!1),this.savingError(""),this.name(""),this.name.focused(!1),this.imapServer(""),this.imapPort(""+T.h),this.imapSecure(O.ServerSecure.None),this.imapShortLogin(!1),this.useSieve(!1),this.sieveAllowRaw(!1),this.sieveServer(""),this.sievePort(""+T.o),this.sieveSecure(O.ServerSecure.None),this.smtpServer(""),this.smtpPort(""+T.p),this.smtpSecure(O.ServerSecure.None),this.smtpShortLogin(!1),this.smtpAuth(!0),this.smtpPhpMail(!1),this.whiteList(""),this.aliasName(""),this.enableSmartPorts(!0)},t}(I.a)).prototype,"createOrAddCommand",[a],f()(d.prototype,"createOrAddCommand"),d.prototype),i(d.prototype,"testConnectionCommand",[r],f()(d.prototype,"testConnectionCommand"),d.prototype),i(d.prototype,"whiteListCommand",[s],f()(d.prototype,"whiteListCommand"),d.prototype),i(d.prototype,"backCommand",[c],f()(d.prototype,"backCommand"),d.prototype),i(d.prototype,"sieveCommand",[l],f()(d.prototype,"sieveCommand"),d.prototype),u=d))||u)},,,,,,,,,,,,function(e,t,n){"use strict";n.r(t),n.d(t,"BrandingAdminSettings",function(){return m}),n.d(t,"default",function(){return m});var i=n(8),o=n.n(i),a=n(4),r=n.n(a),s=n(1),c=n(0),l=n(2),u=n(10),d=n(21),p=n(38),f=n(5),m=function(){function e(){o()(this,e),this.capa=p.a.prem,this.title=s.a.observable(Object(f.settingsGet)("Title")).idleTrigger(),this.loadingDesc=s.a.observable(Object(f.settingsGet)("LoadingDescription")).idleTrigger(),this.faviconUrl=s.a.observable(Object(f.settingsGet)("FaviconUrl")).idleTrigger(),this.loginLogo=s.a.observable(Object(f.settingsGet)("LoginLogo")||"").idleTrigger(),this.loginBackground=s.a.observable(Object(f.settingsGet)("LoginBackground")||"").idleTrigger(),this.userLogo=s.a.observable(Object(f.settingsGet)("UserLogo")||"").idleTrigger(),this.userLogoMessage=s.a.observable(Object(f.settingsGet)("UserLogoMessage")||"").idleTrigger(),this.userIframeMessage=s.a.observable(Object(f.settingsGet)("UserIframeMessage")||"").idleTrigger(),this.userLogoTitle=s.a.observable(Object(f.settingsGet)("UserLogoTitle")||"").idleTrigger(),this.loginDescription=s.a.observable(Object(f.settingsGet)("LoginDescription")).idleTrigger(),this.loginCss=s.a.observable(Object(f.settingsGet)("LoginCss")).idleTrigger(),this.userCss=s.a.observable(Object(f.settingsGet)("UserCss")).idleTrigger(),this.welcomePageUrl=s.a.observable(Object(f.settingsGet)("WelcomePageUrl")).idleTrigger(),this.welcomePageDisplay=s.a.observable(Object(f.settingsGet)("WelcomePageDisplay")).idleTrigger(),this.welcomePageDisplay.options=s.a.computed(function(){return Object(u.trigger)(),[{optValue:"none",optText:Object(u.i18n)("TAB_BRANDING/OPTION_WELCOME_PAGE_DISPLAY_NONE")},{optValue:"once",optText:Object(u.i18n)("TAB_BRANDING/OPTION_WELCOME_PAGE_DISPLAY_ONCE")},{optValue:"always",optText:Object(u.i18n)("TAB_BRANDING/OPTION_WELCOME_PAGE_DISPLAY_ALWAYS")}]}),this.loginPowered=s.a.observable(!!Object(f.settingsGet)("LoginPowered")),this.community=!0}return e.prototype.onBuild=function(){var e=this;r.a.delay(function(){var t=Object(l.settingsSaveHelperSimpleFunction)(e.title.trigger,e),n=Object(l.settingsSaveHelperSimpleFunction)(e.loadingDesc.trigger,e),i=Object(l.settingsSaveHelperSimpleFunction)(e.faviconUrl.trigger,e);e.title.subscribe(function(e){d.a.saveAdminConfig(t,{Title:Object(l.trim)(e)})}),e.loadingDesc.subscribe(function(e){d.a.saveAdminConfig(n,{LoadingDescription:Object(l.trim)(e)})}),e.faviconUrl.subscribe(function(e){d.a.saveAdminConfig(i,{FaviconUrl:Object(l.trim)(e)})})},c.Magics.Time50ms)},e}()},function(e,t,n){"use strict";n.r(t),n.d(t,"PluginPopupView",function(){return I}),n.d(t,"default",function(){return I});var i,o,a,r,s,c,l,u,d,p,f=n(18),m=n.n(f),h=n(8),g=n.n(h),b=n(12),v=n.n(b),S=n(11),y=n.n(S),w=n(4),A=n.n(w),O=n(1),T=n(19),C=n.n(T),_=n(0),E=n(2),D=n(10),N=n(21),j=n(9),R=n(24),I=(i=Object(j.popup)({name:"View/Popup/Plugin",templateID:"PopupsPlugin"}),o=Object(j.command)(function(e){return e.hasConfiguration()}),i((r=function(e){function t(){g()(this,t);var n=v()(this,e.call(this));return n.onPluginSettingsUpdateResponse=A.a.bind(n.onPluginSettingsUpdateResponse,n),n.saveError=O.a.observable(""),n.name=O.a.observable(""),n.readme=O.a.observable(""),n.configures=O.a.observableArray([]),n.hasReadme=O.a.computed(function(){return""!==n.readme()}),n.hasConfiguration=O.a.computed(function(){return 0"+n.readme()+" "}},n.bDisabeCloseOnEsc=!0,n.sDefaultKeyScope=_.KeyState.All,n.tryToClosePopup=A.a.debounce(A.a.bind(n.tryToClosePopup,n),_.Magics.Time200ms),n}return y()(t,e),t.prototype.saveCommand=function(){var e={};e.Name=this.name(),A.a.each(this.configures(),function(t){var n=t.value();!1!==n&&!0!==n||(n=n?"1":"0"),e["_"+t.Name]=n}),this.saveError(""),N.a.pluginSettingsUpdate(this.onPluginSettingsUpdateResponse,e)},t.prototype.onPluginSettingsUpdateResponse=function(e,t){_.StorageResultType.Success===e&&t&&t.Result?this.cancelCommand():(this.saveError(""),t&&t.ErrorCode?this.saveError(Object(D.getNotification)(t.ErrorCode)):this.saveError(Object(D.getNotification)(_.Notification.CantSavePluginSettings)))},t.prototype.onShow=function(e){if(this.name(),this.readme(),this.configures([]),e){this.name(e.Name),this.readme(e.Readme);var t=e.Config;Object(E.isNonEmptyArray)(t)&&this.configures(A.a.map(t,function(e){return{value:O.a.observable(e[0]),placeholder:O.a.observable(e[6]),Name:e[1],Type:e[2],Label:e[3],Default:e[4],Desc:e[5]}}))}},t.prototype.tryToClosePopup=function(){var e=this,t=n(99);Object(j.isPopupVisible)(t)||Object(j.showScreenPopup)(t,[Object(D.i18n)("POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW"),function(){e.modalVisibility()&&Object(E.delegateRun)(e,"cancelCommand")}])},t.prototype.onBuild=function(){var e=this;C()("esc",_.KeyState.All,function(){return e.modalVisibility()&&e.tryToClosePopup(),!1})},t}(R.a),s=r.prototype,c="saveCommand",l=[o],u=m()(r.prototype,"saveCommand"),d=r.prototype,p={},Object.keys(u).forEach(function(e){p[e]=u[e]}),p.enumerable=!!p.enumerable,p.configurable=!!p.configurable,("value"in p||p.initializer)&&(p.writable=!0),p=l.slice().reverse().reduce(function(e,t){return t(s,c,e)||e},p),d&&void 0!==p.initializer&&(p.value=p.initializer?p.initializer.call(d):void 0,p.initializer=void 0),void 0===p.initializer&&(Object.defineProperty(s,c,p),p=null),a=r))||a)},function(e,t,n){"use strict";n.r(t),n.d(t,"DomainAliasPopupView",function(){return I}),n.d(t,"default",function(){return I});var i,o,a,r,s,c,l,u,d,p,f=n(18),m=n.n(f),h=n(8),g=n.n(h),b=n(12),v=n.n(b),S=n(11),y=n.n(S),w=n(4),A=n.n(w),O=n(1),T=n(0),C=n(6),_=n(10),E=n(68),D=n(21),N=n(37),j=n(9),R=n(24),I=(i=Object(j.popup)({name:"View/Popup/DomainAlias",templateID:"PopupsDomainAlias"}),o=Object(j.command)(function(e){return e.canBeSaved()}),i((r=function(e){function t(){g()(this,t);var n=v()(this,e.call(this));return n.saving=O.a.observable(!1),n.savingError=O.a.observable(""),n.name=O.a.observable(""),n.name.focused=O.a.observable(!1),n.alias=O.a.observable(""),n.domains=E.a.domainsWithoutAliases,n.domainsOptions=O.a.computed(function(){return A.a.map(n.domains(),function(e){return{optValue:e.name,optText:e.name}})}),n.canBeSaved=O.a.computed(function(){return!n.saving()&&""!==n.name()&&""!==n.alias()}),n.onDomainAliasCreateOrSaveResponse=A.a.bind(n.onDomainAliasCreateOrSaveResponse,n),n}return y()(t,e),t.prototype.createCommand=function(){this.saving(!0),D.a.createDomainAlias(this.onDomainAliasCreateOrSaveResponse,this.name(),this.alias())},t.prototype.onDomainAliasCreateOrSaveResponse=function(e,t){this.saving(!1),T.StorageResultType.Success===e&&t?t.Result?(Object(N.a)().reloadDomainList(),this.closeCommand()):T.Notification.DomainAlreadyExists===t.ErrorCode&&this.savingError(Object(_.i18n)("ERRORS/DOMAIN_ALREADY_EXISTS")):this.savingError(Object(_.i18n)("ERRORS/UNKNOWN_ERROR"))},t.prototype.onShow=function(){this.clearForm()},t.prototype.onShowWithDelay=function(){""!==this.name()||C.bMobileDevice||this.name.focused(!0)},t.prototype.clearForm=function(){this.saving(!1),this.savingError(""),this.name(""),this.name.focused(!1),this.alias("")},t}(R.a),s=r.prototype,c="createCommand",l=[o],u=m()(r.prototype,"createCommand"),d=r.prototype,p={},Object.keys(u).forEach(function(e){p[e]=u[e]}),p.enumerable=!!p.enumerable,p.configurable=!!p.configurable,("value"in p||p.initializer)&&(p.writable=!0),p=l.slice().reverse().reduce(function(e,t){return t(s,c,e)||e},p),d&&void 0!==p.initializer&&(p.value=p.initializer?p.initializer.call(d):void 0,p.initializer=void 0),void 0===p.initializer&&(Object.defineProperty(s,c,p),p=null),a=r))||a)},function(e,t,n){"use strict";n.r(t);var i=n(117),o=n(172);Object(i.a)(o.default)}]);
diff --git a/rainloop/app/rainloop/v/1.12.0/static/js/min/app.min.js b/rainloop/app/rainloop/v/1.12.0/static/js/min/app.min.js
deleted file mode 100644
index 80b03f4dc4c06f62ccb2899ec6470cdd3a334fa3..0000000000000000000000000000000000000000
--- a/rainloop/app/rainloop/v/1.12.0/static/js/min/app.min.js
+++ /dev/null
@@ -1 +0,0 @@
-!function(e){function t(o){if(n[o])return n[o].exports;var i=n[o]={i:o,l:!1,exports:{}};return e[o].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var n={};t.m=e,t.c=n,t.d=function(e,n,o){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:o})},t.r=function(e){Object.defineProperty(e,"__esModule",{value:!0})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="rainloop/v/0.0.0/static/js/min/",t(t.s=201)}([function(e,t,n){"use strict";n.r(t),n.d(t,"FileType",function(){return o}),n.d(t,"StorageResultType",function(){return i}),n.d(t,"Focused",function(){return a}),n.d(t,"State",function(){return r}),n.d(t,"StateType",function(){return s}),n.d(t,"Capa",function(){return c}),n.d(t,"KeyState",function(){return l}),n.d(t,"FolderType",function(){return u}),n.d(t,"ServerFolderType",function(){return d}),n.d(t,"LoginSignMeTypeAsString",function(){return p}),n.d(t,"LoginSignMeType",function(){return h}),n.d(t,"ComposeType",function(){return f}),n.d(t,"UploadErrorCode",function(){return m}),n.d(t,"SetSystemFoldersNotification",function(){return b}),n.d(t,"ClientSideKeyName",function(){return g}),n.d(t,"EventKeyCode",function(){return y}),n.d(t,"MessageSetAction",function(){return v}),n.d(t,"MessageSelectAction",function(){return S}),n.d(t,"DesktopNotification",function(){return O}),n.d(t,"MessagePriority",function(){return w}),n.d(t,"EditorDefaultType",function(){return T}),n.d(t,"ServerSecure",function(){return C}),n.d(t,"SearchDateType",function(){return A}),n.d(t,"SaveSettingsStep",function(){return E}),n.d(t,"Layout",function(){return F}),n.d(t,"FilterConditionField",function(){return j}),n.d(t,"FilterConditionType",function(){return N}),n.d(t,"FiltersAction",function(){return R}),n.d(t,"FilterRulesType",function(){return I}),n.d(t,"SignedVerifyStatus",function(){return L}),n.d(t,"ContactPropertyType",function(){return _}),n.d(t,"Magics",function(){return P}),n.d(t,"Ports",function(){return D}),n.d(t,"Notification",function(){return M});var o={Unknown:"unknown",Text:"text",Html:"html",Code:"code",Eml:"eml",WordText:"word-text",Pdf:"pdf",Image:"image",Audio:"audio",Video:"video",Sheet:"sheet",Presentation:"presentation",Certificate:"certificate",CertificateBin:"certificate-bin",Archive:"archive"},i={Success:"success",Abort:"abort",Error:"error",Unload:"unload"},a={None:"none",MessageList:"message-list",MessageView:"message-view",FolderList:"folder-list"},r={Empty:10,Login:20,Auth:30},s={Webmail:0,Admin:1},c={TwoFactor:"TWO_FACTOR",TwoFactorForce:"TWO_FACTOR_FORCE",OpenPGP:"OPEN_PGP",Prefetch:"PREFETCH",Gravatar:"GRAVATAR",Folders:"FOLDERS",Composer:"COMPOSER",Contacts:"CONTACTS",Reload:"RELOAD",Search:"SEARCH",SearchAdv:"SEARCH_ADV",MessageActions:"MESSAGE_ACTIONS",MessageListActions:"MESSAGELIST_ACTIONS",AttachmentsActions:"ATTACHMENTS_ACTIONS",DangerousActions:"DANGEROUS_ACTIONS",Settings:"SETTINGS",Help:"HELP",Themes:"THEMES",UserBackground:"USER_BACKGROUND",Sieve:"SIEVE",Filters:"FILTERS",AttachmentThumbnails:"ATTACHMENT_THUMBNAILS",Templates:"TEMPLATES",AutoLogout:"AUTOLOGOUT",AdditionalAccounts:"ADDITIONAL_ACCOUNTS",Identities:"IDENTITIES"},l={All:"all",None:"none",ContactList:"contact-list",MessageList:"message-list",FolderList:"folder-list",MessageView:"message-view",Compose:"compose",Settings:"settings",Menu:"menu",PopupComposeOpenPGP:"compose-open-pgp",PopupMessageOpenPGP:"message-open-pgp",PopupViewOpenPGP:"view-open-pgp",PopupKeyboardShortcutsHelp:"popup-keyboard-shortcuts-help",PopupAsk:"popup-ask"},u={Inbox:10,SentItems:11,Draft:12,Trash:13,Spam:14,Archive:15,NotSpam:80,User:99},d={USER:0,INBOX:1,SENT:2,DRAFTS:3,JUNK:4,TRASH:5,IMPORTANT:10,FLAGGED:11,ALL:12},p={DefaultOff:"defaultoff",DefaultOn:"defaulton",Unused:"unused"},h={DefaultOff:0,DefaultOn:1,Unused:2},f={Empty:"empty",Reply:"reply",ReplyAll:"replyall",Forward:"forward",ForwardAsAttachment:"forward-as-attachment",Draft:"draft",EditAsNew:"editasnew"},m={Normal:0,FileIsTooBig:1,FilePartiallyUploaded:2,FileNoUploaded:3,MissingTempFolder:4,FileOnSaveingError:5,FileType:98,Unknown:99},b={None:0,Sent:1,Draft:2,Spam:3,Trash:4,Archive:5},g={FoldersLashHash:0,MessagesInboxLastHash:1,MailBoxListSize:2,ExpandedFolders:3,FolderListSize:4,MessageListSize:5,LastReplyAction:6,LastSignMe:7,ComposeLastIdentityID:8,MessageHeaderFullInfo:9,MessageAttachmnetControls:10},y={Backspace:8,Tab:9,Enter:13,Esc:27,PageUp:33,PageDown:34,Left:37,Right:39,Up:38,Down:40,End:35,Home:36,Space:32,Insert:45,Delete:46,A:65,S:83},v={SetSeen:0,UnsetSeen:1,SetFlag:2,UnsetFlag:3},S={All:0,None:1,Invert:2,Unseen:3,Seen:4,Flagged:5,Unflagged:6},O={Allowed:0,NotAllowed:1,Denied:2,NotSupported:9},w={Low:5,Normal:3,High:1},T={Html:"Html",Plain:"Plain",HtmlForced:"HtmlForced",PlainForced:"PlainForced"},C={None:0,SSL:1,TLS:2},A={All:-1,Days3:3,Days7:7,Month:30},E={Animate:-2,Idle:-1,TrueResult:1,FalseResult:0},F={NoPreview:0,SidePreview:1,BottomPreview:2},j={From:"From",Recipient:"Recipient",Subject:"Subject",Header:"Header",Size:"Size"},N={Contains:"Contains",NotContains:"NotContains",EqualTo:"EqualTo",NotEqualTo:"NotEqualTo",Regex:"Regex",Over:"Over",Under:"Under"},R={None:"None",MoveTo:"MoveTo",Discard:"Discard",Vacation:"Vacation",Reject:"Reject",Forward:"Forward"},I={All:"All",Any:"Any"},L={UnknownPublicKeys:-4,UnknownPrivateKey:-3,Unverified:-2,Error:-1,None:0,Success:1},_={Unknown:0,FullName:10,FirstName:15,LastName:16,MiddleName:16,Nick:18,NamePrefix:20,NameSuffix:21,Email:30,Phone:31,Web:32,Birthday:40,Facebook:90,Skype:91,GitHub:92,Note:110,Custom:250},P={EventWhichMouseMiddle:3,ifvisibleIdle10s:10,BitLength2048:2048,BitLength1024:1024,Size350px:350,Size50px:50,Size20px:20,Size1px:1,Time30mInMin:30,Time60m:36e5,Time30m:18e5,Time20m:12e5,Time15m:9e5,Time10m:6e5,Time5m:3e5,Time3m:18e4,Time2m:12e4,Time1m:6e4,Time30s:3e4,Time10s:1e4,Time7s:7e3,Time5s:5e3,Time3s:3e3,Time1s:1e3,Time500ms:500,Time350ms:350,Time250ms:250,Time200ms:200,Time100ms:100,Time50ms:50,Time20ms:20,Time10ms:10,Time1ms:1},D={Imap:143,ImapSsl:993,Smtp:25,SmtpSsl:465,SmtpStartTls:587},M={InvalidToken:101,AuthError:102,AccessError:103,ConnectionError:104,CaptchaError:105,SocialFacebookLoginAccessDisable:106,SocialTwitterLoginAccessDisable:107,SocialGoogleLoginAccessDisable:108,DomainNotAllowed:109,AccountNotAllowed:110,AccountTwoFactorAuthRequired:120,AccountTwoFactorAuthError:121,CouldNotSaveNewPassword:130,CurrentPasswordIncorrect:131,NewPasswordShort:132,NewPasswordWeak:133,NewPasswordForbidden:134,ContactsSyncError:140,CantGetMessageList:201,CantGetMessage:202,CantDeleteMessage:203,CantMoveMessage:204,CantCopyMessage:205,CantSaveMessage:301,CantSendMessage:302,InvalidRecipients:303,CantSaveFilters:351,CantGetFilters:352,FiltersAreNotCorrect:355,CantCreateFolder:400,CantRenameFolder:401,CantDeleteFolder:402,CantSubscribeFolder:403,CantUnsubscribeFolder:404,CantDeleteNonEmptyFolder:405,CantSaveSettings:501,CantSavePluginSettings:502,DomainAlreadyExists:601,CantInstallPackage:701,CantDeletePackage:702,InvalidPluginPackage:703,UnsupportedPluginPackage:704,LicensingServerIsUnavailable:710,LicensingExpired:711,LicensingBanned:712,DemoSendMessageError:750,DemoAccountError:751,AccountAlreadyExists:801,AccountDoesNotExist:802,MailServerError:901,ClientViewError:902,InvalidInputArgument:903,AjaxFalse:950,AjaxAbort:951,AjaxParse:952,AjaxTimeout:953,UnknownNotification:999,UnknownError:999}},function(e,t,n){"use strict";var o=n(3),i=n.n(o),a=n(4),r=n.n(a),s=n(7),c=n.n(s),l=i.a.Opentip||{};l.styles=l.styles||{},l.styles.rainloop={extends:"standard",fixed:!0,target:!0,delay:.2,hideDelay:0,hideEffect:"fade",hideEffectDuration:.2,showEffect:"fade",showEffectDuration:.2,showOn:"mouseover click",removeElementsOnHide:!0,background:"#fff",shadow:!1,borderColor:"#999",borderRadius:2,borderWidth:1},l.styles.rainloopTip={extends:"rainloop",delay:.4,group:"rainloopTips"},l.styles.rainloopErrorTip={extends:"rainloop",className:"rainloopErrorTip"};var u=n(97),d=n.n(u),p=n(0),h=i.a.ko,f=c()(i.a);h.bindingHandlers.updateWidth={init:function(e,t){var n=c()(e),o=t(),a=function(){o(n.width()),i.a.setTimeout(function(){o(n.width())},p.Magics.Time500ms)};f.on("resize",a),a(),h.utils.domNodeDisposal.addDisposeCallback(e,function(){f.off("resize",a)})}},h.bindingHandlers.editor={init:function(e,t){var o=null,i=t(),a=n(95).default,r=function(){i&&i.__editor&&i.__editor.setHtmlOrPlain(i())},s=function(){i&&i.__editor&&i(i.__editor.getDataWithHtmlMark())};h.isObservable(i)&&a&&(o=new a(e,s,function(){i.__editor=o,r()},s),i.__fetchEditorValue=s,i.subscribe(r))}},h.bindingHandlers.json={init:function(e,t){c()(e).text(i.a.JSON.stringify(h.unwrap(t())))},update:function(e,t){c()(e).text(i.a.JSON.stringify(h.unwrap(t())))}},h.bindingHandlers.scrollerShadows={init:function(e){var t=c()(e),n=t.find("[data-scroller-shadows-content]")[0]||null,o=r.a.throttle(function(){t.toggleClass("scroller-shadow-top",8=n.left&&e.pageX<=n.left+t.width()){if(e.pageY>=o-100&&e.pageY<=o){var a=function(){t.scrollTop(t.scrollTop()+3),r.windowResize()};t.data("timerScroll",i.a.setInterval(a,10)),a()}if(e.pageY>=n.top&&e.pageY<=n.top+100){var s=function(){t.scrollTop(t.scrollTop()-3),r.windowResize()};t.data("timerScroll",i.a.setInterval(s,10)),s()}}})},u.stop=function(){c()(l).each(function(){var e=c()(this);i.a.clearInterval(e.data("timerScroll")),e.data("timerScroll",!1)})}),u.helper=function(e){return t()(e&&e.target?h.dataFor(e.target):null)},c()(e).draggable(u).on("mousedown.koDraggable",function(){r.removeInFocus()}),h.utils.domNodeDisposal.addDisposeCallback(e,function(){c()(e).off("mousedown.koDraggable").draggable("destroy")})}}},h.bindingHandlers.droppable={init:function(e,t,o){if(!n(6).bMobileDevice){var i=t(),a=o(),r=a&&a.droppableOver?a.droppableOver:null,s=a&&a.droppableOut?a.droppableOut:null,l={tolerance:"pointer",hoverClass:"droppableHover",drop:null,over:null,out:null};i&&(l.drop=function(e,t){i(e,t)},r&&(l.over=function(e,t){r(e,t)}),s&&(l.out=function(e,t){s(e,t)}),c()(e).droppable(l),h.utils.domNodeDisposal.addDisposeCallback(e,function(){c()(e).droppable("destroy")}))}}},h.bindingHandlers.nano={init:function(e){var t=n(6),o=n(5);t.bDisableNanoScroll||o.appSettingsGet("useNativeScrollbars")||c()(e).addClass("nano").nanoScroller({iOSNativeScrolling:!1,preventPageScrolling:!0})}},h.bindingHandlers.saveTrigger={init:function(e){var t=c()(e);t.data("save-trigger-type",t.is("input[type=text],input[type=email],input[type=password],select,textarea")?"input":"custom"),"custom"===t.data("save-trigger-type")?t.append(' ').addClass("settings-saved-trigger"):t.addClass("settings-saved-trigger-input")},update:function(e,t){var n=h.unwrap(t()),o=c()(e);if("custom"===o.data("save-trigger-type"))switch(n.toString()){case"1":o.find(".animated,.error").hide().removeClass("visible").end().find(".success").show().addClass("visible");break;case"0":o.find(".animated,.success").hide().removeClass("visible").end().find(".error").show().addClass("visible");break;case"-2":o.find(".error,.success").hide().removeClass("visible").end().find(".animated").show().addClass("visible");break;default:o.find(".animated").hide().end().find(".error,.success").removeClass("visible")}else switch(n.toString()){case"1":o.addClass("success").removeClass("error");break;case"0":o.addClass("error").removeClass("success");break;case"-2":break;default:o.removeClass("error success")}}},h.bindingHandlers.emailsTags={init:function(e,t,o){var i=n(2),a=n(44).default,s=c()(e),l=t(),u=o().autoCompleteSource||null,d=[",",";","\n"];s.inputosaurus({parseOnBlur:!0,allowDragAndDrop:!0,focusCallback:function(e){l&&l.focused&&l.focused(!!e)},inputDelimiters:d,autoCompleteSource:u,splitHook:function(e){var t=i.trim(e);return t&&-1=i&&(i=t),i===e()&&""+i!=""+n&&e(i+1),e(i)}});return i(e()),i},h.extenders.limitedList=function(e,t){var o=n(2),i=h.computed({read:e,write:function(n){var i=h.unwrap(e),a=h.unwrap(t);o.isNonEmptyArray(a)?-11&&void 0!==arguments[1])||arguments[1];return!!i(e)&&(t?/^[0-9]*$/.test(e.toString()):/^[1-9]+[0-9]*$/.test(e.toString()))}function r(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=i(e)&&""!==e?ce.a.parseInt(e,10):t;return ce.a.isNaN(n)?t:n}function s(e){return i(e)?""+e:""}function c(e){return!!e}function l(e){return e?"1":"0"}function u(e){return Te(e)&&00&&void 0!==arguments[0]?arguments[0]:32,t="0123456789abcdefghijklmnopqrstuvwxyz",n=t.length;e=r(e);for(var o="";o.length1&&void 0!==arguments[1]?arguments[1]:100,n="",o="",i=e,a=0,r=0;i.length>t;)a=(o=i.substring(0,t)).lastIndexOf(" "),-1!==(r=o.lastIndexOf("\n"))&&(a=r),-1===a&&(a=t),n+=o.substring(0,a)+"\n",i=i.substring(a+1);return n+i}function v(){try{if(ce.a.document.activeElement)return Ee(ce.a.document.activeElement.__inFocusCache)&&(ce.a.document.activeElement.__inFocusCache=ue()(ce.a.document.activeElement).is("input,textarea,iframe,.cke_editable")),!!ce.a.document.activeElement.__inFocusCache}catch(e){}return!1}function S(e){if(ce.a.document&&ce.a.document.activeElement&&ce.a.document.activeElement.blur)try{var t=ue()(ce.a.document.activeElement);t&&t.is("input,textarea")?ce.a.document.activeElement.blur():e&&ce.a.document.activeElement.blur()}catch(e){}}function O(){try{if(ce.a&&ce.a.getSelection){var e=ce.a.getSelection();e&&e.removeAllRanges&&e.removeAllRanges()}else ce.a.document&&ce.a.document.selection&&ce.a.document.selection.empty&&ce.a.document.selection.empty()}catch(e){}}function w(e,t){e=Oe(e.toUpperCase()),t=Oe(t.replace(/[\s]+/g," "));var n=!1,o="RE"===e,i="FWD"===e,a=[],r=!i;return""!==t&&pe.a.each(t.split(":"),function(e){var t=Oe(e);n||!/^(RE|FWD)$/i.test(t)&&!/^(RE|FWD)[\[\(][\d]+[\]\)]$/i.test(t)?(a.push(e),n=!0):(o||(o=!!/^RE/i.test(t)),i||(i=!!/^FWD/i.test(t)))}),r?o=!1:i=!1,Oe((r?"Re: ":"Fwd: ")+(o?"Re: ":"")+(i?"Fwd: ":"")+Oe(a.join(":")))}function T(e,t){return ce.a.Math.round(e*ce.a.Math.pow(10,t))/ce.a.Math.pow(10,t)}function C(e){switch(e=r(e),!0){case 1073741824<=e:return T(e/1073741824,1)+"GB";case 1048576<=e:return T(e/1048576,1)+"MB";case 1024<=e:return T(e/1024,0)+"KB"}return e+"B"}function A(e){ce.a.console&&ce.a.console.log&&ce.a.console.log(e)}function E(e,t,n){var o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0;e&&e[t]&&(o=r(o),n=Te(n)?n:[],0>=o?e[t].apply(e,n):pe.a.delay(function(){e[t].apply(e,n)},o))}function F(e){if((e=e||ce.a.event)&&e.ctrlKey&&!e.shiftKey&&!e.altKey){var t=e.keyCode||e.which;if(t===ge.EventKeyCode.S)return void e.preventDefault();if(t===ge.EventKeyCode.A){var n=e.target||e.srcElement;if(n&&("true"==""+n.contentEditable||n.tagName&&n.tagName.match(/INPUT|TEXTAREA/i)))return;ce.a.getSelection?ce.a.getSelection().removeAllRanges():ce.a.document.selection&&ce.a.document.selection.clear&&ce.a.document.selection.clear(),e.preventDefault()}}}function j(e,t){var n=!(arguments.length>2&&void 0!==arguments[2])||arguments[2],o=null;return(o=t?function(){for(var n=arguments.length,i=Array(n),a=0;a1&&void 0!==arguments[1]&&arguments[1];return n(10).i18n("LANGS_NAMES"+(!0===t?"_EN":"")+"/LANG_"+e.toUpperCase().replace(/[^a-zA-Z0-9]+/g,"_"),null,e)}function _(){return ue()('
').appendTo("#rl-hidden")}function P(e,t){t&&!Ee(t.disabled)&&e&&ue()(e).toggleClass("disabled",t.disabled).prop("disabled",t.disabled)}function D(e){e.find("blockquote.rl-bq-switcher").removeClass("rl-bq-switcher hidden-bq"),e.find(".rlBlockquoteSwitcher").off(".rlBlockquoteSwitcher").remove(),e.find("[data-html-editor-font-wrapper]").removeAttr("data-html-editor-font-wrapper")}function M(e,t,o,i){var a=e.title,r=e.subject,s=e.date,c=e.fromCreds,l=e.toCreds,u=e.toLabel,d=e.ccClass,p=e.ccCreds,h=e.ccLabel,f=ce.a.open(""),m=f.document,b=t.clone(),y=o?"html":"plain";D(b);var v=b?b.html():"";m.write(n(170).replace("{{title}}",g(a)).replace("{{subject}}",g(r)).replace("{{date}}",g(s)).replace("{{fromCreds}}",g(c)).replace("{{toCreds}}",g(l)).replace("{{toLabel}}",g(u)).replace("{{ccClass}}",g(d)).replace("{{ccCreds}}",g(p)).replace("{{ccLabel}}",g(h)).replace("{{bodyClass}}",y).replace("{{html}}",v)),m.close(),i&&ce.a.setTimeout(function(){return f.print()},100)}function k(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:1e3;return o=r(o),function(i,a,r,s,c){t.call(n,a&&a.Result?ge.SaveSettingsStep.TrueResult:ge.SaveSettingsStep.FalseResult),e&&e.call(n,i,a,r,s,c),pe.a.delay(function(){t.call(n,ge.SaveSettingsStep.Idle)},o)}}function x(e,t){return k(null,e,t,1e3)}function U(e,t,n,o){return function(i){if(e){switch(n){case"bool":case"boolean":i=i?"1":"0";break;case"int":case"integer":case"number":i=r(i);break;case"trim":i=Oe(i);break;default:i=s(i)}var a={};a[t]=i,e.saveAdminConfig?e.saveAdminConfig(o||null,a):e.saveSettings&&e.saveSettings(o||null,a)}}}function H(e){return me.a?me.a.link(e,{newWindow:!0,stripPrefix:!1,urls:!0,email:!0,mention:!1,phone:!1,hashtag:!1,replaceFn:function(e){return!(e&&"url"===e.getType()&&e.matchedText&&0!==e.matchedText.indexOf("http"))}}):e}function B(e){var t,n=0,o=0,i=0,a=0,r=0,s="";for(s=e.replace(/]*><\/p>/gi,"").replace(/
]*>([\s\S\r\n\t]*)<\/pre>/gim,function(){for(var e=arguments.length,t=Array(e),n=0;n ").replace(/[\r]/gm,""):""}).replace(/[\s]+/gm," ").replace(/((?:href|data)\s?=\s?)("[^"]+?"|'[^']+?')/gim,function(){for(var e=arguments.length,t=Array(e),n=0;n]*>/gim,"\n").replace(/<\/h[\d]>/gi,"\n").replace(/<\/p>/gi,"\n\n").replace(/]*>/gim,"\n").replace(/<\/ul>/gi,"\n").replace(/]*>/gim," * ").replace(/<\/li>/gi,"\n").replace(/<\/td>/gi,"\n").replace(/<\/tr>/gi,"\n").replace(/ ]*>/gim,"\n_______________________________\n\n").replace(/]*>([\s\S\r\n]*)<\/div>/gim,function e(){for(var t=arguments.length,n=Array(t),o=0;o
]*>([\s\S\r\n]*)<\/div>/gim,e),i="\n"+Oe(i)+"\n"),i}return""}).replace(/]*>/gim,"\n__bq__start__\n").replace(/<\/blockquote>/gim,"\n__bq__end__\n").replace(/]*>([\s\S\r\n]*?)<\/a>/gim,function(){for(var e=arguments.length,t=Array(e),n=0;n/gi,"\n").replace(/ /gi," ").replace(/"/gi,'"').replace(/<[^>]*>/gm,""),s=y(s=(s=be.$div.html(s).text()).replace(/\n[ \t]+/gm,"\n").replace(/[\n]{3,}/gm,"\n\n").replace(/>/gi,">").replace(/</gi,"<").replace(/&/gi,"&")),n=0,o=800;0 "+Oe(t).replace(/\n/gm,"\n> ")).replace(/(^|\n)([> ]+)/gm,function(){for(var e=arguments.length,t=Array(e),n=0;n1&&void 0!==arguments[1]&&arguments[1],n=!1,o=!0,i=!0,a=[],r="",s=0,c=(e=(e=e.toString().replace(/\r/g,"")).replace(/^>[> ]>+/gm,function(e){var t=e[0];return t?t.replace(/[ ]+/g,""):t})).split("\n");do{for(o=!1,a=[],s=0;s"===(r=c[s]).substr(0,1))&&!n?(o=!0,n=!0,a.push("~~~blockquote~~~"),a.push(r.substr(1))):!i&&n?""!==r?(n=!1,a.push("~~~/blockquote~~~"),a.push(r)):a.push(r):i&&n?a.push(r.substr(1)):a.push(r);n&&(n=!1,a.push("~~~/blockquote~~~")),c=a}while(o);return e=(e=c.join("\n")).replace(/&/g,"&").replace(/>/g,">").replace(/").replace(/[\s]*~~~\/blockquote~~~/g," ").replace(/\n/g," "),t?H(e):e}function K(e,t,n,o,a,r,s,c,l,u){var d=null,p=!1,h=0,f=0,m=[];for(u=!Ee(u)&&!!u,l=i(l)?l:00&&void 0!==arguments[0]&&arguments[0]?pe.a.delay(e,100):e()}function q(e){ke[e]||(ke[e]=ue()('script[type="application/json"][data-configuration="'+e+'"]'));try{return JSON.parse(ke[e].text())}catch(e){}return{}}function W(e,t){var n=t||e;n&&"function"==typeof n.dispose&&n.dispose()}function Y(e){e&&(Te(e.disposables)&&pe.a.each(e.disposables,W),he.a.utils.objectForEach(e,W))}function $(e){e&&(Te(e)?pe.a.each(e,function(e){$(e)}):e&&e.onDestroy&&e.onDestroy())}function J(e,t){return!(!e||!e[0]||(e[0].styleSheet&&!Ee(e[0].styleSheet.cssText)?e[0].styleSheet.cssText=t:e.text(t),0))}function X(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:Re,n=ue()("#app-theme-link"),o=function(){xe=ce.a.setTimeout(function(){return t(ge.SaveSettingsStep.Idle)},1e3),Ue=null},i=ue()("#app-theme-style"),a=n.attr("href");a||(a=i.attr("data-href")),a&&("Json/"!==(a=(a=(a=a.toString().replace(/\/-\/[^\/]+\/\-\//,"/-/"+e+"/-/")).replace(/\/Css\/[^\/]+\/User\//,"/Css/0/User/")).replace(/\/Hash\/[^\/]+\//,"/Hash/-/")).substring(a.length-5,a.length)&&(a+="Json/"),ce.a.clearTimeout(xe),t(ge.SaveSettingsStep.Animate),Ue&&Ue.abort&&Ue.abort(),Ue=ue.a.ajax({url:a,dataType:"json"}).then(function(e){e&&Te(e)&&2===e.length&&(!n||!n[0]||i&&i[0]||(i=ue()(''),n.after(i),n.remove()),i&&i[0]&&J(i,e[1])&&i.attr("data-href",a).attr("data-theme",e[0]),t(ge.SaveSettingsStep.TrueResult))}).then(o,o))}function Z(e,t){return function(){var n=e(),o=t(),i=[],a=function(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",a={current:e===n,name:""===o?e.toString():o.toString(),custom:""!==o,title:""===o?"":e.toString(),value:e.toString()};t?i.push(a):i.unshift(a)},r=0,s=0,c=2;if(1=n||o-2<=n)&&(c+=2),a(n),r=n,s=n);0=s)a(s,!0),c-=1;else if(0>=r)break;3===r?a(2,!1):3s&&a(Math.round((o+s)/2),!0,"..."),1s&&a(o,!0)}return i}}function Q(e){var t=(e=Oe(e).toLowerCase()).split(".").pop();return t===e?"":t}function ee(e){var t,n="application/octet-stream";return"winmail.dat"===(e=Oe(e).toLowerCase())?"application/ms-tnef":((t=Q(e))&&0this.height?[this.width-this.height,0]:[0,this.height-this.width],i.fillStyle="#fff",i.fillRect(0,0,t,t),i.drawImage(this,e[0]/2,e[1]/2,this.width-e[0],this.height-e[1],0,0,t,t),n(o.toDataURL("image/jpeg"))},o.src=e}function ie(e,t){if(e&&"mailto:"===e.toString().substr(0,7).toLowerCase()){if(!t)return!0;var o,i=[],a=null,r=null,c=(e=e.toString().substr(7)).replace(/\?.+$/,""),l=e.replace(/^[^\?]*\?/,""),u=n(44).default;return o=m(l),Ee(o.to)?i=u.parseEmailLine(c):(i=u.parseEmailLine(p(c+","+o.to)),i=pe.a.values(i.reduce(function(e,t){return t&&(e[t.email]&&e[t.email].name||(e[t.email]=t)),e},{}))),Ee(o.cc)||(a=u.parseEmailLine(p(o.cc))),Ee(o.bcc)||(r=u.parseEmailLine(p(o.bcc))),n(9).showScreenPopup(t,[ge.ComposeType.Empty,null,i,a,r,Ee(o.subject)?null:s(p(o.subject)),Ee(o.body)?null:G(s(p(o.body)))]),!0}return!1}function ae(e){ue()(function(){return e()})}function re(){He()}n.r(t);var se=n(3),ce=n.n(se),le=n(7),ue=n.n(le),de=n(4),pe=n.n(de),he=n(1),fe=n(96),me=n.n(fe),be=n(6),ge=n(0),ye={eml:"message/rfc822",mime:"message/rfc822",txt:"text/plain",text:"text/plain",def:"text/plain",list:"text/plain",in:"text/plain",ini:"text/plain",log:"text/plain",sql:"text/plain",cfg:"text/plain",conf:"text/plain",asc:"text/plain",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:"application/json",swf:"application/x-shockwave-flash",hlp:"application/winhlp",wgt:"application/widget",chm:"application/vnd.ms-htmlhelp",p10:"application/pkcs10",p7c:"application/pkcs7-mime",p7m:"application/pkcs7-mime",p7s:"application/pkcs7-signature",torrent:"application/x-bittorrent",js:"application/javascript",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",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",jpe:"image/jpeg",jfif:"image/jpeg",gif:"image/gif",bmp:"image/bmp",cgm:"image/cgm",ief:"image/ief",ico:"image/x-icon",tif:"image/tiff",tiff:"image/tiff",svg:"image/svg+xml",svgz:"image/svg+xml",djv:"image/vnd.djvu",djvu:"image/vnd.djvu",webp:"image/webp",zip:"application/zip","7z":"application/x-7z-compressed",rar:"application/x-rar-compressed",exe:"application/x-msdownload",dll:"application/x-msdownload",scr:"application/x-msdownload",com:"application/x-msdownload",bat:"application/x-msdownload",msi:"application/x-msdownload",cab:"application/vnd.ms-cab-compressed",gz:"application/x-gzip",tgz:"application/x-gzip",bz:"application/x-bzip",bz2:"application/x-bzip2",deb:"application/x-debian-package",psf:"application/x-font-linux-psf",otf:"application/x-font-otf",pcf:"application/x-font-pcf",snf:"application/x-font-snf",ttf:"application/x-font-ttf",ttc:"application/x-font-ttf",mp3:"audio/mpeg",amr:"audio/amr",aac:"audio/x-aac",aif:"audio/x-aiff",aifc:"audio/x-aiff",aiff:"audio/x-aiff",wav:"audio/x-wav",wma:"audio/x-ms-wma",wax:"audio/x-ms-wax",midi:"audio/midi",mp4a:"audio/mp4",ogg:"audio/ogg",weba:"audio/webm",ra:"audio/x-pn-realaudio",ram:"audio/x-pn-realaudio",rmp:"audio/x-pn-realaudio-plugin",m3u:"audio/x-mpegurl",flv:"video/x-flv",qt:"video/quicktime",mov:"video/quicktime",wmv:"video/windows-media",avi:"video/x-msvideo",mpg:"video/mpeg",mpeg:"video/mpeg",mpe:"video/mpeg",m1v:"video/mpeg",m2v:"video/mpeg","3gp":"video/3gpp","3g2":"video/3gpp2",h261:"video/h261",h263:"video/h263",h264:"video/h264",jpgv:"video/jpgv",mp4:"video/mp4",mp4v:"video/mp4",mpg4:"video/mp4",ogv:"video/ogg",webm:"video/webm",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",pdf:"application/pdf",psd:"image/vnd.adobe.photoshop",ai:"application/postscript",eps:"application/postscript",ps:"application/postscript",doc:"application/msword",dot:"application/msword",rtf:"application/rtf",xls:"application/vnd.ms-excel",ppt:"application/vnd.ms-powerpoint",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",dotx:"application/vnd.openxmlformats-officedocument.wordprocessingml.template",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",odt:"application/vnd.oasis.opendocument.text",ods:"application/vnd.oasis.opendocument.spreadsheet"},ve=n(59);n.d(t,"trim",function(){return Oe}),n.d(t,"inArray",function(){return we}),n.d(t,"isArray",function(){return Te}),n.d(t,"isObject",function(){return Ce}),n.d(t,"isFunc",function(){return Ae}),n.d(t,"isUnd",function(){return Ee}),n.d(t,"isNull",function(){return Fe}),n.d(t,"has",function(){return je}),n.d(t,"bind",function(){return Ne}),n.d(t,"noop",function(){return Re}),n.d(t,"noopTrue",function(){return Ie}),n.d(t,"noopFalse",function(){return Le}),n.d(t,"silentTryCatch",function(){return o}),n.d(t,"isNormal",function(){return i}),n.d(t,"isPosNumeric",function(){return a}),n.d(t,"pInt",function(){return r}),n.d(t,"pString",function(){return s}),n.d(t,"pBool",function(){return c}),n.d(t,"boolToAjax",function(){return l}),n.d(t,"isNonEmptyArray",function(){return u}),n.d(t,"encodeURIComponent",function(){return d}),n.d(t,"decodeURIComponent",function(){return p}),n.d(t,"decodeURI",function(){return h}),n.d(t,"encodeURI",function(){return f}),n.d(t,"simpleQueryParser",function(){return m}),n.d(t,"fakeMd5",function(){return b}),n.d(t,"encodeHtml",function(){return g}),n.d(t,"splitPlainText",function(){return y}),n.d(t,"timeOutAction",function(){return _e}),n.d(t,"timeOutActionSecond",function(){return Pe}),n.d(t,"inFocus",function(){return v}),n.d(t,"removeInFocus",function(){return S}),n.d(t,"removeSelection",function(){return O}),n.d(t,"replySubjectAdd",function(){return w}),n.d(t,"roundNumber",function(){return T}),n.d(t,"friendlySize",function(){return C}),n.d(t,"log",function(){return A}),n.d(t,"delegateRun",function(){return E}),n.d(t,"killCtrlACtrlS",function(){return F}),n.d(t,"createCommandLegacy",function(){return j}),n.d(t,"convertThemeName",function(){return De}),n.d(t,"quoteName",function(){return N}),n.d(t,"microtime",function(){return R}),n.d(t,"timestamp",function(){return I}),n.d(t,"convertLangName",function(){return L}),n.d(t,"draggablePlace",function(){return _}),n.d(t,"defautOptionsAfterRender",function(){return P}),n.d(t,"clearBqSwitcher",function(){return D}),n.d(t,"previewMessage",function(){return M}),n.d(t,"settingsSaveHelperFunction",function(){return k}),n.d(t,"settingsSaveHelperSimpleFunction",function(){return x}),n.d(t,"settingsSaveHelperSubscribeFunction",function(){return U}),n.d(t,"findEmailAndLinks",function(){return H}),n.d(t,"htmlToPlain",function(){return B}),n.d(t,"plainToHtml",function(){return G}),n.d(t,"folderListOptionsBuilder",function(){return K}),n.d(t,"selectElement",function(){return V}),n.d(t,"detectDropdownVisibility",function(){return Me}),n.d(t,"triggerAutocompleteInputChange",function(){return z}),n.d(t,"getConfigurationFromScriptTag",function(){return q}),n.d(t,"disposeOne",function(){return W}),n.d(t,"disposeObject",function(){return Y}),n.d(t,"delegateRunOnDestroy",function(){return $}),n.d(t,"appendStyles",function(){return J}),n.d(t,"changeTheme",function(){return X}),n.d(t,"computedPagenatorHelper",function(){return Z}),n.d(t,"getFileExtension",function(){return Q}),n.d(t,"mimeContentType",function(){return ee}),n.d(t,"isTransparent",function(){return te}),n.d(t,"getRealHeight",function(){return ne}),n.d(t,"resizeAndCrop",function(){return oe}),n.d(t,"mailToHelper",function(){return ie}),n.d(t,"domReady",function(){return ae}),n.d(t,"windowResize",function(){return He}),n.d(t,"windowResizeCallback",function(){return re}),n.d(t,"jassl",function(){return ve.a});var Se,Oe=ue.a.trim,we=ue.a.inArray,Te=pe.a.isArray,Ce=pe.a.isObject,Ae=pe.a.isFunction,Ee=pe.a.isUndefined,Fe=pe.a.isNull,je=pe.a.has,Ne=pe.a.bind,Re=function(){},Ie=function(){return!0},Le=function(){return!1},_e=(Se={},function(e,t,n){Se[e]=Ee(Se[e])?0:Se[e],ce.a.clearTimeout(Se[e]),Se[e]=ce.a.setTimeout(t,n)}),Pe=function(){var e={};return function(t,n,o){e[t]||(e[t]=ce.a.setTimeout(function(){n(),e[t]=0},o))}}(),De=pe.a.memoize(function(e){return"@custom"===e.substr(-7)&&(e=Oe(e.substring(0,e.length-7))),Oe(e.replace(/[^a-zA-Z0-9]+/g," ").replace(/([A-Z])/g," $1").replace(/[\s]+/g," "))});ce.a.rainloop_Utils_htmlToPlain=B,ce.a.rainloop_Utils_plainToHtml=G;var Me=pe.a.debounce(function(){Object(be.dropdownVisibility)(!!pe.a.find(be.data.aBootstrapDropdowns,function(e){return e.hasClass("open")}))},50),ke={},xe=0,Ue=null,He=pe.a.debounce(function(e){Ee(e)||Fe(e)?be.$win.resize():ce.a.setTimeout(function(){be.$win.resize()},e)},50),Be=ce.a.String.substr;"b"!=="ab".substr(-1)&&(Be=function(e,t,n){return t=0>t?e.length+t:t,e.substr(t,n)},ce.a.String.substr=Be)},function(e,t){e.exports=window},function(e,t){e.exports=window._},function(e,t,n){"use strict";function o(e){return Object(l.isUnd)(u[e])?null:u[e]}function i(e,t){u[e]=t}function a(e){return Object(l.isUnd)(d[e])?null:d[e]}function r(e){var t=o("Capa");return Object(l.isArray)(t)&&Object(l.isNormal)(e)&&-1 "),y=c()("
");y.attr("area","hidden").css({position:"absolute",left:-5e3}).appendTo(b);var v=(new i.a.Date).getTime(),S=!0,O=d.a.observable(!1).extend({rateLimit:0}),w=d.a.observable(!0),T="navigator"in i.a&&"userAgent"in i.a.navigator&&i.a.navigator.userAgent.toLowerCase()||"",C=-11&&void 0!==arguments[1])||arguments[1];return Object(k.createCommandLegacy)(null,e,t)}function a(e,t,n,o){var i=arguments.length>4&&void 0!==arguments[4]&&arguments[4];e.__rlSettingsData={Label:n,Template:t,Route:o,IsDefault:!!i},M.VIEW_MODELS.settings.push(e)}function r(e){M.VIEW_MODELS["settings-removed"].push(e)}function s(e){M.VIEW_MODELS["settings-disabled"].push(e)}function c(){I.a.changed.active=!1}function l(){I.a.changed.active=!0}function u(e){return""===e||Object(k.isUnd)(H[e])?null:H[e]}function d(e){var t=null;return e&&(t=e,e.default&&(t=e.default)),t}function p(e){var t=d(e);t&&t.__vm&&t.__dom&&t.__vm.modalVisibility(!1)}function h(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;E.a.each(t.__names,function(o){Object(D.f)(e,[o,t.__vm,n])})}function f(e,t){if(e&&!e.__builded){var n=null,o=new e(t),a=e.__type||"",r=a?j()("#rl-content #rl-"+a.toLowerCase()):null;e.__builded=!0,e.__vm=o,o.onShowTrigger=N.a.observable(!1),o.onHideTrigger=N.a.observable(!1),o.viewModelName=e.__name,o.viewModelNames=e.__names,o.viewModelTemplateID=e.__templateID,o.viewModelPosition=e.__type,r&&1===r.length?((n=j()("
").addClass("rl-view-model").addClass("RL-"+o.viewModelTemplateID).hide()).appendTo(r),o.viewModelDom=n,e.__dom=n,B.Popup===a&&(o.cancelCommand=o.closeCommand=i(function(){p(e)}),o.modalVisibility.subscribe(function(t){t?(o.viewModelDom.show(),o.storeAndSetKeyScope(),M.popupVisibilityNames.push(o.viewModelName),o.viewModelDom.css("z-index",3e3+Object(M.popupVisibilityNames)().length+10),o.onShowTrigger&&o.onShowTrigger(!o.onShowTrigger()),Object(k.delegateRun)(o,"onShowWithDelay",[],500)):(Object(k.delegateRun)(o,"onHide"),Object(k.delegateRun)(o,"onHideWithDelay",[],500),o.onHideTrigger&&o.onHideTrigger(!o.onHideTrigger()),o.restoreKeyScope(),h("view-model-on-hide",e),M.popupVisibilityNames.remove(o.viewModelName),o.viewModelDom.css("z-index",2e3),E.a.delay(function(){return o.viewModelDom.hide()},300))})),h("view-model-pre-build",e,n),N.a.applyBindingAccessorsToNode(n[0],{translatorInit:!0,template:function(){return{name:o.viewModelTemplateID}}},o),Object(k.delegateRun)(o,"onBuild",[n]),o&&B.Popup===a&&o.registerPopupKeyDown(),h("view-model-post-build",e,n)):Object(k.log)("Cannot find view model position: "+a)}return e?e.__vm:null}function m(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=d(e);n&&(f(n),n.__vm&&n.__dom&&(Object(k.delegateRun)(n.__vm,"onBeforeShow",t||[]),n.__vm.modalVisibility(!0),Object(k.delegateRun)(n.__vm,"onShow",t||[]),h("view-model-on-show",n,t||[])))}function b(e){var t=d(e);t&&(f(t),t.__vm&&t.__dom&&Object(k.delegateRun)(t.__vm,"onWarmUp"))}function g(e){var t=d(e);return!(!t||!t.__vm)&&t.__vm.modalVisibility()}function y(e,t){var n=null,o=!1,i=null;""===Object(k.pString)(e)&&(e=U),""!==e&&((n=u(e))||(n=u(U))&&(t=e+"/"+t,e=U),n&&n.__started&&(o=x&&n===x,n.__builded||(n.__builded=!0,Object(k.isNonEmptyArray)(n.viewModels())&&E.a.each(n.viewModels(),function(e){f(e,n)}),Object(k.delegateRun)(n,"onBuild")),E.a.defer(function(){x&&!o&&(Object(k.delegateRun)(x,"onHide"),Object(k.delegateRun)(x,"onHideWithDelay",[],500),x.onHideTrigger&&x.onHideTrigger(!x.onHideTrigger()),Object(k.isNonEmptyArray)(x.viewModels())&&E.a.each(x.viewModels(),function(e){e.__vm&&e.__dom&&B.Popup!==e.__vm.viewModelPosition&&(e.__dom.hide(),e.__vm.viewModelVisibility(!1),Object(k.delegateRun)(e.__vm,"onHide"),Object(k.delegateRun)(e.__vm,"onHideWithDelay",[],500),e.__vm.onHideTrigger&&e.__vm.onHideTrigger(!e.__vm.onHideTrigger()))})),(x=n)&&!o&&(Object(k.delegateRun)(x,"onShow"),x.onShowTrigger&&x.onShowTrigger(!x.onShowTrigger()),Object(D.f)("screen-on-show",[x.screenName(),x]),Object(k.isNonEmptyArray)(x.viewModels())&&E.a.each(x.viewModels(),function(e){e.__vm&&e.__dom&&B.Popup!==e.__vm.viewModelPosition&&(Object(k.delegateRun)(e.__vm,"onBeforeShow"),e.__dom.show(),e.__vm.viewModelVisibility(!0),Object(k.delegateRun)(e.__vm,"onShow"),e.__vm.onShowTrigger&&e.__vm.onShowTrigger(!e.__vm.onShowTrigger()),Object(k.delegateRun)(e.__vm,"onShowWithDelay",[],200),h("view-model-on-show",e))})),(i=n&&n.__cross?n.__cross():null)&&i.parse(t)})))}function v(e){E.a.each(e,function(e){if(e){var t=new e,n=t?t.screenName():"";t&&""!==n&&(""===U&&(U=n),H[n]=t)}}),E.a.each(H,function(e){e&&!e.__started&&e.__start&&(e.__started=!0,e.__start(),Object(D.f)("screen-pre-start",[e.screenName(),e]),Object(k.delegateRun)(e,"onStart"),Object(D.f)("screen-post-start",[e.screenName(),e]))});var t=_.a.create();t.addRoute(/^([a-zA-Z0-9\-]*)\/?(.*)$/,y),I.a.initialized.add(t.parse,t),I.a.changed.add(t.parse,t),I.a.init(),E.a.delay(function(){return M.$html.removeClass("rl-started-trigger").addClass("rl-started")},100),E.a.delay(function(){return M.$html.addClass("rl-started-delay")},200)}function S(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];e="/"===(e="#"===e.substr(0,1)?e.substr(1):e).substr(0,1)?e.substr(1):e;var o=n?"replaceHash":"setHash";t?(I.a.changed.active=!1,I.a[o](e),I.a.changed.active=!0):(I.a.changed.active=!0,I.a[o](e),I.a.setHash(e))}function O(e){var t=e.name,n=e.type,o=e.templateID;return function(e){e&&(t&&(Object(k.isArray)(t)?e.__names=t:e.__names=[t],e.__name=e.__names[0]),n&&(e.__type=n),o&&(e.__templateID=o))}}function w(e){var t=e.name,n=e.templateID;return O({name:t,type:B.Popup,templateID:n})}function T(){var e=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];return function(t,n,o){if(!n||!n.match(/Command$/))throw new Error('name "'+n+'" should end with Command suffix');var i=o.value||o.initializer(),a=Object(k.isFunc)(e)?e:function(){return!!e};return o.value=function(){if(a.call(this,this)){for(var e=arguments.length,t=Array(e),n=0;n1&&void 0!==arguments[1]&&arguments[1];f.a.defer(function(){b()("[data-i18n]",e).each(function(e,t){F(t)}),t&&S.bAnimationSupported&&b()(".i18n-animation[data-i18n]",e).letterfx({fx:"fall fade",backwards:!1,timing:50,fx_duration:"50ms",letter_end:"restore",element_end:"restore"})})}function a(){A.forEach(function(e){C[e[0]]=o(e[1])})}function r(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;e&&e(),t?E.subscribe(function(){e&&e(),t&&t()}):e&&E.subscribe(e)}function s(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;return e=p.a.parseInt(e,10)||0,y.Notification.ClientViewError===e&&t?t:(n=n&&p.a.parseInt(n,10)||0,Object(v.isUnd)(C[e])?n&&Object(v.isUnd)(C[n])?C[n]:"":C[e])}function c(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:y.Notification.UnknownNotification;return e&&e.ErrorCode?s(Object(v.pInt)(e.ErrorCode),e.ErrorMessage||""):s(t)}function l(e){var t="";switch(p.a.parseInt(e,10)||0){case y.UploadErrorCode.FileIsTooBig:t=o("UPLOAD/ERROR_FILE_IS_TOO_BIG");break;case y.UploadErrorCode.FilePartiallyUploaded:t=o("UPLOAD/ERROR_FILE_PARTIALLY_UPLOADED");break;case y.UploadErrorCode.FileNoUploaded:t=o("UPLOAD/ERROR_NO_FILE_UPLOADED");break;case y.UploadErrorCode.MissingTempFolder:t=o("UPLOAD/ERROR_MISSING_TEMP_FOLDER");break;case y.UploadErrorCode.FileOnSaveingError:t=o("UPLOAD/ERROR_ON_SAVING_FILE");break;case y.UploadErrorCode.FileType:t=o("UPLOAD/ERROR_FILE_TYPE");break;default:t=o("UPLOAD/ERROR_UNKNOWN")}return t}function u(e,t){var n=Object(v.microtime)();return S.$html.addClass("rl-changing-language"),new p.a.Promise(function(o,i){b.a.ajax({url:Object(w.n)(t,e),dataType:"script",cache:!0}).then(function(){f.a.delay(function(){j();var e=-1t.interval&&(t.isSystemFolder()||t.subScribed()&&t.checkable())&&o.push([t.interval,t.fullNameRaw]),t&&0t[0]?1:0}),s.a.find(o,function(n){var o=Object(p.e)(n[1]);return o&&(o.interval=t,e.push(n[1])),5<=e.length}),s.a.uniq(e)},e}();t.a=new f},function(e,t,n){"use strict";function o(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],o=0,i=0,a=[];if(Object(g.isNonEmptyArray)(e))for(i=e.length;o1&&void 0!==arguments[1]&&arguments[1];return o(this.from,e,t)},t.prototype.fromDkimData=function(){var e=["none",""];return Object(g.isNonEmptyArray)(this.from)&&1===this.from.length&&this.from[0]&&this.from[0].dkimStatus&&(e=[this.from[0].dkimStatus,this.from[0].dkimValue||""]),e},t.prototype.toToLine=function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return o(this.to,e,t)},t.prototype.ccToLine=function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return o(this.cc,e,t)},t.prototype.bccToLine=function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return o(this.bcc,e,t)},t.prototype.replyToToLine=function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return o(this.replyTo,e,t)},t.prototype.lineAsCss=function(){return L()({deleted:this.deleted(),"deleted-mark":this.deletedMark(),selected:this.selected(),checked:this.checked(),flagged:this.flagged(),unseen:this.unseen(),answered:this.answered(),forwarded:this.forwarded(),focused:this.focused(),important:this.isImportant(),withAttachments:this.hasAttachments(),new:this.newForAnimation(),emptySubject:""===this.subject(),hasUnseenSubMessage:this.hasUnseenSubMessage(),hasFlaggedSubMessage:this.hasFlaggedSubMessage()})},t.prototype.hasVisibleAttachments=function(){return!!p.a.find(this.attachments(),function(e){return!e.isLinked})},t.prototype.findAttachmentByCid=function(e){var t=null,n=this.attachments();return Object(g.isNonEmptyArray)(n)&&(e=e.replace(/^<+/,"").replace(/>+$/,""),t=p.a.find(n,function(t){return e===t.cidWithOutTags})),t||null},t.prototype.findAttachmentByContentLocation=function(e){var t=null,n=this.attachments();return Object(g.isNonEmptyArray)(n)&&(t=p.a.find(n,function(t){return e===t.contentLocation})),t||null},t.prototype.messageId=function(){return this.sMessageId},t.prototype.inReplyTo=function(){return this.sInReplyTo},t.prototype.references=function(){return this.sReferences},t.prototype.fromAsSingleEmail=function(){return Object(g.isArray)(this.from)&&this.from[0]?this.from[0].email:""},t.prototype.viewLink=function(){return Object(O.q)(this.requestHash)},t.prototype.downloadLink=function(){return Object(O.p)(this.requestHash)},t.prototype.replyEmails=function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=[],o=Object(g.isUnd)(e)?{}:e;return r(this.replyTo,o,n),0===n.length&&r(this.from,o,n),0!==n.length||t?n:this.replyEmails({},!0)},t.prototype.replyAllEmails=function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=[],o=[],i=Object(g.isUnd)(e)?{}:e;return r(this.replyTo,i,n),0===n.length&&r(this.from,i,n),r(this.to,i,n),r(this.cc,i,o),0!==n.length||t?[n,o]:[this.replyAllEmails({},!0)[0],o]},t.prototype.textBodyToString=function(){return this.body?this.body.html():""},t.prototype.attachmentsToStringLine=function(){var e=p.a.map(this.attachments(),function(e){return e.fileName+" ("+e.friendlySize+")"});return e&&00&&void 0!==arguments[0]&&arguments[0];this.showLazyExternalImagesInBody();var t=this.dateTimeStampInUTC()||0,n=this.ccToLine(!1),o=00&&void 0!==arguments[0]&&arguments[0];if(this.body&&this.body.data("rl-has-images")){this.hasImages(!1),this.body.data("rl-has-images",!1);var t=this.proxy?"data-x-additional-src":"data-x-src";m()("["+t+"]",this.body).each(function(){var n=m()(this);e&&n.is("img")?n.addClass("lazy").attr("data-original",n.attr(t)).removeAttr("data-loaded"):n.attr("src",n.attr(t)).removeAttr("data-loaded")}),t=this.proxy?"data-x-additional-style-url":"data-x-style-url",m()("["+t+"]",this.body).each(function(){var e=m()(this),n=Object(g.trim)(e.attr("style"));n=""===n?"":";"===n.substr(-1)?n+" ":n+"; ",e.attr("style",n+e.attr(t))}),e&&(this.lozad(),S.$win.resize()),Object(g.windowResize)(500)}},t.prototype.showInternalImages=function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];if(this.body&&!this.body.data("rl-init-internal-images")){this.body.data("rl-init-internal-images",!0);var n=this;m()("[data-x-src-cid]",this.body).each(function(){var e=m()(this),o=n.findAttachmentByCid(e.attr("data-x-src-cid"));o&&o.download&&(t&&e.is("img")?e.addClass("lazy").attr("data-original",o.linkPreview()):e.attr("src",o.linkPreview()))}),m()("[data-x-src-location]",this.body).each(function(){var e=m()(this),o=n.findAttachmentByContentLocation(e.attr("data-x-src-location"));o||(o=n.findAttachmentByCid(e.attr("data-x-src-location"))),o&&o.download&&(t&&e.is("img")?e.addClass("lazy").attr("data-original",o.linkPreview()):e.attr("src",o.linkPreview()))}),m()("[data-x-style-cid]",this.body).each(function(){var e="",t="",o=m()(this),i=n.findAttachmentByCid(o.attr("data-x-style-cid"));i&&i.linkPreview&&""!==(t=o.attr("data-x-style-cid-name"))&&(e=""===(e=Object(g.trim)(o.attr("style")))?"":";"===e.substr(-1)?e+" ":e+"; ",o.attr("style",e+t+": url('"+i.linkPreview()+"')"))}),t&&p.a.delay(function(){return e.lozad()},300),Object(g.windowResize)(500)}},t.prototype.storeDataInDom=function(){this.body&&(this.body.data("rl-is-html",!!this.isHtml()),this.body.data("rl-has-images",!!this.hasImages()))},t.prototype.fetchDataFromDom=function(){this.body&&(this.isHtml(!!this.body.data("rl-is-html")),this.hasImages(!!this.body.data("rl-has-images")))},t.prototype.replacePlaneTextBody=function(e){this.body&&this.body.html(e).addClass("b-text-part plain")},t.prototype.flagHash=function(){return[this.deleted(),this.deletedMark(),this.unseen(),this.flagged(),this.answered(),this.forwarded(),this.isReadReceipt()].join(",")},t}(n(36).a),U=n(9),H=n(26),B=n(31),G=n(28),K=n(62),V=n(20),z=n(17),q=function(){function e(){c()(this,e),this.staticMessage=new x,this.messageList=h.a.observableArray([]).extend({rateLimit:0}),this.messageListCount=h.a.observable(0),this.messageListSearch=h.a.observable(""),this.messageListThreadUid=h.a.observable(""),this.messageListPage=h.a.observable(1),this.messageListPageBeforeThread=h.a.observable(1),this.messageListError=h.a.observable(""),this.messageListEndFolder=h.a.observable(""),this.messageListEndSearch=h.a.observable(""),this.messageListEndThreadUid=h.a.observable(""),this.messageListEndPage=h.a.observable(1),this.messageListLoading=h.a.observable(!1),this.messageListIsNotCompleted=h.a.observable(!1),this.messageListCompleteLoadingThrottle=h.a.observable(!1).extend({throttle:200}),this.messageListCompleteLoadingThrottleForAnimation=h.a.observable(!1).extend({specialThrottle:700}),this.messageListDisableAutoSelect=h.a.observable(!1).extend({falseTimeout:500}),this.selectorMessageSelected=h.a.observable(null),this.selectorMessageFocused=h.a.observable(null),this.message=h.a.observable(null),this.message.viewTrigger=h.a.observable(!1),this.messageError=h.a.observable(""),this.messageCurrentLoading=h.a.observable(!1),this.messageLoadingThrottle=h.a.observable(!1).extend({throttle:b.Magics.Time50ms}),this.messageFullScreenMode=h.a.observable(!1),this.messagesBodiesDom=h.a.observable(null),this.messageActiveDom=h.a.observable(null),this.computers(),this.subscribers(),this.onMessageResponse=p.a.bind(this.onMessageResponse,this),this.purgeMessageBodyCacheThrottle=p.a.throttle(this.purgeMessageBodyCache,b.Magics.Time30s)}return e.prototype.computers=function(){var e=this;this.messageLoading=h.a.computed(function(){return e.messageCurrentLoading()}),this.messageListEndHash=h.a.computed(function(){return e.messageListEndFolder()+"|"+e.messageListEndSearch()+"|"+e.messageListEndThreadUid()+"|"+e.messageListEndPage()}),this.messageListPageCount=h.a.computed(function(){var t=u.a.Math.ceil(e.messageListCount()/G.a.messagesPerPage());return 0>=t?1:t}),this.mainMessageListSearch=h.a.computed({read:this.messageListSearch,write:function(t){Object(U.setHash)(Object(O.o)(D.a.currentFolderFullNameHash(),1,Object(g.trim)(t.toString()),e.messageListThreadUid()))}}),this.messageListCompleteLoading=h.a.computed(function(){var t=e.messageListLoading(),n=e.messageListIsNotCompleted();return t||n}),this.isMessageSelected=h.a.computed(function(){return null!==e.message()}),this.messageListChecked=h.a.computed(function(){return p.a.filter(e.messageList(),function(e){return e.checked()})}).extend({rateLimit:0}),this.hasCheckedMessages=h.a.computed(function(){return 0n.data("rl-cache-count")&&(n.addClass("rl-cache-purge"),e+=1)}),02&&void 0!==arguments[2]?arguments[2]:"",i=arguments.length>3&&void 0!==arguments[3]&&arguments[3];t=p.a.map(t,function(e){return Object(g.pInt)(e)});var a=0,r=this.messageList(),s=this.message(),c=D.a.trashFolder(),l=D.a.spamFolder(),u=Object(y.e)(e),d=""===o?null:Object(y.e)(o||""),h=D.a.currentFolderFullNameRaw()===e?p.a.filter(r,function(e){return e&&-1 ').insertBefore(e).on("click.rlBlockquoteSwitcher",function(){e.toggleClass("hidden-bq"),Object(g.windowResize)()}).after(" ").before(" "))})}},e.prototype.initOpenPgpControls=function(e,t){e&&e.find&&e.find(".b-plain-openpgp:not(.inited)").each(function(){M.a.initMessageBodyControls(m()(this),t)})},e.prototype.setMessage=function(e,t){var n=!1,o=null,i="",a="",r="",s=!1,c=this.messagesBodiesDom(),l=this.selectorMessageSelected(),u=this.message();if(e&&u&&e.Result&&"Object/Message"===e.Result["@Object"]&&u.folderFullNameRaw===e.Result.Folder){var d=u.threads();if(u.uid!==e.Result.Uid&&1 ').text(a)).html():v&&u.isPgpEncrypted()?S.$div.append(m()(' ').text(a)).html():""+r+" ",S.$div.empty(),u.isPgpSigned(s),u.isPgpEncrypted(v)}else r=""+r+" ";else f=!1,r=""+r+" ";S.data.iMessageBodyCacheCount+=1,(o=m()('
').hide().addClass("rl-cache-class")).data("rl-cache-count",S.data.iMessageBodyCacheCount),o.html(Object(g.findEmailAndLinks)(r)).addClass("b-text-part "+(f?"html":"plain")),u.isHtml(!!f),u.hasImages(!!e.Result.HasExternals),u.body=o,u.body&&c.append(u.body),u.storeDataInDom(),e.Result.HasInternals&&u.showInternalImages(!0),u.hasImages()&&G.a.showImages()&&u.showExternalImages(!0),this.purgeMessageBodyCacheThrottle()}this.messageActiveDom(u.body),this.hideMessageBodies(),o&&(this.initOpenPgpControls(o,u),this.initBlockquoteSwitcher(o)),u.body.show()}Object(y.n)(u),(u.unseen()||u.hasUnseenSubMessage())&&Object(V.a)().messageListAction(u.folderFullNameRaw,b.MessageSetAction.SetSeen,[u]),n&&(u=this.message(),l&&u&&(u.folderFullNameRaw!==l.folderFullNameRaw||u.uid!==l.uid)?(this.selectorMessageSelected(null),1===this.messageList().length&&this.selectorMessageFocused(null)):!l&&u&&(l=p.a.find(this.messageList(),function(e){return e&&e.folderFullNameRaw===u.folderFullNameRaw&&e.uid===u.uid}))&&(this.selectorMessageSelected(l),this.selectorMessageFocused(l))),Object(g.windowResize)()}}},e.prototype.selectMessage=function(e){e?(this.message(this.staticMessage.populateByMessageListItem(e)),this.populateMessageBody(this.message())):this.message(null)},e.prototype.selectMessageByFolderAndUid=function(e,t){e&&t?(this.message(this.staticMessage.populateByMessageListItem(null)),this.message().folderFullNameRaw=e,this.message().uid=t,this.populateMessageBody(this.message())):this.message(null)},e.prototype.populateMessageBody=function(e){e&&z.a.message(this.onMessageResponse,e.folderFullNameRaw,e.uid)&&this.messageCurrentLoading(!0)},e.prototype.onMessageResponse=function(e,t,n){this.hideMessageBodies(),this.messageCurrentLoading(!1),b.StorageResultType.Success===e&&t&&t.Result?this.setMessage(t,n):b.StorageResultType.Unload===e?(this.message(null),this.messageError("")):b.StorageResultType.Abort!==e&&(this.message(null),this.messageError(t&&t.ErrorCode?Object(w.getNotification)(t.ErrorCode):Object(w.getNotification)(b.Notification.UnknownError)))},e.prototype.calculateMessageListHash=function(e){return p.a.map(e,function(e){return e.hash+"_"+e.threadsLen()+"_"+e.flagHash()}).join("|")},e.prototype.setMessageList=function(e,t){if(e&&e.Result&&"Collection/MessageCollection"===e.Result["@Object"]&&e.Result["@Collection"]&&Object(g.isArray)(e.Result["@Collection"])){var n=0,o=!1,i=[],a=Object(T.momentNowUnix)(),r=Object(g.pInt)(e.Result.MessageResultCount),s=Object(g.pInt)(e.Result.Offset),c=Object(y.e)(Object(g.isNormal)(e.Result.Folder)?e.Result.Folder:"");c&&!t&&(c.interval=a,Object(y.q)(e.Result.Folder,e.Result.FolderHash),Object(g.isNormal)(e.Result.MessageCount)&&c.messageCountAll(e.Result.MessageCount),Object(g.isNormal)(e.Result.MessageUnseenCount)&&(Object(g.pInt)(c.messageCountUnread())!==Object(g.pInt)(e.Result.MessageUnseenCount)&&(o=!0),c.messageCountUnread(e.Result.MessageUnseenCount)),this.initUidNextAndNewMessages(c.fullNameRaw,e.Result.UidNext,e.Result.NewMessages)),o&&c&&Object(y.c)(c.fullNameRaw),p.a.each(e.Result["@Collection"],function(e){if(e&&"Object/Message"===e["@Object"]){var o=x.newInstanceFromJson(e);o&&(Object(y.l)(o.folderFullNameRaw,o.uid)&&5>=n&&(n+=1,o.newForAnimation(!0)),o.deleted(!1),t?Object(y.n)(o):Object(y.u)(o),i.push(o))}}),this.messageListCount(r),this.messageListSearch(Object(g.isNormal)(e.Result.Search)?e.Result.Search:""),this.messageListPage(u.a.Math.ceil(s/G.a.messagesPerPage()+1)),this.messageListThreadUid(Object(g.isNormal)(e.Result.ThreadUid)?Object(g.pString)(e.Result.ThreadUid):""),this.messageListEndFolder(Object(g.isNormal)(e.Result.Folder)?e.Result.Folder:""),this.messageListEndSearch(this.messageListSearch()),this.messageListEndThreadUid(this.messageListThreadUid()),this.messageListEndPage(this.messageListPage()),this.messageListDisableAutoSelect(!0),this.messageList(i),this.messageListIsNotCompleted(!1),Object(y.d)(),c&&(t||o||G.a.useThreads())&&Object(V.a)().folderInformation(c.fullNameRaw,i)}else this.messageListCount(0),this.messageList([]),this.messageListError(Object(w.getNotification)(e&&e.ErrorCode?e.ErrorCode:b.Notification.CantGetMessageList))},e}();t.a=new q},function(e,t,n){"use strict";function o(e,t){e=Object(R.trim)(e),t(H&&""!==e?I.h(e):"",e)}function i(e,t){return e+"#"+t}function a(e,t){U[i(e,t)]=!0}function r(e,t){return!0===U[i(e,t)]}function s(e,t){k[i(e,t)]=!0}function c(e,t){return!!k[i(e,t)]&&(k[i(e,t)]=null,!0)}function l(){k={}}function u(){return""===x?"INBOX":x}function d(e){return""!==e&&_[e]?_[e]:""}function p(e,t){_[e]=t,"INBOX"!==t&&""!==x||(x=t)}function h(e){return""!==e&&P[e]?P[e]:""}function f(e,t){""!==e&&(P[e]=t)}function m(e){return""!==e&&D[e]?D[e]:""}function b(e,t){D[e]=t}function g(e){return""!==e&&L[e]?L[e]:null}function y(e,t){L[e]=t}function v(e){y(e,null)}function S(e,t){return M[e]&&M[e][t]?M[e][t]:null}function O(e,t,n){M[e]||(M[e]={}),M[e][t]=n}function w(e){M[e]={}}function T(e){if(e){var t=e.uid,n=S(e.folderFullNameRaw,t);if(n&&00&&void 0!==arguments[0]?arguments[0]:"";return W+Object(V.pString)(e)}function r(){return ee?q:Y+te}function s(){return q}function c(e,t,n){return n=Object(V.isUnd)(n)?ne:n,Y+"/Raw/"+$+"/"+n+"/"+e+"/"+$+"/"+t}function l(e,t){return c("Download",e,t)}function u(e,t){return c("View",e,t)}function d(e,t){return c("ViewThumbnail",e,t)}function p(e,t){return c("ViewAsPlain",e,t)}function h(e,t){return c("FramedView",e,t)}function f(e){return Y+"/"+e+"/"+$+"/"+ne+"/"}function m(){return f("Upload")}function b(){return f("UploadContacts")}function g(){return f("UploadBackground")}function y(){return f("Append")}function v(e){return f("Change")+Object(V.encodeURIComponent)(e)+"/"}function S(e){return f("Ajax")+e}function O(e){return Y+"/Raw/"+$+"/"+ne+"/ViewAsPlain/"+$+"/"+e}function w(e){return Y+"/Raw/"+$+"/"+ne+"/Download/"+$+"/"+e}function T(e){return Y+"/Raw/0/Avatar/"+Object(V.encodeURIComponent)(e)+"/"}function C(e){return Y+"/Raw/"+$+"/"+ne+"/UserBackground/"+$+"/"+e}function A(){return Y+"/Info"}function E(e,t){return Y+"/Lang/0/"+(t?"Admin":"App")+"/"+K.a.encodeURI(e)+"/"+J+"/"}function F(){return Y+"/Raw/"+$+"/"+ne+"/ContactsVcf/"}function j(){return Y+"/Raw/"+$+"/"+ne+"/ContactsCsv/"}function N(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];return Y+"SocialGoogle"+(""!==ne?"/"+$+"/"+ne+"/":"")+(e?"&xauth=1":"")}function R(){return Y+"SocialTwitter"+(""!==ne?"/"+$+"/"+ne+"/":"")}function I(){return Y+"SocialFacebook"+(""!==ne?"/"+$+"/"+ne+"/":"")}function L(e){return Q+e}function _(){return L("css/images/empty-contact.png")}function P(e){return L("sounds/"+e)}function D(){return L("css/images/icom-message-notification.png")}function M(){return L("js/min/openpgp.min.js")}function k(){return L("js/min/openpgp.worker.min.js")}function x(e){var t=Z;return"@custom"===e.substr(-7)&&(e=Object(V.trim)(e.substring(0,e.length-7)),t=X),t+"themes/"+K.a.encodeURI(e)+"/images/preview.png"}function U(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"INBOX";return W+"mailbox/"+e}function H(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";return W+"settings"+(e?"/"+e:"")}function B(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"";t=Object(V.isNormal)(t)?Object(V.pInt)(t):1,n=Object(V.pString)(n);var i=W+"mailbox/";if(""!==e){var a=Object(V.pInt)(o);i+=K.a.encodeURI(e)+(0>2,r=(3&n)<<4|(o=e.charCodeAt(l++))>>4,s=(15&o)<<2|(i=e.charCodeAt(l++))>>6,c=63&i,isNaN(o)?s=c=64:isNaN(i)&&(c=64),t=t+m.charAt(a)+m.charAt(r)+m.charAt(s)+m.charAt(c);return t},decode:function(e){var t="",n=void 0,o=void 0,i=void 0,a=void 0,r=void 0,s=void 0,c=0;for(e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");c>4,o=(15&a)<<4|(r=m.indexOf(e.charAt(c++)))>>2,i=(3&r)<<6|(s=m.indexOf(e.charAt(c++))),t+=String.fromCharCode(n),64!==r&&(t+=String.fromCharCode(o)),64!==s&&(t+=String.fromCharCode(i));return b._utf8_decode(t)},_utf8_encode:function(e){for(var t="",n=0,o=(e=e.replace(/\r\n/g,"\n")).length,i=0;n127&&i<2048?(t+=String.fromCharCode(i>>6|192),t+=String.fromCharCode(63&i|128)):(t+=String.fromCharCode(i>>12|224),t+=String.fromCharCode(i>>6&63|128),t+=String.fromCharCode(63&i|128));return t},_utf8_decode:function(e){for(var t="",n=0,o=0,i=0,a=0;n191&&o<224?(i=e.charCodeAt(n+1),t+=String.fromCharCode((31&o)<<6|63&i),n+=2):(i=e.charCodeAt(n+1),a=e.charCodeAt(n+2),t+=String.fromCharCode((15&o)<<12|(63&i)<<6|63&a),n+=3);return t}},g=(b.decode,b.encode,b.urlsafe_encode),y=n(5),v=n(26),S=n(28),O=n(20),w=function(e){function t(){i()(this,t);var n=r()(this,e.call(this));return n.oRequests={},n}return c()(t,e),t.prototype.folders=function(e){this.defaultRequest(e,"Folders",{SentFolder:y.settingsGet("SentFolder"),DraftFolder:y.settingsGet("DraftFolder"),SpamFolder:y.settingsGet("SpamFolder"),TrashFolder:y.settingsGet("TrashFolder"),ArchiveFolder:y.settingsGet("ArchiveFolder")},null,"",["Folders"])},t.prototype.login=function(e,t,n,o,i,a,r,s){this.defaultRequest(e,"Login",{Email:t,Login:n,Password:o,Language:a||"",AdditionalCode:r||"",AdditionalCodeSignMe:s?"1":"0",SignMe:i?"1":"0"})},t.prototype.getTwoFactor=function(e){this.defaultRequest(e,"GetTwoFactorInfo")},t.prototype.createTwoFactor=function(e){this.defaultRequest(e,"CreateTwoFactorSecret")},t.prototype.clearTwoFactor=function(e){this.defaultRequest(e,"ClearTwoFactorInfo")},t.prototype.showTwoFactorSecret=function(e){this.defaultRequest(e,"ShowTwoFactorSecret")},t.prototype.testTwoFactor=function(e,t){this.defaultRequest(e,"TestTwoFactorInfo",{Code:t})},t.prototype.enableTwoFactor=function(e,t){this.defaultRequest(e,"EnableTwoFactor",{Enable:t?"1":"0"})},t.prototype.clearTwoFactorInfo=function(e){this.defaultRequest(e,"ClearTwoFactorInfo")},t.prototype.contactsSync=function(e){this.defaultRequest(e,"ContactsSync",null,p.d)},t.prototype.saveContactsSyncData=function(e,t,n,o,i){this.defaultRequest(e,"SaveContactsSyncData",{Enable:t?"1":"0",Url:n,User:o,Password:i})},t.prototype.accountSetup=function(e,t,n){var o=!(arguments.length>3&&void 0!==arguments[3])||arguments[3];this.defaultRequest(e,"AccountSetup",{Email:t,Password:n,New:o?"1":"0"})},t.prototype.accountDelete=function(e,t){this.defaultRequest(e,"AccountDelete",{EmailToDelete:t})},t.prototype.accountsAndIdentitiesSortOrder=function(e,t,n){this.defaultRequest(e,"AccountsAndIdentitiesSortOrder",{Accounts:t,Identities:n})},t.prototype.identityUpdate=function(e,t,n,o,i,a,r,s){this.defaultRequest(e,"IdentityUpdate",{Id:t,Email:n,Name:o,ReplyTo:i,Bcc:a,Signature:r,SignatureInsertBefore:s?"1":"0"})},t.prototype.identityDelete=function(e,t){this.defaultRequest(e,"IdentityDelete",{IdToDelete:t})},t.prototype.accountsAndIdentities=function(e){this.defaultRequest(e,"AccountsAndIdentities")},t.prototype.accountsCounts=function(e){this.defaultRequest(e,"AccountsCounts")},t.prototype.filtersSave=function(e,t,n,o){this.defaultRequest(e,"FiltersSave",{Raw:n,RawIsActive:Object(d.boolToAjax)(o),Filters:u.a.map(t,function(e){return e.toJson()})})},t.prototype.filtersGet=function(e){this.defaultRequest(e,"Filters",{})},t.prototype.templates=function(e){this.defaultRequest(e,"Templates",{})},t.prototype.templateGetById=function(e,t){this.defaultRequest(e,"TemplateGetByID",{ID:t})},t.prototype.templateDelete=function(e,t){this.defaultRequest(e,"TemplateDelete",{IdToDelete:t})},t.prototype.templateSetup=function(e,t,n,o){this.defaultRequest(e,"TemplateSetup",{ID:t,Name:n,Body:o})},t.prototype.messageList=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:20,i=arguments.length>4&&void 0!==arguments[4]?arguments[4]:"",a=arguments.length>5&&void 0!==arguments[5]?arguments[5]:"",r=arguments.length>6&&void 0!==arguments[6]&&arguments[6];t=Object(d.pString)(t);var s=Object(h.g)(t),c=v.a.threadsAllowed()&&S.a.useThreads(),l=Object(h.h)()===t?Object(h.i)(t):"";return""===s||""!==i&&-1!==i.indexOf("is:")?this.defaultRequest(e,"MessageList",{Folder:t,Offset:n,Limit:o,Search:i,UidNext:l,UseThreads:c?"1":"0",ThreadUid:c?a:""},""===i?p.g:p.m,"",r?[]:["MessageList"]):this.defaultRequest(e,"MessageList",{},""===i?p.g:p.m,"MessageList/"+Object(f.E)()+"/"+g([t,n,o,i,v.a.projectHash(),s,l,c?"1":"0",c?a:""].join(String.fromCharCode(0))),r?[]:["MessageList"])},t.prototype.messageUploadAttachments=function(e,t){this.defaultRequest(e,"MessageUploadAttachments",{Attachments:t},999e3)},t.prototype.message=function(e,t,n){return t=Object(d.pString)(t),n=Object(d.pInt)(n),!!(Object(h.e)(t)&&02&&void 0!==arguments[2]?arguments[2]:[],o=!0,i=[];Object(d.isArray)(n)&&03&&void 0!==arguments[3]?arguments[3]:null;this.defaultRequest(e,"MessageSetSeenToAll",{Folder:t,SetAction:n?"1":"0",ThreadUids:o?o.join(","):""})},t.prototype.saveMessage=function(e,t,n,o,i,a,r,s,c,l,u,d,h,f,m,b,g){this.defaultRequest(e,"SaveMessage",{IdentityID:t,MessageFolder:n,MessageUid:o,DraftFolder:i,To:a,Cc:r,Bcc:s,ReplyTo:c,Subject:l,TextIsHtml:u?"1":"0",Text:d,DraftInfo:f,InReplyTo:m,References:b,MarkAsImportant:g?"1":"0",Attachments:h},p.l)},t.prototype.sendReadReceiptMessage=function(e,t,n,o,i,a){this.defaultRequest(e,"SendReadReceiptMessage",{MessageFolder:t,MessageUid:n,ReadReceipt:o,Subject:i,Text:a})},t.prototype.sendMessage=function(e,t,n,o,i,a,r,s,c,l,u,d,h,f,m,b,g,y,v){this.defaultRequest(e,"SendMessage",{IdentityID:t,MessageFolder:n,MessageUid:o,SentFolder:i,To:a,Cc:r,Bcc:s,ReplyTo:c,Subject:l,TextIsHtml:u?"1":"0",Text:d,DraftInfo:f,InReplyTo:m,References:b,Dsn:g?"1":"0",ReadReceiptRequest:y?"1":"0",MarkAsImportant:v?"1":"0",Attachments:h},p.n)},t.prototype.saveSystemFolders=function(e,t){this.defaultRequest(e,"SystemFoldersUpdate",t)},t.prototype.saveSettings=function(e,t){this.defaultRequest(e,"SettingsUpdate",t)},t.prototype.saveSettingsHelper=function(e,t,n){var o=this;return function(i){var a;o.saveSettings(n||null,((a={})[e]=t?t(i):i,a))}},t.prototype.changePassword=function(e,t,n){this.defaultRequest(e,"ChangePassword",{PrevPassword:t,NewPassword:n})},t.prototype.folderClear=function(e,t){this.defaultRequest(e,"FolderClear",{Folder:t})},t.prototype.folderSetSubscribe=function(e,t,n){this.defaultRequest(e,"FolderSubscribe",{Folder:t,Subscribe:n?"1":"0"})},t.prototype.folderSetCheckable=function(e,t,n){this.defaultRequest(e,"FolderCheckable",{Folder:t,Checkable:n?"1":"0"})},t.prototype.messagesMove=function(e,t,n,o,i,a){this.defaultRequest(e,"MessageMove",{FromFolder:t,ToFolder:n,Uids:o.join(","),MarkAsRead:a?"1":"0",Learning:i||""},null,"",["MessageList"])},t.prototype.messagesCopy=function(e,t,n,o){this.defaultRequest(e,"MessageCopy",{FromFolder:t,ToFolder:n,Uids:o.join(",")})},t.prototype.messagesDelete=function(e,t,n){this.defaultRequest(e,"MessageDelete",{Folder:t,Uids:n.join(",")},null,"",["MessageList"])},t.prototype.appDelayStart=function(e){this.defaultRequest(e,"AppDelayStart")},t.prototype.quota=function(e){this.defaultRequest(e,"Quota")},t.prototype.contacts=function(e,t,n,o){this.defaultRequest(e,"Contacts",{Offset:t,Limit:n,Search:o},null,"",["Contacts"])},t.prototype.contactSave=function(e,t,n,o){this.defaultRequest(e,"ContactSave",{RequestUid:t,Uid:Object(d.trim)(n),Properties:o})},t.prototype.contactsDelete=function(e,t){this.defaultRequest(e,"ContactsDelete",{Uids:t.join(",")})},t.prototype.suggestions=function(e,t,n){this.defaultRequest(e,"Suggestions",{Query:t,Page:n},null,"",["Suggestions"])},t.prototype.clearUserBackground=function(e){this.defaultRequest(e,"ClearUserBackground")},t.prototype.facebookUser=function(e){this.defaultRequest(e,"SocialFacebookUserInformation")},t.prototype.facebookDisconnect=function(e){this.defaultRequest(e,"SocialFacebookDisconnect")},t.prototype.twitterUser=function(e){this.defaultRequest(e,"SocialTwitterUserInformation")},t.prototype.twitterDisconnect=function(e){this.defaultRequest(e,"SocialTwitterDisconnect")},t.prototype.googleUser=function(e){this.defaultRequest(e,"SocialGoogleUserInformation")},t.prototype.googleDisconnect=function(e){this.defaultRequest(e,"SocialGoogleDisconnect")},t.prototype.socialUsers=function(e){this.defaultRequest(e,"SocialUsers")},t}(n(115).a);t.a=new w},function(e,t,n){e.exports={default:n(111),__esModule:!0}},function(e,t){e.exports=window.key},function(e,t,n){"use strict";function o(){return n(173).default}n.d(t,"a",function(){return o})},,function(e,t,n){"use strict";function o(e,t,n){Object(s.isObject)(e)?(n=t||null,t=null,r.a.each(e,function(e,t){o(t,e,n)})):(Object(s.isUnd)(l[e])&&(l[e]=[]),l[e].push([t,n]))}function i(e,t){c.f("rl-pub",[e,t]),Object(s.isUnd)(l[e])||r.a.each(l[e],function(e){e[0]&&e[0].apply(e[1]||null,t||[])})}n.d(t,"b",function(){return o}),n.d(t,"a",function(){return i});var a=n(4),r=n.n(a),s=n(2),c=n(29),l={}},function(e,t,n){"use strict";n.d(t,"i",function(){return o}),n.d(t,"j",function(){return i}),n.d(t,"c",function(){return a}),n.d(t,"g",function(){return r}),n.d(t,"m",function(){return s}),n.d(t,"n",function(){return c}),n.d(t,"l",function(){return l}),n.d(t,"d",function(){return u}),n.d(t,"r",function(){return d}),n.d(t,"b",function(){return p}),n.d(t,"h",function(){return h}),n.d(t,"p",function(){return f}),n.d(t,"o",function(){return m}),n.d(t,"k",function(){return b}),n.d(t,"a",function(){return g}),n.d(t,"q",function(){return y}),n.d(t,"f",function(){return v}),n.d(t,"e",function(){return S});var o=20,i=[10,20,30,50,100],a=50,r=3e4,s=3e5,c=3e5,l=2e5,u=2e5,d="__UNUSE__",p="rlcsc",h=143,f=25,m=4190,b=15,g=7,y=10,v="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC4AAAAuCAYAAABXuSs3AAAHHklEQVRoQ7VZW08bVxCeXRuwIbTGXIwNtBBaqjwgVUiR8lDlbza9qe1DpVZ9aNQ/0KpPeaJK07SpcuEeCEmUAObm21bfrL9lONjexSYrWfbunj37zXdmvpkz9oIgCKTD0Wg0xPd94TDP83Q0zvWa50vzklSrdanVanqf4/D84GBGr+F+Op3S8fqoJxLOdnZgTvsO/nYhenHA+UC7CWF1uXwkb9++ldPTUwVerVbVqFQqpR8YPjQ0JCMjI5LNDijoRgP3PQVu5+5Eor2XGLg7IV4GkIdHJ/LmzRs5ODiIwNbrdR0O0GCcq4Xz4eFhmZyclP7+tDQaIik/BG5XKQn4SwG3zJTLZXn9+rUclI8UHD5YVoDDN8bSzXhONwL48fFxGR4eilzFZT1uFRIB5yT8BqCdnR3Z3d0VP9Un6XRawYJpggVrZBv38ME4XKtUKnLt2jUplUoy1PR/l3U7T6sVSAQcgMAkj8PDQ9ne3pajoyMRL7zeKsYZWHgWYDGmv78/mmdwcFA+mJlSgziHDWrERrsjEXDXegTi1tZW+DLxI2bxIrqFNYTXyDyCFweMAHCwb8e4RnTNuOsqe3t7sra21pTD0Kct666E8XlcZyzw9/RUUXK5nK5oUinUQI6TQ3cynO/v78vq6qrKXCNwlTiJJpyNGc3nZHp6uqV2dwrQWOCtZBDAV1ZWwsQk7f0wiQn5kffbAu/0/KWBYzIC1+XukfGx0RGZmppKlC2tIV0Bh4aDcZW7HhkfH8urLLZL7T2pihvlkMNnz56FiadHxicL41IsFpN41bkxsYxbRdFo9jwB8KdPn14J8KnSpBQKhQs63nPmbCVRcBUAR2Lq1VVmpksyMTFxAXjcEsQybiegESionjx5osCZOeNe1O4+EhCAX7bQSgQcxRHTMgAgcz5+/Dis/hL4uHU3/B4YGNASGHIKxuEql0k+l05AeIAF1vPnz5VxFFmdDlaJrMtZITJeSsXCOTlMunKxjLtMYOKNjQ158eJFuAuKkUOb5sEwgff19SkJUBVkThZUbnXZrtCKBQ6gbnWIkjZpyne3ejAWoGnA7Icz6irvBLgbOMicCM6TkxPx/LAkbXfgWcsazuE2kFRsKD5Z+CiqDumKncpZvieWcS6dDVD8xiYCNflpJdwcdwJOf9airLmVQ7DPzMxIYWLsXGXoVqLt5k0M3K3JUVPDZdbWNzsCp48TPFdvdnZWUz32nDha7bJ63kgAJPzSdRks9/Kf9xMJAQ1gq2NpaUmy2Yz4zar4nQC3xb99AQwCcGzLAAwuhG8YiWvcOKts+r4GOe5nMhm5efOm9lUA3E3vSZJRrKvE0fnPv//Jy5cvo5cTHIPQbSjhOoqq69evS19f6lxDKK4+sVhigZPtKJqbrQeqxd5+WR4+fKgqgT0k2XX3nhiPgETWXFhYkFzuPZ2yVq1GTSOXpE47/VjgNnD4m4GG7/LhsTx69EiwD4Vr2MwIIxgbAH18fKx1yfz8vEogNvGtWnCuhLZa9UTAreVWFsHy/b/+Vrbdl7E5REMQD2jDoUbByty+/ZnU64GkU2HzyJLhktU1cLv8nARgkYS2d3ajAgwG8qU2oLmDZ92CMaOjo7K4uCiZgbDWaRWgnZhPxLhrMUCvr69riwKZk1LHF7XqrWAO9hJxH6ozNzcnCx/PqztZg9mf6SQMscCtm2C5ke4BGMlHWTUp36036AJajDVrFMzBrhhWslQsSrFYiOqVpMriNYIgqFRq2j3FAb/zffT6zuxFXxsNzs3NTXn16lW4gYiW96w1FyedF+83xG/2FNGCRpU4NjamMsn+OZ9xE5RXqdaDdPpib6RWCzuwKF9RxqI2AVNQBwQYJoK0wdBejnqtEikP3pfP51XjUTESl12FqJEKxsEorARYDD44ONTeID7YpsEnrRvQfWAI2e8WfDaTUSIwJ0iBCmFOtOUAHvVMPp/TPwvYFVYFIuP8l+DBgwdaa2Miqwa0GgYwfeMltovbDfh6c1vIgMYcliSsKv4IWFr6VDHxvldvBAH+1sA+cnl5WYOPmmr9ir+1l9I0Cgz0yjhXjfJJ0JROnmezWbl165ayr/5fqwcBNr7IfhjMqKcvESSM4eRcCasQ3bDNObmKPLdGUGpZsN24cUNLBm9zazu4d++e6qpNBFaTuUS26U5dpuR1CxyA7J9ddrMRqlz4pwLLYawymPd++/2PADt2ugcGwq9gCCdhQ96C6xWwa6j1ceuq+I0EhW0i8MAIVJfeL3d/DVD8EKi12P6/2S2jV/EccVB54O/ejz/9HGCpoBBMta5rXMXLu53D1XAwjhXwvvv+h4BAXVe4bOu3O3ChxF08LiZFG3fel199G9CH3fLyqv24NcB44MRhpdK788U3CpyKwsCw590xmfSpzsBt0Fqc3ud3vtZigxWcVZCklVpSiN0w3q5E/h9TGMIUuA3+EQAAAABJRU5ErkJggg==",S="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC"},function(e,t,n){"use strict";n.d(t,"a",function(){return l});var o=n(8),i=n.n(o),a=n(1),r=n(2),s=n(0),c=n(6),l=function(){function e(){i()(this,e),this.bDisabeCloseOnEsc=!1,this.sDefaultKeyScope=s.KeyState.None,this.sCurrentKeyScope=s.KeyState.None,this.viewModelVisibility=a.a.observable(!1),this.modalVisibility=a.a.observable(!1).extend({rateLimit:0}),this.viewModelName="",this.viewModelNames=[],this.viewModelDom=null}return e.prototype.storeAndSetKeyScope=function(){this.sCurrentKeyScope=Object(c.keyScope)(),Object(c.keyScope)(this.sDefaultKeyScope)},e.prototype.restoreKeyScope=function(){Object(c.keyScope)(this.sCurrentKeyScope)},e.prototype.registerPopupKeyDown=function(){var e=this;c.$win.on("keydown",function(t){if(t&&e.modalVisibility&&e.modalVisibility()){if(!e.bDisabeCloseOnEsc&&s.EventKeyCode.Esc===t.keyCode)return Object(r.delegateRun)(e,"cancelCommand"),!1;if(s.EventKeyCode.Backspace===t.keyCode&&!Object(r.inFocus)())return!1}return!0})},e.prototype.cancelCommand=function(){},e.prototype.closeCommand=function(){},e}()},function(e,t,n){"use strict";var o=n(8),i=n.n(o),a=n(3),r=n.n(a),s=n(1),c=n(7),l=n.n(c),u=n(5),d=function(){function e(){var t=this;i()(this,e),this.google={},this.twitter={},this.facebook={},this.dropbox={},this.google.enabled=s.a.observable(!1),this.google.clientID=s.a.observable(""),this.google.clientSecret=s.a.observable(""),this.google.apiKey=s.a.observable(""),this.google.loading=s.a.observable(!1),this.google.userName=s.a.observable(""),this.google.loggined=s.a.computed(function(){return""!==t.google.userName()}),this.google.capa={},this.google.capa.auth=s.a.observable(!1),this.google.capa.authFast=s.a.observable(!1),this.google.capa.drive=s.a.observable(!1),this.google.capa.preview=s.a.observable(!1),this.google.require={},this.google.require.clientSettings=s.a.computed(function(){return t.google.enabled()&&(t.google.capa.auth()||t.google.capa.drive())}),this.google.require.apiKeySettings=s.a.computed(function(){return t.google.enabled()&&t.google.capa.drive()}),this.facebook.enabled=s.a.observable(!1),this.facebook.appID=s.a.observable(""),this.facebook.appSecret=s.a.observable(""),this.facebook.loading=s.a.observable(!1),this.facebook.userName=s.a.observable(""),this.facebook.supported=s.a.observable(!1),this.facebook.loggined=s.a.computed(function(){return""!==t.facebook.userName()}),this.twitter.enabled=s.a.observable(!1),this.twitter.consumerKey=s.a.observable(""),this.twitter.consumerSecret=s.a.observable(""),this.twitter.loading=s.a.observable(!1),this.twitter.userName=s.a.observable(""),this.twitter.loggined=s.a.computed(function(){return""!==t.twitter.userName()}),this.dropbox.enabled=s.a.observable(!1),this.dropbox.apiKey=s.a.observable("")}return e.prototype.populate=function(){this.google.enabled(!!u.settingsGet("AllowGoogleSocial")),this.google.clientID(u.settingsGet("GoogleClientID")),this.google.clientSecret(u.settingsGet("GoogleClientSecret")),this.google.apiKey(u.settingsGet("GoogleApiKey")),this.google.capa.auth(!!u.settingsGet("AllowGoogleSocialAuth")),this.google.capa.authFast(!!u.settingsGet("AllowGoogleSocialAuthFast")),this.google.capa.drive(!!u.settingsGet("AllowGoogleSocialDrive")),this.google.capa.preview(!!u.settingsGet("AllowGoogleSocialPreview")),this.facebook.enabled(!!u.settingsGet("AllowFacebookSocial")),this.facebook.appID(u.settingsGet("FacebookAppID")),this.facebook.appSecret(u.settingsGet("FacebookAppSecret")),this.facebook.supported(!!u.settingsGet("SupportedFacebookSocial")),this.twitter.enabled=s.a.observable(!!u.settingsGet("AllowTwitterSocial")),this.twitter.consumerKey=s.a.observable(u.settingsGet("TwitterConsumerKey")),this.twitter.consumerSecret=s.a.observable(u.settingsGet("TwitterConsumerSecret")),this.dropbox.enabled(!!u.settingsGet("AllowDropboxSocial")),this.dropbox.apiKey(u.settingsGet("DropboxApiKey"))},e.prototype.appendDropbox=function(){if(!r.a.Dropbox&&this.dropbox.enabled()&&this.dropbox.apiKey()&&!r.a.document.getElementById("dropboxjs")){var e=r.a.document.createElement("script");e.type="text/javascript",e.src="https://www.dropbox.com/static/api/2/dropins.js",l()(e).attr("id","dropboxjs").attr("data-app-key",this.dropbox.apiKey()),r.a.document.body.appendChild(e)}},e}();t.a=new d},function(e,t,n){"use strict";var o=n(8),i=n.n(o),a=n(12),r=n.n(a),s=n(11),c=n.n(s),l=n(1),u=n(0),d=n(6),p=n(2),h=n(5),f=function(e){function t(){i()(this,t);var n=r()(this,e.call(this));n.currentAudio=l.a.observable(""),n.focusedState=l.a.observable(u.Focused.None);var o=h.appSettingsGet("mobile");return n.focusedState.subscribe(function(e){switch(e){case u.Focused.MessageList:Object(d.keyScope)(u.KeyState.MessageList),o&&Object(d.leftPanelDisabled)(!0);break;case u.Focused.MessageView:Object(d.keyScope)(u.KeyState.MessageView),o&&Object(d.leftPanelDisabled)(!0);break;case u.Focused.FolderList:Object(d.keyScope)(u.KeyState.FolderList),o&&Object(d.leftPanelDisabled)(!1)}}),n.projectHash=l.a.observable(""),n.threadsAllowed=l.a.observable(!1),n.composeInEdit=l.a.observable(!1),n.contactsAutosave=l.a.observable(!1),n.useLocalProxyForExternalImages=l.a.observable(!1),n.contactsIsAllowed=l.a.observable(!1),n.attachmentsActions=l.a.observableArray([]),n.devEmail="",n.devPassword="",n}return c()(t,e),t.prototype.populate=function(){e.prototype.populate.call(this),this.projectHash(h.settingsGet("ProjectHash")),this.contactsAutosave(!!h.settingsGet("ContactsAutosave")),this.useLocalProxyForExternalImages(!!h.settingsGet("UseLocalProxyForExternalImages")),this.contactsIsAllowed(!!h.settingsGet("ContactsIsAllowed"));var t=h.appSettingsGet("attachmentsActions");this.attachmentsActions(Object(p.isNonEmptyArray)(t)?t:[]),this.devEmail=h.settingsGet("DevEmail"),this.devPassword=h.settingsGet("DevPassword")},t}(n(116).a);t.a=new f},function(e,t,n){"use strict";n.d(t,"a",function(){return u}),n.d(t,"b",function(){return d});var o=n(8),i=n.n(o),a=n(7),r=n.n(a),s=n(1),c=n(2),l=n(10),u=function(){function e(){i()(this,e),this.disposable=[]}return e.prototype.dispose=function(){this.disposable.forEach(function(e){e&&e.dispose&&e.dispose()})},e}(),d=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return{template:t?{element:t}:" ",viewModel:{createViewModel:function(t,n){return(t=t||{}).element=null,n&&n.element&&(t.component=n,t.element=r()(n.element),Object(l.i18nToNodes)(t.element),!Object(c.isUnd)(t.inline)&&s.a.unwrap(t.inline)&&t.element.css("display","inline-block")),new e(t)}}}}},function(e,t,n){"use strict";var o=n(8),i=n.n(o),a=n(3),r=n.n(a),s=n(1),c=n(23),l=n(0),u=n(6),d=n(2),p=n(22),h=n(5),f=function(){function e(){i()(this,e),this.iAutoLogoutTimer=0,this.layout=s.a.observable(l.Layout.SidePreview).extend({limitedList:[l.Layout.SidePreview,l.Layout.BottomPreview,l.Layout.NoPreview]}),this.editorDefaultType=s.a.observable(l.EditorDefaultType.Html).extend({limitedList:[l.EditorDefaultType.Html,l.EditorDefaultType.Plain,l.EditorDefaultType.HtmlForced,l.EditorDefaultType.PlainForced]}),this.messagesPerPage=s.a.observable(c.i).extend({limitedList:c.j}),this.showImages=s.a.observable(!1),this.useCheckboxesInList=s.a.observable(!0),this.allowDraftAutosave=s.a.observable(!0),this.useThreads=s.a.observable(!1),this.replySameFolder=s.a.observable(!1),this.autoLogout=s.a.observable(l.Magics.Time30mInMin),this.computers(),this.subscribers()}return e.prototype.computers=function(){var e=this;this.usePreviewPane=s.a.computed(function(){return l.Layout.NoPreview!==e.layout()})},e.prototype.subscribers=function(){this.layout.subscribe(function(e){u.$html.toggleClass("rl-no-preview-pane",l.Layout.NoPreview===e),u.$html.toggleClass("rl-side-preview-pane",l.Layout.SidePreview===e),u.$html.toggleClass("rl-bottom-preview-pane",l.Layout.BottomPreview===e),p.a("layout",[e])})},e.prototype.populate=function(){var e=this;this.layout(Object(d.pInt)(h.settingsGet("Layout"))),this.editorDefaultType(h.settingsGet("EditorDefaultType")),this.autoLogout(Object(d.pInt)(h.settingsGet("AutoLogout"))),this.messagesPerPage(h.settingsGet("MPP")),this.showImages(!!h.settingsGet("ShowImages")),this.useCheckboxesInList(!!h.settingsGet("UseCheckboxesInList")),this.allowDraftAutosave(!!h.settingsGet("AllowDraftAutosave")),this.useThreads(!!h.settingsGet("UseThreads")),this.replySameFolder(!!h.settingsGet("ReplySameFolder")),p.b("rl.auto-logout-refresh",function(){r.a.clearTimeout(e.iAutoLogoutTimer),01&&void 0!==arguments[1]?arguments[1]:[];Object(h.isArray)(b[e])&&p.a.each(b[e],function(e){e.apply(void 0,t)})}function a(e){return m.settingsGet(e)}function r(e,t,n,o){f.data.__APP__&&f.data.__APP__.remote().defaultRequest(e,"Plugin"+t,n,o)}function s(e,t,n,o){g.push([e,t,n,o])}function c(e,t,n,o){y.push([e,t,n,o])}function l(e){var t=n(9);p.a.each(e?y:g,function(e){t.addSettingsViewModel(e[0],e[1],e[2],e[3])})}function u(e,t){var n=m.settingsGet("Plugins");return(n=n&&!Object(h.isUnd)(n[e])?n[e]:null)?Object(h.isUnd)(n[t])?null:n[t]:null}n.d(t,"a",function(){return o}),n.d(t,"f",function(){return i}),n.d(t,"d",function(){return a}),n.d(t,"e",function(){return r}),n.d(t,"b",function(){return s}),n.d(t,"c",function(){return c}),n.d(t,"g",function(){return l}),n.d(t,"h",function(){return u});var d=n(4),p=n.n(d),h=n(2),f=n(6),m=n(5),b={},g=[],y=[]},function(e,t,n){"use strict";var o=n(8),i=n.n(o),a=n(1),r=n(4),s=n.n(r),c=n(7),l=n.n(c),u=n(10),d=n(2),p=n(31),h=n(9),f=function(){function e(){i()(this,e),this.capaOpenPGP=a.a.observable(!1),this.openpgp=null,this.openpgpkeys=a.a.observableArray([]),this.openpgpKeyring=null,this.openpgpkeysPublic=this.openpgpkeys.filter(function(e){return!(!e||e.isPrivate)}),this.openpgpkeysPrivate=this.openpgpkeys.filter(function(e){return!(!e||!e.isPrivate)})}return e.prototype.isSupported=function(){return!!this.openpgp},e.prototype.findKeyByHex=function(e,t){return s.a.find(e,function(e){return t&&e&&(t===e.id||-1 ').attr("title",Object(u.i18n)("MESSAGE/PGP_ENCRYPTED_MESSAGE_DESC")).on("click",e.domControlEncryptedClickHelper(this,t,s,a)):i&&(r=l()('
').attr("title",Object(u.i18n)("MESSAGE/PGP_SIGNED_MESSAGE_DESC")).on("click",e.domControlSignedClickHelper(this,t,s))),r&&t.before(r).before("
")}}},e}();t.a=new f},function(e,t,n){"use strict";var o=n(8),i=n.n(o),a=n(1),r=n(4),s=n.n(r),c=n(0),l=n(5),u=function(){function e(){i()(this,e),this.email=a.a.observable(""),this.parentEmail=a.a.observable(""),this.signature=a.a.observable(""),this.accounts=a.a.observableArray([]),this.accounts.loading=a.a.observable(!1).extend({throttle:c.Magics.Time100ms}),this.computers()}return e.prototype.computers=function(){var e=this;this.accountsEmails=a.a.computed(function(){return s.a.compact(s.a.map(e.accounts(),function(e){return e?e.email:null}))}),this.accountsUnreadCount=a.a.computed(function(){return 0})},e.prototype.populate=function(){this.email(l.settingsGet("Email")),this.parentEmail(l.settingsGet("ParentEmail"))},e.prototype.isRootAccount=function(){return""===this.parentEmail()},e}();t.a=new u},function(e,t,n){"use strict";var o=n(8),i=n.n(o),a=n(1),r=n(2),s=n(5),c=function(){function e(){i()(this,e),this.languages=a.a.observableArray([]),this.languagesAdmin=a.a.observableArray([]),this.language=a.a.observable("").extend({limitedList:this.languages}).extend({reversible:!0}),this.languageAdmin=a.a.observable("").extend({limitedList:this.languagesAdmin}).extend({reversible:!0}),this.userLanguage=a.a.observable(""),this.userLanguageAdmin=a.a.observable("")}return e.prototype.populate=function(){var e=s.appSettingsGet("languages"),t=s.appSettingsGet("languagesAdmin");this.languages(Object(r.isArray)(e)?e:[]),this.languagesAdmin(Object(r.isArray)(t)?t:[]),this.language(s.settingsGet("Language")),this.languageAdmin(s.settingsGet("LanguageAdmin")),this.userLanguage(s.settingsGet("UserLanguage")),this.userLanguageAdmin(s.settingsGet("UserLanguageAdmin"))},e}();t.a=new c},function(e,t,n){"use strict";function o(e,t){return!!v&&v.set("p"+e,t)}function i(e){return v?v.get("p"+e):null}var a=n(4),r=n.n(a),s=n(8),c=n.n(s),l=n(3),u=n.n(l),d=n(120),p=n.n(d),h=n(2),f=n(23),m=function(){function e(){c()(this,e)}return e.prototype.set=function(e,t){var n=!1,o=null;try{o=p.a.getJSON(f.b)}catch(e){}(o||(o={}))[e]=t;try{p.a.set(f.b,o,{expires:30}),n=!0}catch(e){}return n},e.prototype.get=function(e){var t=null;try{var n=p.a.getJSON(f.b);t=n&&!Object(h.isUnd)(n[e])?n[e]:null}catch(e){}return t},e.supported=function(){return!(!u.a.navigator||!u.a.navigator.cookieEnabled)},e}(),b=n(69),g=function(){function e(){c()(this,e),this.s=null,this.s=u.a.localStorage||null}return e.prototype.set=function(e,t){if(!this.s)return!1;var n=null;try{var o=this.s.getItem(f.b)||null;n=null===o?null:u.a.JSON.parse(o)}catch(e){}(n||(n={}))[e]=t;try{return this.s.setItem(f.b,u.a.JSON.stringify(n)),!0}catch(e){}return!1},e.prototype.get=function(e){if(!this.s)return null;try{var t=this.s.getItem(f.b)||null,n=null===t?null:u.a.JSON.parse(t);return n&&!Object(h.isUnd)(n[e])?n[e]:null}catch(e){}return null},e.supported=function(){return Object(b.d)("localStorage")},e}();n.d(t,"b",function(){return o}),n.d(t,"a",function(){return i});var y=r.a.find([g,m],function(e){return e&&e.supported()}),v=y?new y:null},function(e,t,n){"use strict";function o(){return S(),y||b()()}function i(){return O(),v||0}function a(e){return o().clone().subtract(e,"days").format("YYYY.MM.DD")}function r(e,t){var n=null,a="",r=i();if((n=0<(e=r<(e=0=t.diff(e,"hours"):return e.fromNow();case t.format("L")===e.format("L"):return Object(g.i18n)("MESSAGE_LIST/TODAY_AT",{TIME:e.format("LT")});case t.clone().subtract(1,"days").format("L")===e.format("L"):return Object(g.i18n)("MESSAGE_LIST/YESTERDAY_AT",{TIME:e.format("LT")});case t.year()===e.year():return e.format("D MMM.")}return e?e.format("LL"):""}(n);break;case"FULL":a=n.format("LLL");break;default:a=n.format(t)}return a}function s(e){var t,n="",o=f()(e);(t=o.data("moment-time"))&&((n=o.data("moment-format"))&&o.text(r(t,n)),(n=o.data("moment-format-title"))&&o.attr("title",r(t,n)))}function c(){p.a.defer(function(){f()(".moment",u.a.document).each(function(e,t){s(t)})})}n.r(t),n.d(t,"momentNow",function(){return o}),n.d(t,"momentNowUnix",function(){return i}),n.d(t,"searchSubtractFormatDateHelper",function(){return a}),n.d(t,"format",function(){return r}),n.d(t,"momentToNode",function(){return s}),n.d(t,"reload",function(){return c});var l=n(3),u=n.n(l),d=n(4),p=n.n(d),h=n(7),f=n.n(h),m=n(54),b=n.n(m),g=n(10),y=null,v=0,S=p.a.debounce(function(){y=b()()},500,!0),O=p.a.debounce(function(){v=b()().unix()},500,!0)},function(e,t){e.exports=window.hasher},function(e,t,n){"use strict";n.d(t,"a",function(){return r});var o=n(8),i=n.n(o),a=n(2),r=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";i()(this,e),this.sModelName="",this.disposables=[],this.sModelName=t||""}return e.prototype.regDisposables=function(e){var t=this;Object(a.isArray)(e)?e.forEach(function(e){t.disposables.push(e)}):e&&this.disposables.push(e)},e.prototype.onDestroy=function(){Object(a.disposeObject)(this)},e}()},,,function(e,t,n){"use strict";var o=n(8),i=n.n(o),a=n(1),r=n(2),s=n(5),c=function(){function e(){i()(this,e),this.themes=a.a.observableArray([]),this.themeBackgroundName=a.a.observable(""),this.themeBackgroundHash=a.a.observable(""),this.theme=a.a.observable("").extend({limitedList:this.themes})}return e.prototype.populate=function(){var e=s.appSettingsGet("themes");this.themes(Object(r.isArray)(e)?e:[]),this.theme(s.settingsGet("Theme")),this.themeBackgroundName(s.settingsGet("UserBackgroundName")),this.themeBackgroundHash(s.settingsGet("UserBackgroundHash"))},e}();t.a=new c},function(e,t){var n=e.exports={version:"2.5.1"};"number"==typeof __e&&(__e=n)},function(e,t){var n=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},function(e,t,n){e.exports=!n(51)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(e,t,n){var o=n(109),i=n(73);e.exports=function(e){return o(i(e))}},function(e,t,n){"use strict";n.r(t),n.d(t,"EmailModel",function(){return u}),n.d(t,"default",function(){return u});var o=n(8),i=n.n(o),a=n(4),r=n.n(a),s=n(76),c=n.n(s),l=n(2),u=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"none",a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"";i()(this,e),this.email="",this.name="",this.dkimStatus="",this.dkimValue="",this.email=t,this.name=n,this.dkimStatus=o,this.dkimValue=a,this.clearDuplicateName()}return e.newInstanceFromJson=function(t){var n=new e;return n.initByJson(t)?n:null},e.prototype.clear=function(){this.email="",this.name="",this.dkimStatus="none",this.dkimValue=""},e.prototype.validate=function(){return""!==this.name||""!==this.email},e.prototype.hash=function(){return"#"+(arguments.length>0&&void 0!==arguments[0]&&arguments[0]?"":this.name)+"#"+this.email+"#"},e.prototype.clearDuplicateName=function(){this.name===this.email&&(this.name="")},e.prototype.search=function(e){return-1<(this.name+" "+this.email).toLowerCase().indexOf(e.toLowerCase())},e.prototype.initByJson=function(e){var t=!1;return e&&"Object/Email"===e["@Object"]&&(this.name=Object(l.trim)(e.Name),this.email=Object(l.trim)(e.Email),this.dkimStatus=Object(l.trim)(e.DkimStatus||""),this.dkimValue=Object(l.trim)(e.DkimValue||""),t=""!==this.email,this.clearDuplicateName()),t},e.prototype.toLine=function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],o="";return""!==this.email&&(e&&""!==this.name?o=t?'")+'" target="_blank" tabindex="-1">'+Object(l.encodeHtml)(this.name)+" ":n?Object(l.encodeHtml)(this.name):this.name:(o=this.email,""!==this.name?t?o=Object(l.encodeHtml)('"'+this.name+'" <')+'")+'" target="_blank" tabindex="-1">'+Object(l.encodeHtml)(o)+" "+Object(l.encodeHtml)(">"):(o='"'+this.name+'" <'+o+">",n&&(o=Object(l.encodeHtml)(o))):t&&(o=''+Object(l.encodeHtml)(this.email)+" "))),o},e.splitEmailLine=function(t){var n=c()(t);if(Object(l.isNonEmptyArray)(n)){var o=[],i=!1;return n.forEach(function(t){var n=t.address?new e(t.address.replace(/^[<]+(.*)[>]+$/g,"$1"),t.name||""):null;n&&n.email&&(i=!0),o.push(n?n.toLine(!1):t.name)}),i?o:null}return null},e.parseEmailLine=function(t){var n=c()(t);return Object(l.isNonEmptyArray)(n)?r.a.compact(n.map(function(t){return t.address?new e(t.address.replace(/^[<]+(.*)[>]+$/g,"$1"),t.name||""):null})):[]},e.prototype.parse=function(e){if(""===(e=Object(l.trim)(e)))return!1;var t=c()(e);return!(!Object(l.isNonEmptyArray)(t)||!t[0]||(this.name=t[0].name||"",this.email=t[0].address||"",this.clearDuplicateName(),0))},e}()},function(e,t,n){"use strict";var o=n(8),i=n.n(o),a=n(3),r=n.n(a),s=n(6),c=n(16),l=n(22),u=n(2),d=function(){function e(){var t=this;if(i()(this,e),this.notificator=null,this.player=null,this.supported=!1,this.supportedMp3=!1,this.supportedOgg=!1,this.supportedWav=!1,this.supportedNotification=!1,this.player=this.createNewObject(),this.supported=!(s.bMobileDevice||s.bSafari||!this.player||!this.player.play),this.supported&&this.player&&this.player.canPlayType&&(this.supportedMp3=""!==this.player.canPlayType("audio/mpeg;").replace(/no/,""),this.supportedWav=""!==this.player.canPlayType('audio/wav; codecs="1"').replace(/no/,""),this.supportedOgg=""!==this.player.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/,""),this.supportedNotification=this.supported&&this.supportedMp3),this.player&&(this.supportedMp3||this.supportedOgg||this.supportedWav)||(this.supported=!1,this.supportedMp3=!1,this.supportedOgg=!1,this.supportedWav=!1,this.supportedNotification=!1),this.supported&&this.player){var n=function(){return t.stop()};this.player.addEventListener("ended",n),this.player.addEventListener("error",n),l.b("audio.api.stop",n)}}return e.prototype.createNewObject=function(){var e=r.a.Audio?new r.a.Audio:null;return e&&e.canPlayType&&e.pause&&e.play&&(e.preload="none",e.loop=!1,e.autoplay=!1,e.muted=!1),e},e.prototype.paused=function(){return!this.supported||!!this.player.paused},e.prototype.stop=function(){this.supported&&this.player.pause&&this.player.pause(),l.a("audio.stop")},e.prototype.pause=function(){this.stop()},e.prototype.clearName=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return e=Object(u.trim)(e),t&&"."+t===e.toLowerCase().substr(-1*(t.length+1))&&(e=Object(u.trim)(e.substr(0,e.length-4))),""===e?"audio":e},e.prototype.playMp3=function(e,t){this.supported&&this.supportedMp3&&(this.player.src=e,this.player.play(),l.a("audio.start",[this.clearName(t,"mp3"),"mp3"]))},e.prototype.playOgg=function(e,t){this.supported&&this.supportedOgg&&(this.player.src=e,this.player.play(),t=this.clearName(t,"oga"),t=this.clearName(t,"ogg"),l.a("audio.start",[t,"ogg"]))},e.prototype.playWav=function(e,t){this.supported&&this.supportedWav&&(this.player.src=e,this.player.play(),l.a("audio.start",[this.clearName(t,"wav"),"wav"]))},e.prototype.playNotification=function(){this.supported&&this.supportedMp3&&(this.notificator||(this.notificator=this.createNewObject(),this.notificator.src=c.D("new-mail.mp3")),this.notificator&&this.notificator.play&&this.notificator.play())},e}();t.a=new d},function(e,t){var n={}.hasOwnProperty;e.exports=function(e,t){return n.call(e,t)}},function(e,t,n){"use strict";n.d(t,"a",function(){return p});var o=n(8),i=n.n(o),a=n(12),r=n.n(a),s=n(11),c=n.n(s),l=n(1),u=n(2),d=n(0),p=function(e){function t(n){i()(this,t);var o=r()(this,e.call(this));return o.value=n.value||"",o.size=n.size||0,o.label=n.label||"",o.preLabel=n.preLabel||"",o.enable=!!Object(u.isUnd)(n.enable)||n.enable,o.trigger=n.trigger&&n.trigger.subscribe?n.trigger:null,o.placeholder=n.placeholder||"",o.labeled=!Object(u.isUnd)(n.label),o.preLabeled=!Object(u.isUnd)(n.preLabel),o.triggered=!Object(u.isUnd)(n.trigger)&&!!o.trigger,o.classForTrigger=l.a.observable(""),o.className=l.a.computed(function(){var e=l.a.unwrap(o.size),t=o.trigger?" "+Object(u.trim)("settings-saved-trigger-input "+o.classForTrigger()):"";return(0o?10:o,S.a.displaySpecSetting(0>=n||oObject(f.microtime)()-l);var d="";switch(!0){case"success"===n&&t&&t.Result&&e===t.Action:d=m.StorageResultType.Success;break;case!("abort"!==n||t&&t.__aborted__):d=m.StorageResultType.Abort;break;default:d=m.StorageResultType.Error}L.f("ajax-default-response",[e,m.StorageResultType.Success===d?t:null,d,i,o]),"success"===n?t&&t.Result&&e===t.Action?(t.__cached__=i,s(t)):t&&t.Action?(u=t,c(t.ErrorCode?t.ErrorCode:m.Notification.AjaxFalse)):(u=t,c(m.Notification.AjaxParse)):"timeout"===n?(u=t,c(m.Notification.AjaxTimeout)):"abort"===n?t&&t.__aborted__||c(m.Notification.AjaxAbort):(u=t,c(m.Notification.AjaxParse)),r.oRequests[e]&&(r.oRequests[e]=null,delete r.oRequests[e]),r.setTrigger(a,!1),u&&(-11&&void 0!==arguments[1]&&arguments[1];if(!a.a.Promise||!a.a.Promise.all)throw new Error("Promises are not available your environment.");if(!e)throw new Error("src should not be empty.");return new a.a.Promise(function(n,o){var i=a.a.document.createElement("script");i.onload=function(){n(e)},i.onerror=function(){o(new Error(e))},i.async=!0===t,i.src=e,a.a.document.body.appendChild(i)})}n.d(t,"a",function(){return o});var i=n(3),a=n.n(i)},function(e,t,n){var o=n(85)("wks"),i=n(70),a=n(41).Symbol,r="function"==typeof a;(e.exports=function(e){return o[e]||(o[e]=r&&a[e]||(r?a:i)("Symbol."+e))}).store=o},function(e,t,n){var o=n(52);e.exports=function(e){if(!o(e))throw TypeError(e+" is not an object!");return e}},function(e,t,n){"use strict";var o=n(8),i=n.n(o),a=n(3),r=n.n(a),s=n(1),c=n(0),l=n(22),u=n(45),d=n(5),p=function(){function e(){var t=this;i()(this,e),this.enableSoundNotification=s.a.observable(!1),this.soundNotificationIsSupported=s.a.observable(!1),this.allowDesktopNotification=s.a.observable(!1),this.desktopNotificationPermissions=s.a.computed(function(){t.allowDesktopNotification();var e=c.DesktopNotification.NotSupported,n=t.notificationClass();if(n&&n.permission)switch(n.permission.toLowerCase()){case"granted":e=c.DesktopNotification.Allowed;break;case"denied":e=c.DesktopNotification.Denied;break;case"default":e=c.DesktopNotification.NotAllowed}else r.a.webkitNotifications&&r.a.webkitNotifications.checkPermission&&(e=r.a.webkitNotifications.checkPermission());return e}).extend({notify:"always"}),this.enableDesktopNotification=s.a.computed({read:function(){return t.allowDesktopNotification()&&c.DesktopNotification.Allowed===t.desktopNotificationPermissions()},write:function(e){if(e){var n=t.notificationClass(),o=t.desktopNotificationPermissions();n&&c.DesktopNotification.Allowed===o?t.allowDesktopNotification(!0):n&&c.DesktopNotification.NotAllowed===o?n.requestPermission(function(){t.allowDesktopNotification.valueHasMutated(),c.DesktopNotification.Allowed===t.desktopNotificationPermissions()?t.allowDesktopNotification()?t.allowDesktopNotification.valueHasMutated():t.allowDesktopNotification(!0):t.allowDesktopNotification()?t.allowDesktopNotification(!1):t.allowDesktopNotification.valueHasMutated()}):t.allowDesktopNotification(!1)}else t.allowDesktopNotification(!1)}}).extend({notify:"always"}),this.enableDesktopNotification.valueHasMutated||(this.enableDesktopNotification.valueHasMutated=function(){t.allowDesktopNotification.valueHasMutated()}),this.computers(),this.initNotificationPlayer()}return e.prototype.computers=function(){var e=this;this.isDesktopNotificationSupported=s.a.computed(function(){return c.DesktopNotification.NotSupported!==e.desktopNotificationPermissions()}),this.isDesktopNotificationDenied=s.a.computed(function(){return c.DesktopNotification.NotSupported===e.desktopNotificationPermissions()||c.DesktopNotification.Denied===e.desktopNotificationPermissions()})},e.prototype.initNotificationPlayer=function(){u.a&&u.a.supportedNotification?this.soundNotificationIsSupported(!0):(this.enableSoundNotification(!1),this.soundNotificationIsSupported(!1))},e.prototype.playSoundNotification=function(e){u.a&&u.a.supportedNotification&&(e||this.enableSoundNotification())&&u.a.playNotification()},e.prototype.displayDesktopNotification=function(e,t,n,o){if(this.enableDesktopNotification()){var i=this.notificationClass(),a=i?new i(t,{body:n,icon:e}):null;a&&(a.show&&a.show(),o&&(a.onclick=function(){r.a.focus(),o.Folder&&o.Uid&&l.a("mailbox.message.show",[o.Folder,o.Uid])}),r.a.setTimeout((s=a,function(){s.cancel?s.cancel():s.close&&s.close()}),c.Magics.Time7s))}var s},e.prototype.populate=function(){this.enableSoundNotification(!!d.settingsGet("SoundNotification")),this.enableDesktopNotification(!!d.settingsGet("DesktopNotifications"))},e.prototype.notificationClass=function(){return r.a.Notification&&r.a.Notification.requestPermission?r.a.Notification:null},e}();t.a=new p},function(e,t,n){"use strict";function o(e,t,n,o,i){var a={};return Object.keys(o).forEach(function(e){a[e]=o[e]}),a.enumerable=!!a.enumerable,a.configurable=!!a.configurable,("value"in a||a.initializer)&&(a.writable=!0),a=n.slice().reverse().reduce(function(n,o){return o(e,t,n)||n},a),i&&void 0!==a.initializer&&(a.value=a.initializer?a.initializer.call(i):void 0,a.initializer=void 0),void 0===a.initializer&&(Object.defineProperty(e,t,a),a=null),a}n.r(t);var i,a,r,s,c,l,u,d,p,h,f=n(18),m=n.n(f),b=n(8),g=n.n(b),y=n(12),v=n.n(y),S=n(11),O=n.n(S),w=n(3),T=n.n(w),C=n(4),A=n.n(C),E=n(7),F=n.n(E),j=n(1),N=n(19),R=n.n(N),I=n(78),L=n.n(I),_=n(0),P=n(2),D=n(23),M=n(6),k=n(16),x=n(10),U=n(34),H=n(15),B=n(95),G=n(26),K=n(28),V=n(56),z=n(31),q=n(13),W=n(30),Y=n(14),$=n(25),J=n(17),X=n(5),Z=n(22),Q=n(79),ee=function(e){function t(n,o){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,a=arguments.length>3&&void 0!==arguments[3]&&arguments[3],r=arguments.length>4&&void 0!==arguments[4]&&arguments[4],s=arguments.length>5&&void 0!==arguments[5]?arguments[5]:"",c=arguments.length>6&&void 0!==arguments[6]?arguments[6]:"";g()(this,t);var l=v()(this,e.call(this,"ComposeAttachmentModel"));return l.id=n,l.isInline=!!a,l.isLinked=!!r,l.CID=s,l.contentLocation=c,l.fromMessage=!1,l.fileName=j.a.observable(o),l.size=j.a.observable(i),l.tempName=j.a.observable(""),l.progress=j.a.observable(0),l.error=j.a.observable(""),l.waiting=j.a.observable(!0),l.uploading=j.a.observable(!1),l.enabled=j.a.observable(!0),l.complete=j.a.observable(!1),l.progressText=j.a.computed(function(){var e=l.progress();return 0===e?"":(98a[e.email][1])&&(o=a[e.email][0],n=a[e.email][1])};if(A.a.each(i,function(e,t){a[e.email()]=[e,t]}),t)switch(e){case _.ComposeType.Empty:break;case _.ComposeType.Reply:case _.ComposeType.ReplyAll:case _.ComposeType.Forward:case _.ComposeType.ForwardAsAttachment:A.a.each(A.a.union(t.to,t.cc,t.bcc),r),o||A.a.each(t.deliveredTo,r);break;case _.ComposeType.Draft:A.a.each(A.a.union(t.from,t.replyTo),r)}return o||i[0]||null},t.prototype.selectIdentity=function(e){e&&e.item&&(this.currentIdentity(e.item),this.setSignatureFromIdentity(e.item))},t.prototype.sendMessageResponse=function(e,t){var n=!1,o="";this.sending(!1),_.StorageResultType.Success===e&&t&&t.Result&&(n=!0,this.modalVisibility()&&Object(P.delegateRun)(this,"closeCommand")),this.modalVisibility()&&!n&&(t&&_.Notification.CantSaveMessage===t.ErrorCode?(this.sendSuccessButSaveError(!0),this.savedErrorDesc(Object(P.trim)(Object(x.i18n)("COMPOSE/SAVED_ERROR_ON_SEND")))):(o=Object(x.getNotification)(t&&t.ErrorCode?t.ErrorCode:_.Notification.CantSendMessage,t&&t.ErrorMessage?t.ErrorMessage:""),this.sendError(!0),this.sendErrorDesc(o||Object(x.getNotification)(_.Notification.CantSendMessage)))),this.reloadDraftFolder()},t.prototype.saveMessageResponse=function(e,t){var n=!1;if(this.saving(!1),_.StorageResultType.Success===e&&t&&t.Result&&t.Result.NewFolder&&t.Result.NewUid){if(n=!0,this.bFromDraft){var o=Y.a.message();o&&this.draftFolder()===o.folderFullNameRaw&&this.draftUid()===o.uid&&Y.a.message(null)}this.draftFolder(t.Result.NewFolder),this.draftUid(t.Result.NewUid),this.savedTime(T.a.Math.round((new T.a.Date).getTime()/1e3)),this.bFromDraft&&Object(H.q)(this.draftFolder(),"")}n||(this.savedError(!0),this.savedErrorDesc(Object(x.getNotification)(_.Notification.CantSaveMessage))),this.reloadDraftFolder()},t.prototype.onHide=function(){this.autosaveStop(),this.bSkipNextHide||(G.a.composeInEdit(!1),this.reset()),this.bSkipNextHide=!1,this.to.focused(!1),Object(ne.routeOn)()},t.prototype.editor=function(e){var t=this;e&&(!this.oEditor&&this.composeEditorArea()?this.oEditor=new B.HtmlEditor(this.composeEditorArea(),null,function(){e(t.oEditor),t.resizerTrigger()},function(e){t.isHtml(!!e)}):this.oEditor&&(e(this.oEditor),this.resizerTrigger()))},t.prototype.converSignature=function(e){var t=10,n="",o=[],i=/{{MOMENT:([^}]+)}}/g;if(e=e.replace(/[\r]/g,""),""!==(n=this.oLastMessage?this.emailArrayToStringLineHelper(this.oLastMessage.from,!0):"")&&(e=e.replace(/{{FROM-FULL}}/g,n),-1===n.indexOf(" ")&&0 "+f+":"+Object(P.trim)(h)+" ";break;case _.ComposeType.Forward:c=g.fromToLine(!1,!0),l=g.toToLine(!1,!0),u=g.ccToLine(!1,!0),h=" "+Object(x.i18n)("COMPOSE/FORWARD_MESSAGE_TOP_TITLE")+" "+Object(x.i18n)("COMPOSE/FORWARD_MESSAGE_TOP_FROM")+": "+c+" "+Object(x.i18n)("COMPOSE/FORWARD_MESSAGE_TOP_TO")+": "+l+(0 "+Object(x.i18n)("COMPOSE/FORWARD_MESSAGE_TOP_CC")+": "+u:"")+" "+Object(x.i18n)("COMPOSE/FORWARD_MESSAGE_TOP_SENT")+": "+Object(P.encodeHtml)(d)+" "+Object(x.i18n)("COMPOSE/FORWARD_MESSAGE_TOP_SUBJECT")+": "+Object(P.encodeHtml)(p)+" "+Object(P.trim)(h)+" ";break;case _.ComposeType.ForwardAsAttachment:h=""}this.editor(function(e){e.setHtml(h,!1),(_.EditorDefaultType.PlainForced===s.editorDefaultType()||!g.isHtml()&&_.EditorDefaultType.HtmlForced!==s.editorDefaultType())&&e.modeToggle(!1),m&&_.ComposeType.Draft!==S&&_.ComposeType.EditAsNew!==S&&s.setSignatureFromIdentity(m),s.setFocusInPopup()})}else _.ComposeType.Empty===S?(this.subject(Object(P.isNormal)(a)?""+a:""),h=Object(P.isNormal)(r)?""+r:"",this.editor(function(e){e.setHtml(h,!1),_.EditorDefaultType.Html!==s.editorDefaultType()&&_.EditorDefaultType.HtmlForced!==s.editorDefaultType()&&e.modeToggle(!1),m&&s.setSignatureFromIdentity(m),s.setFocusInPopup()})):Object(P.isNonEmptyArray)(t)?(A.a.each(t,function(e){s.addMessageAsAttachment(e)}),this.editor(function(e){e.setHtml("",!1),_.EditorDefaultType.Html!==s.editorDefaultType()&&_.EditorDefaultType.HtmlForced!==s.editorDefaultType()&&e.modeToggle(!1),m&&_.ComposeType.Draft!==S&&_.ComposeType.EditAsNew!==S&&s.setSignatureFromIdentity(m),s.setFocusInPopup()})):this.setFocusInPopup();var T=this.getAttachmentsDownloadsForUpload();Object(P.isNonEmptyArray)(T)&&J.a.messageUploadAttachments(this.onMessageUploadAttachments,T),m&&this.currentIdentity(m),this.resizerTrigger()},t.prototype.onMessageUploadAttachments=function(e,t){var n=this;_.StorageResultType.Success===e&&t&&t.Result?this.viewModelVisibility()||A.a.each(t.Result,function(e,t){var o=n.getAttachmentById(e);o&&(o.tempName(t),o.waiting(!1).uploading(!1).complete(!0))}):this.setMessageAttachmentFailedDownloadText()},t.prototype.setFocusInPopup=function(){var e=this;M.bMobileDevice||A.a.delay(function(){""===e.to()?e.to.focused(!0):e.oEditor&&(e.to.focused()||e.oEditor.focus())},_.Magics.Time100ms)},t.prototype.onShowWithDelay=function(){this.resizerTrigger()},t.prototype.tryToClosePopup=function(){var e=this,t=n(99);!Object(ne.isPopupVisible)(t)&&this.modalVisibility()&&(this.bSkipNextHide||this.isEmptyForm()&&!this.draftUid()?Object(P.delegateRun)(this,"closeCommand"):Object(ne.showScreenPopup)(t,[Object(x.i18n)("POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW"),function(){e.modalVisibility()&&Object(P.delegateRun)(e,"closeCommand")}]))},t.prototype.onBuild=function(){var e=this;this.initUploader(),R()("ctrl+q, command+q, ctrl+w, command+w",_.KeyState.Compose,P.noopFalse),R()("`",_.KeyState.Compose,function(){return!(e.oEditor&&!e.oEditor.hasFocus()&&!Object(P.inFocus)()&&(e.identitiesDropdownTrigger(!0),1))}),R()("ctrl+`",_.KeyState.Compose,function(){return e.identitiesDropdownTrigger(!0),!1}),R()("esc, ctrl+down, command+down",_.KeyState.Compose,function(){return e.skipCommand(),!1}),this.allowFolders&&R()("ctrl+s, command+s",_.KeyState.Compose,function(){return e.saveCommand(),!1}),X.appSettingsGet("allowCtrlEnterOnCompose")&&R()("ctrl+enter, command+enter",_.KeyState.Compose,function(){return e.sendCommand(),!1}),R()("shift+esc",_.KeyState.Compose,function(){return e.modalVisibility()&&e.tryToClosePopup(),!1}),Z.b("window.resize.real",this.resizerTrigger),Z.b("window.resize.real",A.a.debounce(this.resizerTrigger,_.Magics.Time50ms)),$.a.appendDropbox(),this.driveEnabled()&&F.a.getScript("https://apis.google.com/js/api.js",function(){T.a.gapi&&e.driveVisible(!0)}),T.a.setInterval(function(){e.modalVisibility()&&e.oEditor&&e.oEditor.resize()},_.Magics.Time5s)},t.prototype.driveCallback=function(e,t){var n=this;if(t&&T.a.XMLHttpRequest&&T.a.google&&t[T.a.google.picker.Response.ACTION]===T.a.google.picker.Action.PICKED&&t[T.a.google.picker.Response.DOCUMENTS]&&t[T.a.google.picker.Response.DOCUMENTS][0]&&t[T.a.google.picker.Response.DOCUMENTS][0].id){var o=new T.a.XMLHttpRequest;o.open("GET","https://www.googleapis.com/drive/v2/files/"+t[T.a.google.picker.Response.DOCUMENTS][0].id),o.setRequestHeader("Authorization","Bearer "+e),o.addEventListener("load",function(){if(o&&o.responseText){var t=T.a.JSON.parse(o.responseText),i=function(e,n,o){e&&e.exportLinks&&(e.exportLinks[n]?(t.downloadUrl=e.exportLinks[n],t.title=e.title+"."+o,t.mimeType=n):e.exportLinks["application/pdf"]&&(t.downloadUrl=e.exportLinks["application/pdf"],t.title=e.title+".pdf",t.mimeType="application/pdf"))};if(t&&!t.downloadUrl&&t.mimeType&&t.exportLinks)switch(t.mimeType.toString().toLowerCase()){case"application/vnd.google-apps.document":i(t,"application/vnd.openxmlformats-officedocument.wordprocessingml.document","docx");break;case"application/vnd.google-apps.spreadsheet":i(t,"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","xlsx");break;case"application/vnd.google-apps.drawing":i(t,"image/png","png");break;case"application/vnd.google-apps.presentation":i(t,"application/vnd.openxmlformats-officedocument.presentationml.presentation","pptx");break;default:i(t,"application/pdf","pdf")}t&&t.downloadUrl&&n.addDriveAttachment(t,e)}}),o.send()}},t.prototype.driveCreatePiker=function(e){var t=this;T.a.gapi&&e&&e.access_token&&T.a.gapi.load("picker",{callback:function(){T.a.google&&T.a.google.picker&&(new T.a.google.picker.PickerBuilder).addView(T.a.google.picker.ViewId.DOCS).setAppId(X.settingsGet("GoogleClientID")).setOAuthToken(e.access_token).setCallback(A.a.bind(t.driveCallback,t,e.access_token)).enableFeature(T.a.google.picker.Feature.NAV_HIDDEN).build().setVisible(!0)}})},t.prototype.driveOpenPopup=function(){var e=this;T.a.gapi&&T.a.gapi.load("auth",{callback:function(){var t=T.a.gapi.auth.getToken(),n=function(t){if(t&&!t.error){var n=T.a.gapi.auth.getToken();return n&&e.driveCreatePiker(n),!0}return!1};t?e.driveCreatePiker(t):T.a.gapi.auth.authorize({client_id:X.settingsGet("GoogleClientID"),scope:"https://www.googleapis.com/auth/drive.readonly",immediate:!0},function(e){n(e)||T.a.gapi.auth.authorize({client_id:X.settingsGet("GoogleClientID"),scope:"https://www.googleapis.com/auth/drive.readonly",immediate:!1},n)})}})},t.prototype.getAttachmentById=function(e){return A.a.find(this.attachments(),function(t){return t&&e===t.id})},t.prototype.cancelAttachmentHelper=function(e,t){var n=this;return function(){var o=A.a.find(n.attachments(),function(t){return t&&t.id===e});o&&(n.attachments.remove(o),Object(P.delegateRunOnDestroy)(o),t&&t.cancel(e))}},t.prototype.initUploader=function(){var e=this;if(this.composeUploaderButton()){var t={},n=Object(P.pInt)(X.settingsGet("AttachmentLimit")),o=new L.a({action:Object(k.G)(),name:"uploader",queueSize:2,multipleSizeLimit:50,clickElement:this.composeUploaderButton(),dragAndDropElement:this.composeUploaderDropPlace()});o?(o.on("onDragEnter",function(){e.dragAndDropOver(!0)}).on("onDragLeave",function(){e.dragAndDropOver(!1)}).on("onBodyDragEnter",function(){e.attachmentsPlace(!0),e.dragAndDropVisible(!0)}).on("onBodyDragLeave",function(){e.dragAndDropVisible(!1)}).on("onProgress",function(n,o,i){var a=t[n];a||(a=e.getAttachmentById(n))&&(t[n]=a),a&&a.progress(T.a.Math.floor(o/i*100))}).on("onSelect",function(t,i){e.dragAndDropOver(!1);var a=Object(P.isUnd)(i.FileName)?"":i.FileName.toString(),r=Object(P.isNormal)(i.Size)?Object(P.pInt)(i.Size):null,s=new ee(t,a,r);return s.cancel=e.cancelAttachmentHelper(t,o),e.attachments.push(s),e.attachmentsPlace(!0),!(00&&void 0!==arguments[0]&&!arguments[0]?0===this.attachmentsInReady().length:0===this.attachments().length;return 0===this.to().length&&0===this.cc().length&&0===this.bcc().length&&0===this.replyTo().length&&0===this.subject().length&&e&&(!this.oEditor||""===this.oEditor.getData())},t.prototype.reset=function(){this.to(""),this.cc(""),this.bcc(""),this.replyTo(""),this.subject(""),this.requestDsn(!1),this.requestReadReceipt(!1),this.markAsImportant(!1),this.attachmentsPlace(!1),this.aDraftInfo=null,this.sInReplyTo="",this.bFromDraft=!1,this.sReferences="",this.sendError(!1),this.sendSuccessButSaveError(!1),this.savedError(!1),this.savedTime(0),this.emptyToError(!1),this.attachmentsInProcessError(!1),this.showCc(!1),this.showBcc(!1),this.showReplyTo(!1),Object(P.delegateRunOnDestroy)(this.attachments()),this.attachments([]),this.dragAndDropOver(!1),this.dragAndDropVisible(!1),this.draftFolder(""),this.draftUid(""),this.sending(!1),this.saving(!1),this.oEditor&&this.oEditor.clear(!1)},t.prototype.getAttachmentsDownloadsForUpload=function(){return A.a.map(A.a.filter(this.attachments(),function(e){return e&&""===e.tempName()}),function(e){return e.id})},t.prototype.resizerTrigger=function(){this.resizer(!this.resizer())},t}(oe.a)).prototype,"sendCommand",[a],m()(h.prototype,"sendCommand"),h.prototype),o(h.prototype,"saveCommand",[r],m()(h.prototype,"saveCommand"),h.prototype),o(h.prototype,"deleteCommand",[s],m()(h.prototype,"deleteCommand"),h.prototype),o(h.prototype,"skipCommand",[c],m()(h.prototype,"skipCommand"),h.prototype),o(h.prototype,"contactsCommand",[l],m()(h.prototype,"contactsCommand"),h.prototype),o(h.prototype,"dropboxCommand",[u],m()(h.prototype,"dropboxCommand"),h.prototype),o(h.prototype,"driveCommand",[d],m()(h.prototype,"driveCommand"),h.prototype),p=h))||p)},function(e,t){e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},function(e,t,n){"use strict";n.d(t,"a",function(){return u});var o=n(8),i=n.n(o),a=n(4),r=n.n(a),s=n(75),c=n.n(s),l=n(2),u=function(){function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[];i()(this,e),this.oCross=null,this.sScreenName=t,this.aViewModels=Object(l.isArray)(n)?n:[]}return e.prototype.viewModels=function(){return this.aViewModels},e.prototype.screenName=function(){return this.sScreenName},e.prototype.routes=function(){return null},e.prototype.__cross=function(){return this.oCross},e.prototype.__start=function(){var e=null,t=null,n=this.routes();Object(l.isNonEmptyArray)(n)&&(t=r.a.bind(this.onRoute||l.noop,this),e=c.a.create(),n.forEach(function(n){n&&e&&(e.addRoute(n[0],t).rules=n[1])}),this.oCross=e)},e}()},function(e,t){e.exports=window.ssm},function(e,t,n){var o=n(52);e.exports=function(e,t){if(!o(e))return e;var n,i;if(t&&"function"==typeof(n=e.toString)&&!o(i=n.call(e)))return i;if("function"==typeof(n=e.valueOf)&&!o(i=n.call(e)))return i;if(!t&&"function"==typeof(n=e.toString)&&!o(i=n.call(e)))return i;throw TypeError("Can't convert object to primitive value")}},,function(e,t,n){"use strict";function o(e){if(e in l.a&&l.a[e]&&l.a[e].setItem){var t=l.a[e],n="testLocalStorage_"+l.a.Math.random();try{if(t.setItem(n,n),n===t.getItem(n))return t.removeItem(n),!0}catch(e){}}return!1}function i(){return h(u)}function a(){var e="AuthAccountHash",t=l.a.__rlah_data();f(u,t&&t[e]?t[e]:""),b()}function r(){f(u,""),b()}function s(){return m()>g()+36e5&&(r(),!0)}n.d(t,"d",function(){return o}),n.d(t,"c",function(){return i}),n.d(t,"e",function(){return a}),n.d(t,"b",function(){return r}),n.d(t,"a",function(){return s});var c=n(3),l=n.n(c),u="__rlA",d=o("sessionStorage")&&l.a.sessionStorage||null,p=l.a.top||l.a||null,h=function(e){var t=null;if(d)t=d.getItem(e)||null;else if(p&&l.a.JSON){var n=p.name&&"{"===p.name.toString().substr(0,1)?l.a.JSON.parse(p.name.toString()):null;t=n&&n[e]||null}return t},f=function(e,t){if(d)d.setItem(e,t);else if(p&&l.a.JSON){var n=p.name&&"{"===p.name.toString().substr(0,1)?l.a.JSON.parse(p.name.toString()):null;(n=n||{})[e]=t,p.name=l.a.JSON.stringify(n)}},m=function(){return l.a.Math.round((new l.a.Date).getTime()/1e3)},b=function(){return f("__rlT",m())},g=function(){var e=h("__rlT",0);return e&&l.a.parseInt(e,10)||0};l.a.setInterval(b,6e4)},function(e,t){var n=0,o=Math.random();e.exports=function(e){return"Symbol(".concat(void 0===e?"":e,")_",(++n+o).toString(36))}},function(e,t){t.f={}.propertyIsEnumerable},function(e,t,n){var o=n(71),i=n(64),a=n(43),r=n(67),s=n(46),c=n(77),l=Object.getOwnPropertyDescriptor;t.f=n(42)?l:function(e,t){if(e=a(e),t=r(t,!0),c)try{return l(e,t)}catch(e){}if(s(e,t))return i(!o.f.call(e,t),e[t])}},function(e,t){e.exports=function(e){if(void 0==e)throw TypeError("Can't call method on "+e);return e}},function(e,t,n){"use strict";n.d(t,"a",function(){return d});var o=n(8),i=n.n(o),a=n(12),r=n.n(a),s=n(11),c=n.n(s),l=n(1),u=n(2),d=function(e){function t(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};i()(this,t);var o=r()(this,e.call(this));return o.value=n.value,!Object(u.isUnd)(o.value)&&o.value.subscribe||(o.value=l.a.observable(!Object(u.isUnd)(o.value)&&!!o.value)),o.enable=n.enable,!Object(u.isUnd)(o.enable)&&o.enable.subscribe||(o.enable=l.a.observable(!!Object(u.isUnd)(o.enable)||!!o.enable)),o.disable=n.disable,!Object(u.isUnd)(o.disable)&&o.disable.subscribe||(o.disable=l.a.observable(!Object(u.isUnd)(o.disable)&&!!o.disable)),o.label=n.label||"",o.inline=!Object(u.isUnd)(n.inline)&&n.inline,o.readOnly=!Object(u.isUnd)(n.readOnly)&&!!n.readOnly,o.inverted=!Object(u.isUnd)(n.inverted)&&!!n.inverted,o.labeled=!Object(u.isUnd)(n.label),o.labelAnimated=!!n.labelAnimated,o}return c()(t,e),t.prototype.click=function(){this.readOnly||!this.enable()||this.disable()||this.value(!this.value())},t}(n(27).a)},function(e,t){e.exports=window.crossroads},function(e,t,n){"use strict";function o(e){var t=[],n=[],i=[];return new r(e).tokenize().forEach(function(e){"operator"!==e.type||","!==e.value&&";"!==e.value?n.push(e):(n.length&&t.push(n),n=[])}),n.length&&t.push(n),t.forEach(function(e){(e=function(e){for(var t=!1,n="text",i=void 0,a=[],r={address:[],comment:[],group:[],text:[]},s=0,c=e.length;s=0;u--)if(r.text[u].match(/^[^@\s]+@[^@\s]+$/)){r.address=r.text.splice(u,1);break}if(!r.address.length)for(var d=r.text.length-1;d>=0&&(r.text[d]=r.text[d].replace(/\s*\b[^@\s]+@[^@\s]+\b\s*/,function(e){return r.address.length?e:(r.address=[e.trim()]," ")}).trim(),!r.address.length);d--);}if(!r.text.length&&r.comment.length&&(r.text=r.comment,r.comment=[]),r.address.length>1&&(r.text=r.text.concat(r.address.splice(1))),r.text=r.text.join(" "),r.address=r.address.join(" "),!r.address&&t)return[];(i={address:r.address||r.text||"",name:r.text||r.address||""}).address===i.name&&((i.address||"").match(/@/)?i.name="":i.address=""),a.push(i)}return a}(e)).length&&(i=i.concat(e))}),i}Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t){for(var n=0;n",",":"",":":";",";":""},r=function(){function e(t){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.str=(t||"").toString(),this.operatorCurrent="",this.operatorExpecting="",this.node=null,this.escaped=!1,this.list=[]}return i(e,[{key:"tokenize",value:function(){for(var e=void 0,t=[],n=0,o=this.str.length;n +$/,""),this.fileNameExt=Object(b.getFileExtension)(this.fileName),this.fileType=S(this.fileNameExt,this.mimeType),t=!0),t},t.prototype.isImage=function(){return f.FileType.Image===this.fileType},t.prototype.isMp3=function(){return f.FileType.Audio===this.fileType&&"mp3"===this.fileNameExt},t.prototype.isOgg=function(){return f.FileType.Audio===this.fileType&&("oga"===this.fileNameExt||"ogg"===this.fileNameExt)},t.prototype.isWav=function(){return f.FileType.Audio===this.fileType&&"wav"===this.fileNameExt},t.prototype.hasThumbnail=function(){return this.isThumbnail},t.prototype.isText=function(){return f.FileType.Text===this.fileType||f.FileType.Eml===this.fileType||f.FileType.Certificate===this.fileType||f.FileType.Html===this.fileType||f.FileType.Code===this.fileType},t.prototype.isPdf=function(){return f.FileType.Pdf===this.fileType},t.prototype.isFramed=function(){return this.framed&&m.data.__APP__&&m.data.__APP__.googlePreviewSupported()&&!(this.isPdf()&&m.bAllowPdfPreview)&&!this.isText()&&!this.isImage()},t.prototype.hasPreview=function(){return this.isImage()||this.isPdf()&&m.bAllowPdfPreview||this.isText()||this.isFramed()},t.prototype.hasPreplay=function(){return v.a.supportedMp3&&this.isMp3()||v.a.supportedOgg&&this.isOgg()||v.a.supportedWav&&this.isWav()},t.prototype.linkDownload=function(){return Object(g.c)(this.download)},t.prototype.linkPreview=function(){return Object(g.e)(this.download)},t.prototype.linkThumbnail=function(){return this.hasThumbnail()?Object(g.g)(this.download):""},t.prototype.linkThumbnailPreviewStyle=function(){var e=this.linkThumbnail();return""===e?"":"background:url("+e+")"},t.prototype.linkFramed=function(){return Object(g.d)(this.download)},t.prototype.linkPreviewAsPlain=function(){return Object(g.f)(this.download)},t.prototype.linkPreviewMain=function(){var e="";switch(!0){case this.isImage():case this.isPdf()&&m.bAllowPdfPreview:e=this.linkPreview();break;case this.isText():e=this.linkPreviewAsPlain();break;case this.isFramed():e=this.linkFramed()}return e},t.prototype.generateTransferDownloadUrl=function(){var e=this.linkDownload();return"http"!==e.substr(0,4)&&(e=u.a.location.protocol+"//"+u.a.location.host+u.a.location.pathname+e),this.mimeType+":"+this.fileName+":"+e},t.prototype.eventDragStart=function(e,t){var n=t.originalEvent||t;return e&&n&&n.dataTransfer&&n.dataTransfer.setData&&n.dataTransfer.setData("DownloadURL",this.generateTransferDownloadUrl()),!0},t.prototype.iconClass=function(){return O(this.fileType)[0]},t.prototype.iconText=function(){return O(this.fileType)[1]},t}(y.a)},function(e,t,n){"use strict";n.r(t);var o=n(8),i=n.n(o),a=n(12),r=n.n(a),s=n(11),c=n.n(s),l=n(27),u=function(e){function t(){return i()(this,t),r()(this,e.apply(this,arguments))}return c()(t,e),t}(n(74).a);t.default=Object(l.b)(u,"CheckboxComponent")},function(e,t,n){var o=n(41),i=n(40),a=n(90),r=n(82),s=n(49).f;e.exports=function(e){var t=i.Symbol||(i.Symbol=a?{}:o.Symbol||{});"_"==e.charAt(0)||e in t||s(t,e,{value:r.f(e)})}},function(e,t,n){t.f=n(60)},function(e,t,n){var o=n(49).f,i=n(46),a=n(60)("toStringTag");e.exports=function(e,t,n){e&&!i(e=n?e:e.prototype,a)&&o(e,a,{configurable:!0,value:t})}},function(e,t){e.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},function(e,t,n){var o=n(41),i=o["__core-js_shared__"]||(o["__core-js_shared__"]={});e.exports=function(e){return i[e]||(i[e]={})}},function(e,t,n){var o=n(85)("keys"),i=n(70);e.exports=function(e){return o[e]||(o[e]=i(e))}},function(e,t,n){var o=n(104),i=n(84);e.exports=Object.keys||function(e){return o(e,i)}},function(e,t,n){var o=n(61),i=n(164),a=n(84),r=n(86)("IE_PROTO"),s=function(){},c=function(){var e,t=n(93)("iframe"),o=a.length;for(t.style.display="none",n(160).appendChild(t),t.src="javascript:",(e=t.contentWindow.document).open(),e.write("', '<\/script>',
- \str_replace($aJsonReplaces[0], $aJsonReplaces[1], $sText));
- }
-
- /**
- * @param array $aInput
- */
- public static function ClearArrayUtf8Values(&$aInput)
- {
- if (\is_array($aInput))
- {
- foreach ($aInput as $mKey => $mItem)
- {
- if (\is_string($mItem))
- {
- $aInput[$mKey] = \MailSo\Base\Utils::Utf8Clear($mItem);
- }
- else if (\is_array($mItem))
- {
- \MailSo\Base\Utils::ClearArrayUtf8Values($mItem);
- $aInput[$mKey] = $mItem;
- }
- }
- }
- }
-
- /**
- * @param mixed $mInput
- * @param \MailSo\Log\Logger|null $oLogger = null
- *
- * @return string
- */
- public static function Php2js($mInput, $oLogger = null)
- {
- static $iOpt = null;
- if (null === $iOpt)
- {
- $iOpt = \defined('JSON_UNESCAPED_UNICODE') ? JSON_UNESCAPED_UNICODE : 0;
- }
-
- $sResult = @\json_encode($mInput, $iOpt);
- if (!\is_string($sResult) || '' === $sResult)
- {
- if (!$oLogger && \MailSo\Log\Logger::IsSystemEnabled())
- {
- $oLogger = \MailSo\Config::$SystemLogger;
- }
-
- if (!($oLogger instanceof \MailSo\Log\Logger))
- {
- $oLogger = null;
- }
-
- if ($oLogger)
- {
- $oLogger->Write('json_encode: '.\trim(
- (\MailSo\Base\Utils::FunctionExistsAndEnabled('json_last_error') ? ' [Error Code: '.\json_last_error().']' : '').
- (\MailSo\Base\Utils::FunctionExistsAndEnabled('json_last_error_msg') ? ' [Error Message: '.\json_last_error_msg().']' : '')
- ), \MailSo\Log\Enumerations\Type::WARNING, 'JSON'
- );
- }
-
- if (\is_array($mInput))
- {
- if ($oLogger)
- {
- $oLogger->WriteDump($mInput, \MailSo\Log\Enumerations\Type::INFO, 'JSON');
- $oLogger->Write('Trying to clear Utf8 before json_encode', \MailSo\Log\Enumerations\Type::INFO, 'JSON');
- }
-
- \MailSo\Base\Utils::ClearArrayUtf8Values($mInput);
- $sResult = @\json_encode($mInput, $iOpt);
- }
- }
-
- return $sResult;
- }
-
- /**
- * @param string $sFileName
- *
- * @return string
- */
- public static function ClearFileName($sFileName)
- {
- return \MailSo\Base\Utils::Trim(\MailSo\Base\Utils::ClearNullBite(
- \MailSo\Base\Utils::StripSpaces(
- \str_replace(array('"', '/', '\\', '*', '?', '<', '>', '|', ':'), ' ', $sFileName))));
- }
-
- /**
- * @param string $sValue
- *
- * @return string
- */
- public static function ClearXss($sValue)
- {
- return \MailSo\Base\Utils::Trim(\MailSo\Base\Utils::ClearNullBite(
- \str_replace(array('"', '/', '\\', '*', '?', '<', '>', '|', ':'), ' ', $sValue)));
- }
-
- /**
- * @param string $sValue
- *
- * @return string
- */
- public static function Trim($sValue)
- {
- return \trim(\preg_replace('/^[\x00-\x1F]+/u', '',
- \preg_replace('/[\x00-\x1F]+$/u', '', \trim($sValue))));
- }
-
- /**
- * @param string $sDir
- *
- * @return bool
- */
- public static function RecRmDir($sDir)
- {
- if (@\is_dir($sDir))
- {
- $aObjects = \scandir($sDir);
- foreach ($aObjects as $sObject)
- {
- if ('.' !== $sObject && '..' !== $sObject)
- {
-// if ('dir' === \filetype($sDir.'/'.$sObject))
- if (\is_dir($sDir.'/'.$sObject))
- {
- self::RecRmDir($sDir.'/'.$sObject);
- }
- else
- {
- @\unlink($sDir.'/'.$sObject);
- }
- }
- }
-
- return @\rmdir($sDir);
- }
-
- return false;
- }
-
- /**
- * @param string $sSource
- * @param string $sDestination
- */
- public static function CopyDir($sSource, $sDestination)
- {
- if (\is_dir($sSource))
- {
- if (!\is_dir($sDestination))
- {
- \mkdir($sDestination);
- }
-
- $oDirectory = \dir($sSource);
- if ($oDirectory)
- {
- while (false !== ($sRead = $oDirectory->read()))
- {
- if ('.' === $sRead || '..' === $sRead)
- {
- continue;
- }
-
- $sPathDir = $sSource.'/'.$sRead;
- if (\is_dir($sPathDir))
- {
- \MailSo\Base\Utils::CopyDir($sPathDir, $sDestination.'/'.$sRead);
- continue;
- }
-
- \copy($sPathDir, $sDestination.'/'.$sRead);
- }
-
- $oDirectory->close();
- }
- }
- }
-
- /**
- * @param string $sTempPath
- * @param int $iTime2Kill
- * @param int $iNow
- *
- * @return bool
- */
- public static function RecTimeDirRemove($sTempPath, $iTime2Kill, $iNow)
- {
- $iFileCount = 0;
-
- $sTempPath = rtrim($sTempPath, '\\/');
- if (@\is_dir($sTempPath))
- {
- $rDirH = @\opendir($sTempPath);
- if ($rDirH)
- {
- $bRemoveAllDirs = true;
- while (($sFile = @\readdir($rDirH)) !== false)
- {
- if ('.' !== $sFile && '..' !== $sFile)
- {
- if (@\is_dir($sTempPath.'/'.$sFile))
- {
- if (!\MailSo\Base\Utils::RecTimeDirRemove($sTempPath.'/'.$sFile, $iTime2Kill, $iNow))
- {
- $bRemoveAllDirs = false;
- }
- }
- else
- {
- $iFileCount++;
- }
- }
- }
-
- @\closedir($rDirH);
- }
-
- if ($iFileCount > 0)
- {
- if (\MailSo\Base\Utils::TimeFilesRemove($sTempPath, $iTime2Kill, $iNow))
- {
- return @\rmdir($sTempPath);
- }
- }
- else
- {
- return $bRemoveAllDirs ? @\rmdir($sTempPath) : false;
- }
-
- return false;
- }
-
- return true;
- }
-
- /**
- * @param string $sTempPath
- * @param int $iTime2Kill
- * @param int $iNow
- */
- public static function TimeFilesRemove($sTempPath, $iTime2Kill, $iNow)
- {
- $bResult = true;
-
- $sTempPath = rtrim($sTempPath, '\\/');
- if (@\is_dir($sTempPath))
- {
- $rDirH = @\opendir($sTempPath);
- if ($rDirH)
- {
- while (($sFile = @\readdir($rDirH)) !== false)
- {
- if ($sFile !== '.' && $sFile !== '..')
- {
- if ($iNow - \filemtime($sTempPath.'/'.$sFile) > $iTime2Kill)
- {
- @\unlink($sTempPath.'/'.$sFile);
- }
- else
- {
- $bResult = false;
- }
- }
- }
-
- @\closedir($rDirH);
- }
- }
-
- return $bResult;
- }
-
- /**
- * @param string $sUtfString
- * @param int $iLength
- *
- * @return string
- */
- public static function Utf8Truncate($sUtfString, $iLength)
- {
- if (\strlen($sUtfString) <= $iLength)
- {
- return $sUtfString;
- }
-
- while ($iLength >= 0)
- {
- if ((\ord($sUtfString[$iLength]) < 0x80) || (\ord($sUtfString[$iLength]) >= 0xC0))
- {
- return \substr($sUtfString, 0, $iLength);
- }
-
- $iLength--;
- }
-
- return '';
- }
-
- /**
- * @param string $sUtfString
- * @param string $sReplaceOn = ''
- *
- * @return string
- */
- public static function Utf8Clear($sUtfString, $sReplaceOn = '')
- {
- if ('' === $sUtfString)
- {
- return $sUtfString;
- }
-
- $sUtfString = \preg_replace(\MailSo\Base\Utils::$sValidUtf8Regexp, '$1', $sUtfString);
-
- $sUtfString = \preg_replace(
- '/\xE0[\x80-\x9F][\x80-\xBF]'.
- '|\xEF\xBF\xBF'.
- '|\xED[\xA0-\xBF][\x80-\xBF]/S', $sReplaceOn, $sUtfString);
-
- $sUtfString = \preg_replace('/\xEF\xBF\xBD/', '?', $sUtfString);
-
- $sNewUtfString = false;
- if (false === $sNewUtfString && \MailSo\Base\Utils::IsMbStringSupported())
- {
- $sNewUtfString = \MailSo\Base\Utils::MbConvertEncoding($sUtfString, 'UTF-8', 'UTF-8');
- }
-
- if (false === $sNewUtfString && \MailSo\Base\Utils::IsIconvSupported())
- {
- $sNewUtfString = \MailSo\Base\Utils::IconvConvertEncoding($sUtfString, 'UTF-8', 'UTF-8');
- }
-
- if (false !== $sNewUtfString)
- {
- $sUtfString = $sNewUtfString;
- }
-
- return $sUtfString;
- }
-
- /**
- * @param string $sUtfString
- *
- * @return bool
- */
- public static function IsRTL($sUtfString)
- {
- // \x{0591}-\x{05F4} - Hebrew
- // \x{0600}-\x{068F} - Arabic
- // \x{0750}-\x{077F} - Arabic
- // \x{08A0}-\x{08FF} - Arabic
- // \x{103A0}-\x{103DF} - Old Persian
- return 0 < (int) preg_match('/[\x{0591}-\x{05F4}\x{0600}-\x{068F}\x{0750}-\x{077F}\x{08A0}-\x{08FF}\x{103A0}-\x{103DF}]/u', $sUtfString);
- }
-
- /**
- * @param string $sString
- *
- * @return string
- */
- public static function Base64Decode($sString)
- {
- $sResultString = \base64_decode($sString, true);
- if (false === $sResultString)
- {
- $sString = \str_replace(array(' ', "\r", "\n", "\t"), '', $sString);
- $sString = \preg_replace('/[^a-zA-Z0-9=+\/](.*)$/', '', $sString);
-
- if (false !== \strpos(\trim(\trim($sString), '='), '='))
- {
- $sString = \preg_replace('/=([^=])/', '= $1', $sString);
- $aStrings = \explode(' ', $sString);
- foreach ($aStrings as $iIndex => $sParts)
- {
- $aStrings[$iIndex] = \base64_decode($sParts);
- }
-
- $sResultString = \implode('', $aStrings);
- }
- else
- {
- $sResultString = \base64_decode($sString);
- }
- }
-
- return $sResultString;
- }
-
- /**
- * @param string $sValue
- *
- * @return string
- */
- public static function UrlSafeBase64Encode($sValue)
- {
- return \rtrim(\strtr(\base64_encode($sValue), '+/', '-_'), '=');
- }
-
- /**
- * @param string $sValue
- *
- * @return string
- */
- public static function UrlSafeBase64Decode($sValue)
- {
- $sValue = \rtrim(\strtr($sValue, '-_.', '+/='), '=');
- return \MailSo\Base\Utils::Base64Decode(\str_pad($sValue, \strlen($sValue) + (\strlen($sValue) % 4), '=', STR_PAD_RIGHT));
- }
-
- /**
- * @param string $sSequence
- *
- * @return array
- */
- public static function ParseFetchSequence($sSequence)
- {
- $aResult = array();
- $sSequence = \trim($sSequence);
- if (0 < \strlen($sSequence))
- {
- $aSequence = \explode(',', $sSequence);
- foreach ($aSequence as $sItem)
- {
- if (false === \strpos($sItem, ':'))
- {
- $aResult[] = (int) $sItem;
- }
- else
- {
- $aItems = \explode(':', $sItem);
- $iMax = \max($aItems[0], $aItems[1]);
-
- for ($iIndex = $aItems[0]; $iIndex <= $iMax; $iIndex++)
- {
- $aResult[] = (int) $iIndex;
- }
- }
- }
- }
-
- return $aResult;
- }
- /**
- * @param array $aSequence
- *
- * @return string
- */
- public static function PrepearFetchSequence($aSequence)
- {
- $aResult = array();
- if (\is_array($aSequence) && 0 < \count($aSequence))
- {
- $iStart = null;
- $iPrev = null;
-
- foreach ($aSequence as $sItem)
- {
- // simple protection
- if (false !== \strpos($sItem, ':'))
- {
- $aResult[] = $sItem;
- continue;
- }
-
- $iItem = (int) $sItem;
- if (null === $iStart || null === $iPrev)
- {
- $iStart = $iItem;
- $iPrev = $iItem;
- continue;
- }
-
- if ($iPrev === $iItem - 1)
- {
- $iPrev = $iItem;
- }
- else
- {
- $aResult[] = $iStart === $iPrev ? $iStart : $iStart.':'.$iPrev;
- $iStart = $iItem;
- $iPrev = $iItem;
- }
- }
-
- if (null !== $iStart && null !== $iPrev)
- {
- $aResult[] = $iStart === $iPrev ? $iStart : $iStart.':'.$iPrev;
- }
- }
-
- return \implode(',', $aResult);
- }
-
- /**
- *
- * @param resource $fResource
- * @param int $iBufferLen = 8192
- *
- * @return bool
- */
- public static function FpassthruWithTimeLimitReset($fResource, $iBufferLen = 8192)
- {
- $bResult = false;
- if (\is_resource($fResource))
- {
- while (!\feof($fResource))
- {
- $sBuffer = @\fread($fResource, $iBufferLen);
- if (false !== $sBuffer)
- {
- echo $sBuffer;
- \MailSo\Base\Utils::ResetTimeLimit();
- continue;
- }
-
- break;
- }
-
- $bResult = true;
- }
-
- return $bResult;
- }
-
- /**
- * @param resource $rRead
- * @param array $aWrite
- * @param int $iBufferLen = 8192
- * @param bool $bResetTimeLimit = true
- * @param bool $bFixCrLf = false
- * @param bool $bRewindOnComplete = false
- *
- * @return int|bool
- */
- public static function MultipleStreamWriter($rRead, $aWrite, $iBufferLen = 8192, $bResetTimeLimit = true, $bFixCrLf = false, $bRewindOnComplete = false)
- {
- $mResult = false;
- if ($rRead && \is_array($aWrite) && 0 < \count($aWrite))
- {
- $mResult = 0;
- while (!\feof($rRead))
- {
- $sBuffer = \fread($rRead, $iBufferLen);
- if (false === $sBuffer)
- {
- $mResult = false;
- break;
- }
-
- if (0 === $iBufferLen || '' === $sBuffer)
- {
- break;
- }
-
- if ($bFixCrLf)
- {
- $sBuffer = \str_replace("\n", "\r\n", \str_replace("\r", '', $sBuffer));
- }
-
- $mResult += \strlen($sBuffer);
-
- foreach ($aWrite as $rWriteStream)
- {
- $mWriteResult = \fwrite($rWriteStream, $sBuffer);
- if (false === $mWriteResult)
- {
- $mResult = false;
- break 2;
- }
- }
-
- if ($bResetTimeLimit)
- {
- \MailSo\Base\Utils::ResetTimeLimit();
- }
- }
- }
-
- if ($mResult && $bRewindOnComplete)
- {
- foreach ($aWrite as $rWriteStream)
- {
- if (\is_resource($rWriteStream))
- {
- @\rewind($rWriteStream);
- }
- }
- }
-
- return $mResult;
- }
-
- /**
- * @param string $sUtfModifiedString
- *
- * @return string
- */
- public static function ModifiedToPlainUtf7($sUtfModifiedString)
- {
- $sUtf = '';
- $bBase = false;
-
- for ($iIndex = 0, $iLen = \strlen($sUtfModifiedString); $iIndex < $iLen; $iIndex++)
- {
- if ('&' === $sUtfModifiedString[$iIndex])
- {
- if (isset($sUtfModifiedString[$iIndex+1]) && '-' === $sUtfModifiedString[$iIndex + 1])
- {
- $sUtf .= '&';
- $iIndex++;
- }
- else
- {
- $sUtf .= '+';
- $bBase = true;
- }
- }
- else if ($sUtfModifiedString[$iIndex] == '-' && $bBase)
- {
- $bBase = false;
- }
- else
- {
- if ($bBase && ',' === $sUtfModifiedString[$iIndex])
- {
- $sUtf .= '/';
- }
- else if (!$bBase && '+' === $sUtfModifiedString[$iIndex])
- {
- $sUtf .= '+-';
- }
- else
- {
- $sUtf .= $sUtfModifiedString[$iIndex];
- }
- }
- }
-
- return $sUtf;
- }
-
- /**
- * @param string $sStr
- *
- * @return string|bool
- */
- public static function Utf7ModifiedToUtf8($sStr)
- {
- $aArray = array(-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,62, 63,-1,-1,-1,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,
- 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
- 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1);
-
- $sResult = '';
- $bError = false;
- $iLen = \strlen($sStr);
-
- for ($iIndex = 0; $iLen > 0; $iIndex++, $iLen--)
- {
- $sChar = $sStr{$iIndex};
- if ($sChar == '&')
- {
- $iIndex++;
- $iLen--;
-
- $sChar = isset($sStr{$iIndex}) ? $sStr{$iIndex} : null;
- if ($sChar === null)
- {
- break;
- }
-
- if ($iLen && $sChar == '-')
- {
- $sResult .= '&';
- continue;
- }
-
- $iCh = 0;
- $iK = 10;
- for (; $iLen > 0; $iIndex++, $iLen--)
- {
- $sChar = $sStr{$iIndex};
-
- $iB = $aArray[\ord($sChar)];
- if ((\ord($sChar) & 0x80) || $iB == -1)
- {
- break;
- }
-
- if ($iK > 0)
- {
- $iCh |= $iB << $iK;
- $iK -= 6;
- }
- else
- {
- $iCh |= $iB >> (-$iK);
- if ($iCh < 0x80)
- {
- if (0x20 <= $iCh && $iCh < 0x7f)
- {
- return $bError;
- }
-
- $sResult .= \chr($iCh);
- }
- else if ($iCh < 0x800)
- {
- $sResult .= \chr(0xc0 | ($iCh >> 6));
- $sResult .= \chr(0x80 | ($iCh & 0x3f));
- }
- else
- {
- $sResult .= \chr(0xe0 | ($iCh >> 12));
- $sResult .= \chr(0x80 | (($iCh >> 6) & 0x3f));
- $sResult .= \chr(0x80 | ($iCh & 0x3f));
- }
-
- $iCh = ($iB << (16 + $iK)) & 0xffff;
- $iK += 10;
- }
- }
-
- if (($iCh || $iK < 6) ||
- (!$iLen || $sChar != '-') ||
- ($iLen > 2 && '&' === $sStr{$iIndex+1} && '-' !== $sStr{$iIndex+2}))
- {
- return $bError;
- }
- }
- else if (\ord($sChar) < 0x20 || \ord($sChar) >= 0x7f)
- {
- return $bError;
- }
- else
- {
- $sResult .= $sChar;
- }
- }
-
- return $sResult;
- }
-
- /**
- * @param string $sStr
- *
- * @return string|bool
- */
- public static function Utf8ToUtf7Modified($sStr)
- {
- $sArray = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S',
- 'T','U','V','W','X','Y','Z', 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
- 'p','q','r','s','t','u','v','w','x','y','z', '0','1','2','3','4','5','6','7','8','9','+',',');
-
- $sLen = \strlen($sStr);
- $bIsB = false;
- $iIndex = $iN = 0;
- $sReturn = '';
- $bError = false;
- $iCh = $iB = $iK = 0;
-
- while ($sLen)
- {
- $iC = \ord($sStr{$iIndex});
- if ($iC < 0x80)
- {
- $iCh = $iC;
- $iN = 0;
- }
- else if ($iC < 0xc2)
- {
- return $bError;
- }
- else if ($iC < 0xe0)
- {
- $iCh = $iC & 0x1f;
- $iN = 1;
- }
- else if ($iC < 0xf0)
- {
- $iCh = $iC & 0x0f;
- $iN = 2;
- }
- else if ($iC < 0xf8)
- {
- $iCh = $iC & 0x07;
- $iN = 3;
- }
- else if ($iC < 0xfc)
- {
- $iCh = $iC & 0x03;
- $iN = 4;
- }
- else if ($iC < 0xfe)
- {
- $iCh = $iC & 0x01;
- $iN = 5;
- }
- else
- {
- return $bError;
- }
-
- $iIndex++;
- $sLen--;
-
- if ($iN > $sLen)
- {
- return $bError;
- }
-
- for ($iJ = 0; $iJ < $iN; $iJ++)
- {
- $iO = \ord($sStr{$iIndex+$iJ});
- if (($iO & 0xc0) != 0x80)
- {
- return $bError;
- }
-
- $iCh = ($iCh << 6) | ($iO & 0x3f);
- }
-
- if ($iN > 1 && !($iCh >> ($iN * 5 + 1)))
- {
- return $bError;
- }
-
- $iIndex += $iN;
- $sLen -= $iN;
-
- if ($iCh < 0x20 || $iCh >= 0x7f)
- {
- if (!$bIsB)
- {
- $sReturn .= '&';
- $bIsB = true;
- $iB = 0;
- $iK = 10;
- }
-
- if ($iCh & ~0xffff)
- {
- $iCh = 0xfffe;
- }
-
- $sReturn .= $sArray[($iB | $iCh >> $iK)];
- $iK -= 6;
- for (; $iK >= 0; $iK -= 6)
- {
- $sReturn .= $sArray[(($iCh >> $iK) & 0x3f)];
- }
-
- $iB = ($iCh << (-$iK)) & 0x3f;
- $iK += 16;
- }
- else
- {
- if ($bIsB)
- {
- if ($iK > 10)
- {
- $sReturn .= $sArray[$iB];
- }
- $sReturn .= '-';
- $bIsB = false;
- }
-
- $sReturn .= \chr($iCh);
- if ('&' === \chr($iCh))
- {
- $sReturn .= '-';
- }
- }
- }
-
- if ($bIsB)
- {
- if ($iK > 10)
- {
- $sReturn .= $sArray[$iB];
- }
-
- $sReturn .= '-';
- }
-
- return $sReturn;
- }
-
- /**
- * @param string|array $mFunctionNameOrNames
- *
- * @return bool
- */
- public static function FunctionExistsAndEnabled($mFunctionNameOrNames)
- {
- static $aCache = null;
-
- if (\is_array($mFunctionNameOrNames))
- {
- foreach ($mFunctionNameOrNames as $sFunctionName)
- {
- if (!\MailSo\Base\Utils::FunctionExistsAndEnabled($sFunctionName))
- {
- return false;
- }
- }
-
- return true;
- }
-
- if (empty($mFunctionNameOrNames) || !\function_exists($mFunctionNameOrNames) || !\is_callable($mFunctionNameOrNames))
- {
- return false;
- }
-
- if (null === $aCache)
- {
- $sDisableFunctions = @\ini_get('disable_functions');
- $sDisableFunctions = \is_string($sDisableFunctions) && 0 < \strlen($sDisableFunctions) ? $sDisableFunctions : '';
-
- $aCache = \explode(',', $sDisableFunctions);
- $aCache = \is_array($aCache) && 0 < \count($aCache) ? $aCache : array();
-
- if (\extension_loaded('suhosin'))
- {
- $sSuhosin = @\ini_get('suhosin.executor.func.blacklist');
- $sSuhosin = \is_string($sSuhosin) && 0 < \strlen($sSuhosin) ? $sSuhosin : '';
-
- $aSuhosinCache = \explode(',', $sSuhosin);
- $aSuhosinCache = \is_array($aSuhosinCache) && 0 < \count($aSuhosinCache) ? $aSuhosinCache : array();
-
- if (0 < \count($aSuhosinCache))
- {
- $aCache = \array_merge($aCache, $aSuhosinCache);
- $aCache = \array_unique($aCache);
- }
- }
- }
-
- return !\in_array($mFunctionNameOrNames, $aCache);
- }
-
- /**
- * @param string $mValue
- *
- * @return string
- */
- public static function ClearNullBite($mValue)
- {
- return \str_replace('%00', '', $mValue);
- }
-
- /**
- * @param mixed $mValue
- * @param bool $bClearNullBite = false
- *
- * @return mixed
- */
- public static function StripSlashesValue($mValue, $bClearNullBite = false)
- {
- static $bIsMagicQuotesOn = null;
- if (null === $bIsMagicQuotesOn)
- {
- $bIsMagicQuotesOn = (bool) @\ini_get('magic_quotes_gpc');
- }
-
- if (!$bIsMagicQuotesOn)
- {
- return $bClearNullBite && \is_string($mValue) ? \MailSo\Base\Utils::ClearNullBite($mValue) : $mValue;
- }
-
- $sType = \gettype($mValue);
- if ('string' === $sType)
- {
- return \stripslashes($bClearNullBite ? \MailSo\Base\Utils::ClearNullBite($mValue) : $mValue);
- }
- else if ('array' === $sType)
- {
- $aReturnValue = array();
- $mValueKeys = \array_keys($mValue);
- foreach ($mValueKeys as $sKey)
- {
- $aReturnValue[$sKey] = \MailSo\Base\Utils::StripSlashesValue($mValue[$sKey], $bClearNullBite);
- }
-
- return $aReturnValue;
- }
-
- return $mValue;
- }
-
- /**
- * @param string $sStr
- *
- * @return string
- */
- public static function CharsetDetect($sStr)
- {
- $mResult = '';
- if (!\MailSo\Base\Utils::IsAscii($sStr))
- {
- $mResult = \MailSo\Base\Utils::IsMbStringSupported() &&
- \MailSo\Base\Utils::FunctionExistsAndEnabled('mb_detect_encoding') ?
- @\mb_detect_encoding($sStr, 'auto', true) : false;
-
- if (false === $mResult && \MailSo\Base\Utils::IsIconvSupported())
- {
- $mResult = \md5(@\iconv('utf-8', 'utf-8//IGNORE', $sStr)) === \md5($sStr) ? 'utf-8' : '';
- }
- }
-
- return \is_string($mResult) && 0 < \strlen($mResult) ? $mResult : '';
- }
-
- /**
- * @param string $sAdditionalSalt = ''
- *
- * @return string
- */
- public static function Md5Rand($sAdditionalSalt = '')
- {
- return \md5(\microtime(true).\rand(10000, 99999).
- \md5($sAdditionalSalt).\rand(10000, 99999).\microtime(true));
- }
-
- /**
- * @param string $sAdditionalSalt = ''
- *
- * @return string
- */
- public static function Sha1Rand($sAdditionalSalt = '')
- {
- return \sha1(\microtime(true).\rand(10000, 99999).
- \sha1($sAdditionalSalt).\rand(10000, 99999).\microtime(true));
- }
-
- /**
- * @param string $sData
- * @param string $sKey
- *
- * @return string
- */
- public static function Hmac($sData, $sKey)
- {
- if (\function_exists('hash_hmac'))
- {
- return \hash_hmac('md5', $sData, $sKey);
- }
-
- $iLen = 64;
- if ($iLen < \strlen($sKey))
- {
- $sKey = \pack('H*', \md5($sKey));
- }
-
- $sKey = \str_pad($sKey, $iLen, \chr(0x00));
- $sIpad = \str_pad('', $iLen, \chr(0x36));
- $sOpad = \str_pad('', $iLen, \chr(0x5c));
-
- return \md5(($sKey ^ $sOpad).\pack('H*', \md5(($sKey ^ $sIpad).$sData)));
- }
-
- /**
- * @param string $sDomain
- * @param bool $bSimple = false
- *
- * @return bool
- */
- public static function ValidateDomain($sDomain, $bSimple = false)
- {
- $aMatch = array();
- if ($bSimple)
- {
- return \preg_match('/.+(\.[a-zA-Z]+)$/', $sDomain, $aMatch) && !empty($aMatch[1]);
- }
-
- return \preg_match('/.+(\.[a-zA-Z]+)$/', $sDomain, $aMatch) && !empty($aMatch[1]) && \in_array($aMatch[1], \explode(' ',
- '.academy .actor .agency .audio .bar .beer .bike .blue .boutique .cab .camera .camp .capital .cards .careers .cash .catering .center .cheap .city .cleaning .clinic .clothing .club .coffee .community .company .computer .construction .consulting .contractors .cool .credit .dance .dating .democrat .dental .diamonds .digital .direct .directory .discount .domains .education .email .energy .equipment .estate .events .expert .exposed .fail .farm .fish .fitness .florist .fund .futbol .gallery .gift .glass .graphics .guru .help .holdings .holiday .host .hosting .house .institute .international .kitchen .land .life .lighting .limo .link .management .market .marketing .media .menu .moda .partners .parts .photo .photography .photos .pics .pink .press .productions .pub .red .rentals .repair .report .rest .sexy .shoes .social .solar .solutions .space .support .systems .tattoo .tax .technology .tips .today .tools .town .toys .trade .training .university .uno .vacations .vision .vodka .voyage .watch .webcam .wiki .work .works .wtf .zone .aero .asia .biz .cat .com .coop .edu .gov .info .int .jobs .mil .mobi .museum .name .net .org .pro .tel .travel .xxx .xyz '.
- '.ac .ad .ae .af .ag .ai .al .am .an .ao .aq .ar .as .at .au .aw .ax .az .ba .bb .bd .be .bf .bg .bh .bi .bj .bm .bn .bo .br .bs .bt .bv .bw .by .bz .ca .cc .cd .cf .cg .ch .ci .ck .cl .cm .cn .co .cr .cs .cu .cv .cx .cy .cz .dd .de .dj .dk .dm .do .dz .ec .ee .eg .er .es .et .eu .fi .fj .fk .fm .fo .fr .ga .gb .gd .ge .gf .gg .gh .gi .gl .gm .gn .gp .gq .gr .gs .gt .gu .gw .gy .hk .hm .hn .hr .ht .hu .id .ie .il .im .in .io .iq .ir .is .it .je .jm .jo .jp .ke .kg .kh .ki .km .kn .kp .kr .kw .ky .kz .la .lb .lc .li .lk .lr .ls .lt .lu .lv .ly .ma .mc .md .me .mg .mh .mk .ml .mm .mn .mo .mp .mq .mr .ms .mt .mu .mv .mw .mx .my .mz .na .nc .ne .nf .ng .ni .nl .no .np .nr .nu .nz .om .pa .pe .pf .pg .ph .pk .pl .pm .pn .pr .ps .pt .pw .py .qa .re .ro .rs .ru . .rw .sa .sb .sc .sd .se .sg .sh .si .sj .sk .sl .sm .sn .so .sr .st .su .sv .sy .sz .tc .td .tf .tg .th .tj .tk .tl .tm .tn .to .tp .tr .tt .tv .tw .tz .ua .ug .uk .us .uy .uz .va .vc .ve .vg .vi .vn .vu .wf .ws .ye .yt .za .zm .zw'
- ));
- }
-
- /**
- * @param string $sIp
- *
- * @return bool
- */
- public static function ValidateIP($sIp)
- {
- return !empty($sIp) && $sIp === @\filter_var($sIp, FILTER_VALIDATE_IP);
- }
-
- /**
- * @return \Net_IDNA2
- */
- private static function idn()
- {
- static $oIdn = null;
- if (null === $oIdn)
- {
- include_once MAILSO_LIBRARY_ROOT_PATH.'Vendors/Net/IDNA2.php';
- $oIdn = new \Net_IDNA2();
- $oIdn->setParams('utf8', true);
- }
-
- return $oIdn;
- }
-
- /**
- * @param string $sStr
- * @param bool $bLowerIfAscii = false
- *
- * @return string
- */
- public static function IdnToUtf8($sStr, $bLowerIfAscii = false)
- {
- if (0 < \strlen($sStr) && \preg_match('/(^|\.|@)xn--/i', $sStr))
- {
- try
- {
- $sStr = self::idn()->decode($sStr);
- }
- catch (\Exception $oException) {}
- }
-
- return $bLowerIfAscii ? \MailSo\Base\Utils::StrMailDomainToLowerIfAscii($sStr) : $sStr;
- }
-
- /**
- * @param string $sStr
- * @param bool $bLowerIfAscii = false
- *
- * @return string
- */
- public static function IdnToAscii($sStr, $bLowerIfAscii = false)
- {
- $sStr = $bLowerIfAscii ? \MailSo\Base\Utils::StrMailDomainToLowerIfAscii($sStr) : $sStr;
-
- $sUser = '';
- $sDomain = $sStr;
- if (false !== \strpos($sStr, '@'))
- {
- $sUser = \MailSo\Base\Utils::GetAccountNameFromEmail($sStr);
- $sDomain = \MailSo\Base\Utils::GetDomainFromEmail($sStr);
- }
-
- if (0 < \strlen($sDomain) && \preg_match('/[^\x20-\x7E]/', $sDomain))
- {
- try
- {
- $sDomain = self::idn()->encode($sDomain);
- }
- catch (\Exception $oException) {}
- }
-
- return ('' === $sUser ? '' : $sUser.'@').$sDomain;
- }
-
- /**
- * @param string $sHash
- * @param string $sSalt
- *
- * @return int
- */
- public static function HashToId($sHash, $sSalt = '')
- {
- $sData = $sHash ? @\MailSo\Base\Crypt::XxteaDecrypt(\hex2bin($sHash), \md5($sSalt)) : null;
-
- $aMatch = array();
- if ($sData && preg_match('/^id:(\d+)$/', $sData, $aMatch) && isset($aMatch[1]))
- {
- return is_numeric($aMatch[1]) ? (int) $aMatch[1] : null;
- }
-
- return null;
- }
-
- /**
- * @param int $iID
- * @param string $sSalt
- *
- * @return string
- */
- public static function IdToHash($iID, $sSalt = '')
- {
- return is_int($iID) ?
- \bin2hex(\MailSo\Base\Crypt::XxteaEncrypt('id:'.$iID, \md5($sSalt))) : null
- ;
- }
-
- /**
- * @param string $sPassword
- *
- * @return bool
- */
- public static function PasswordWeaknessCheck($sPassword)
- {
- $sPassword = \trim($sPassword);
- if (6 > \strlen($sPassword))
- {
- return false;
- }
-
- $sLine = 'password 123.456 12345678 abc123 qwerty monkey letmein dragon 111.111 baseball iloveyou trustno1 1234567 sunshine master 123.123 welcome shadow ashley football jesus michael ninja mustang password1 123456 123456789 qwerty 111111 1234567 666666 12345678 7777777 123321 654321 1234567890 123123 555555 vkontakte gfhjkm 159753 777777 temppassword qazwsx 1q2w3e 1234 112233 121212 qwertyuiop qq18ww899 987654321 12345 zxcvbn zxcvbnm 999999 samsung ghbdtn 1q2w3e4r 1111111 123654 159357 131313 qazwsxedc 123qwe 222222 asdfgh 333333 9379992 asdfghjkl 4815162342 12344321 88888888 11111111 knopka 789456 qwertyu 1q2w3e4r5t iloveyou vfhbyf marina password qweasdzxc 10203 987654 yfnfif cjkysirj nikita 888888 vfrcbv k.,jdm qwertyuiop[] qwe123 qweasd natasha 123123123 fylhtq q1w2e3 stalker 1111111111 q1w2e3r4 nastya 147258369 147258 fyfcnfcbz 1234554321 1qaz2wsx andrey 111222 147852 genius sergey 7654321 232323 123789 fktrcfylh spartak admin test 123 azerty abc123 lol123 easytocrack1 hello saravn holysh!t test123 tundra_cool2 456 dragon thomas killer root 1111 pass master aaaaaa a monkey daniel asdasd e10adc3949ba59abbe56e057f20f883e changeme computer jessica letmein mirage loulou lol superman shadow admin123 secret administrator sophie kikugalanetroot doudou liverpool hallo sunshine charlie parola 100827092 michael andrew password1 fuckyou matrix cjmasterinf internet hallo123 eminem demo gewinner pokemon abcd1234 guest ngockhoa martin sandra asdf hejsan george qweqwe lollipop lovers q1q1q1 tecktonik naruto 12 password12 password123 password1234 password12345 password123456 password1234567 password12345678 password123456789 000000 maximius 123abc baseball1 football1 soccer princess slipknot 11111 nokia super star 666999 12341234 1234321 135790 159951 212121 zzzzzz 121314 134679 142536 19921992 753951 7007 1111114 124578 19951995 258456 qwaszx zaqwsx 55555 77777 54321 qwert 22222 33333 99999 88888 66666';
- return false === \strpos($sLine, \strtolower($sPassword));
- }
-}
+ 'utf-8',
+ '.20127' => 'iso-8859-1',
+
+ '.1250' => 'windows-1250',
+ '.cp1250' => 'windows-1250',
+ '.cp-1250' => 'windows-1250',
+ '.1251' => 'windows-1251',
+ '.cp1251' => 'windows-1251',
+ '.cp-1251' => 'windows-1251',
+ '.1252' => 'windows-1252',
+ '.cp1252' => 'windows-1252',
+ '.cp-1252' => 'windows-1252',
+ '.1253' => 'windows-1253',
+ '.cp1253' => 'windows-1253',
+ '.cp-1253' => 'windows-1253',
+ '.1254' => 'windows-1254',
+ '.cp1254' => 'windows-1254',
+ '.cp-1254' => 'windows-1254',
+ '.1255' => 'windows-1255',
+ '.cp1255' => 'windows-1255',
+ '.cp-1255' => 'windows-1255',
+ '.1256' => 'windows-1256',
+ '.cp1256' => 'windows-1256',
+ '.cp-1256' => 'windows-1256',
+ '.1257' => 'windows-1257',
+ '.cp1257' => 'windows-1257',
+ '.cp-1257' => 'windows-1257',
+ '.1258' => 'windows-1258',
+ '.cp1258' => 'windows-1258',
+ '.cp-1258' => 'windows-1258',
+
+ '.28591' => 'iso-8859-1',
+ '.28592' => 'iso-8859-2',
+ '.28593' => 'iso-8859-3',
+ '.28594' => 'iso-8859-4',
+ '.28595' => 'iso-8859-5',
+ '.28596' => 'iso-8859-6',
+ '.28597' => 'iso-8859-7',
+ '.28598' => 'iso-8859-8',
+ '.28599' => 'iso-8859-9',
+ '.28603' => 'iso-8859-13',
+ '.28605' => 'iso-8859-15',
+
+ '.1125' => 'cp1125',
+ '.20866' => 'koi8-r',
+ '.21866' => 'koi8-u',
+ '.950' => 'big5',
+ '.936' => 'euc-cn',
+ '.20932' => 'euc-js',
+ '.949' => 'euc-kr',
+ );
+
+ /**
+ * @access private
+ */
+ private function __construct()
+ {
+ }
+
+ /**
+ * @return string
+ */
+ public static function DetectSystemCharset()
+ {
+ $sResult = '';
+ $sLocale = @\setlocale(LC_ALL, '');
+ $sLocaleLower = \strtolower(\trim($sLocale));
+
+ foreach (\MailSo\Base\Utils::$aLocaleMapping as $sKey => $sValue)
+ {
+ if (false !== \strpos($sLocaleLower, $sKey) ||
+ false !== \strpos($sLocaleLower, '.'.$sValue))
+ {
+ $sResult = $sValue;
+ break;
+ }
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @return string
+ */
+ public static function ConvertSystemString($sSrt)
+ {
+ $sSrt = \trim($sSrt);
+ if (!empty($sSrt) && !\MailSo\Base\Utils::IsUtf8($sSrt))
+ {
+ $sCharset = \MailSo\Base\Utils::DetectSystemCharset();
+ if (!empty($sCharset))
+ {
+ $sSrt = \MailSo\Base\Utils::ConvertEncoding(
+ $sSrt, $sCharset, \MailSo\Base\Enumerations\Charset::UTF_8);
+ }
+ else
+ {
+ $sSrt = @\utf8_encode($sSrt);
+ }
+ }
+
+ return $sSrt;
+ }
+
+ /**
+ * @param string $sEncoding
+ * @param bool $bAsciAsUtf8 = false
+ *
+ * @return string
+ */
+ public static function NormalizeCharset($sEncoding, $bAsciAsUtf8 = false)
+ {
+ $sEncoding = \strtolower($sEncoding);
+
+ $sEncoding = \preg_replace('/^iso8/', 'iso-8', $sEncoding);
+ $sEncoding = \preg_replace('/^cp-([\d])/', 'cp$1', $sEncoding);
+ $sEncoding = \preg_replace('/^windows?12/', 'windows-12', $sEncoding);
+
+ switch ($sEncoding)
+ {
+ case 'asci':
+ case 'ascii':
+ case 'us-asci':
+ case 'us-ascii':
+ $sEncoding = $bAsciAsUtf8 ? \MailSo\Base\Enumerations\Charset::UTF_8 :
+ \MailSo\Base\Enumerations\Charset::ISO_8859_1;
+ break;
+ case 'unicode-1-1-utf-7':
+ case 'unicode-1-utf-7':
+ case 'unicode-utf-7':
+ $sEncoding = \MailSo\Base\Enumerations\Charset::UTF_7;
+ break;
+ case 'utf8':
+ case 'utf-8':
+ $sEncoding = \MailSo\Base\Enumerations\Charset::UTF_8;
+ break;
+ case 'utf7imap':
+ case 'utf-7imap':
+ case 'utf7-imap':
+ case 'utf-7-imap':
+ $sEncoding = \MailSo\Base\Enumerations\Charset::UTF_7_IMAP;
+ break;
+ case 'ks-c-5601-1987':
+ case 'ks_c_5601-1987':
+ case 'ks_c_5601_1987':
+ $sEncoding = 'euc-kr';
+ break;
+ case 'x-gbk':
+ $sEncoding = 'gb2312';
+ break;
+ case 'iso-8859-i':
+ case 'iso-8859-8-i':
+ $sEncoding = \MailSo\Base\Enumerations\Charset::ISO_8859_8;
+ break;
+ }
+
+ return $sEncoding;
+ }
+
+ /**
+ * @param string $sCharset
+ * @param string $sValue
+ *
+ * @return string
+ */
+ public static function NormalizeCharsetByValue($sCharset, $sValue)
+ {
+ $sCharset = \MailSo\Base\Utils::NormalizeCharset($sCharset);
+
+ if (\MailSo\Base\Enumerations\Charset::UTF_8 !== $sCharset &&
+ \MailSo\Base\Utils::IsUtf8($sValue) &&
+ false === \strpos($sCharset, \MailSo\Base\Enumerations\Charset::ISO_2022_JP)
+ )
+ {
+ $sCharset = \MailSo\Base\Enumerations\Charset::UTF_8;
+ }
+
+ return $sCharset;
+ }
+
+ /**
+ * @param string $sFilePath
+ * @param function $fFileExistsCallback = null
+ *
+ * @return string
+ */
+ public static function SmartFileExists($sFilePath, $fFileExistsCallback = null)
+ {
+ $sFilePath = \str_replace('\\', '/', \trim($sFilePath));
+ if (!$fFileExistsCallback)
+ {
+ $fFileExistsCallback = function ($sPath) {
+ return \file_exists($sPath);
+ };
+ }
+
+ if (!\call_user_func($fFileExistsCallback, $sFilePath))
+ {
+ return $sFilePath;
+ }
+
+ $aFileInfo = \pathinfo($sFilePath);
+
+ $iIndex = 0;
+
+ do
+ {
+ $iIndex++;
+
+ $sFilePathNew = $aFileInfo['dirname'].'/'.
+ \preg_replace('/\(\d{1,2}\)$/', '', $aFileInfo['filename']).
+ ' ('.$iIndex.')'.
+ (empty($aFileInfo['extension']) ? '' : '.'.$aFileInfo['extension'])
+ ;
+
+ if (!\call_user_func($fFileExistsCallback, $sFilePathNew))
+ {
+ $sFilePath = $sFilePathNew;
+ break;
+ }
+ else if (10 < $iIndex)
+ {
+ break;
+ }
+ }
+ while (true);
+
+ return $sFilePath;
+ }
+
+ /**
+ * @return bool
+ */
+ public static function IsMbStringSupported()
+ {
+ return \MailSo\Config::$MBSTRING &&
+ \MailSo\Base\Utils::FunctionExistsAndEnabled('mb_convert_encoding');
+ }
+
+ /**
+ * @return bool
+ */
+ public static function IsIconvSupported()
+ {
+ return \MailSo\Config::$ICONV &&
+ \MailSo\Base\Utils::FunctionExistsAndEnabled('iconv');
+ }
+
+ /**
+ * @return bool
+ */
+ public static function IsIconvIgnoreSupported()
+ {
+ static $bCache = null;
+ if (null !== $bCache)
+ {
+ return $bCache;
+ }
+
+ $bCache = false;
+ if (\MailSo\Base\Utils::IsIconvSupported())
+ {
+ if (false !== @\iconv('', '//IGNORE', ''))
+ {
+ $bCache = true;
+ }
+ }
+
+ return $bCache;
+ }
+
+ /**
+ * @return bool
+ */
+ public static function IsIconvTranslitSupported()
+ {
+ static $bCache = null;
+ if (null !== $bCache)
+ {
+ return $bCache;
+ }
+
+ $bCache = false;
+ if (\MailSo\Base\Utils::IsIconvSupported())
+ {
+ if (false !== @\iconv('', '//TRANSLIT', ''))
+ {
+ $bCache = true;
+ }
+ }
+
+ return $bCache;
+ }
+
+ /**
+ * @param string $sCharset
+ *
+ * @return bool
+ */
+ public static function ValidateCharsetName($sCharset)
+ {
+ $sCharset = \strtolower(\MailSo\Base\Utils::NormalizeCharset($sCharset));
+ return 0 < \strlen($sCharset) && (\in_array($sCharset, array(\MailSo\Base\Enumerations\Charset::UTF_7_IMAP)) ||
+ \in_array($sCharset, \MailSo\Base\Utils::$SuppostedCharsets));
+ }
+
+ /**
+ * @param string $sInputString
+ * @param string $sInputFromEncoding
+ * @param string $sInputToEncoding
+ *
+ * @return string|bool
+ */
+ public static function IconvConvertEncoding($sInputString, $sInputFromEncoding, $sInputToEncoding)
+ {
+ $sIconvOptions = '';
+ if (\MailSo\Base\Utils::IsIconvIgnoreSupported())
+ {
+ $sIconvOptions .= '//IGNORE';
+ }
+// if (\MailSo\Base\Utils::IsIconvTranslitSupported())
+// {
+// $sIconvOptions .= '//TRANSLIT';
+// }
+
+ $mResult = @\iconv(\strtoupper($sInputFromEncoding), \strtoupper($sInputToEncoding).$sIconvOptions, $sInputString);
+ if (false === $mResult)
+ {
+ if (\MailSo\Log\Logger::IsSystemEnabled())
+ {
+ \MailSo\Log\Logger::SystemLog(array(
+ 'inc' => \strtoupper($sInputFromEncoding),
+ 'out' => \strtoupper($sInputToEncoding).$sIconvOptions,
+ 'val' => 500 < \strlen($sInputString) ? \substr($sInputString, 0, 500) : $sInputString,
+ 'hex' => 500 < \strlen($sInputString) ? '-- to long --' : \bin2hex($sInputString)
+ ), \MailSo\Log\Enumerations\Type::NOTICE);
+ }
+
+ if (\MailSo\Config::$FixIconvByMbstring && \MailSo\Base\Utils::IsMbStringSupported())
+ {
+ $mResult = \MailSo\Base\Utils::MbConvertEncoding($sInputString, $sInputFromEncoding, $sInputToEncoding);
+ }
+ }
+ return $mResult;
+ }
+
+ /**
+ * @param string $sInputString
+ * @param string $sInputFromEncoding
+ * @param string $sInputToEncoding
+ *
+ * @return string|bool
+ */
+ public static function MbConvertEncoding($sInputString, $sInputFromEncoding, $sInputToEncoding)
+ {
+ static $sMbstringSubCh = null;
+ if (null === $sMbstringSubCh)
+ {
+ $sMbstringSubCh = \mb_substitute_character();
+ }
+
+ \mb_substitute_character('none');
+ $sResult = @\mb_convert_encoding($sInputString, \strtoupper($sInputToEncoding), \strtoupper($sInputFromEncoding));
+ \mb_substitute_character($sMbstringSubCh);
+
+ return $sResult;
+ }
+
+ /**
+ * @param string $sInputString
+ * @param string $sInputFromEncoding
+ * @param string $sInputToEncoding
+ *
+ * @return string
+ */
+ public static function ConvertEncoding($sInputString, $sInputFromEncoding, $sInputToEncoding)
+ {
+ $sResult = $sInputString;
+
+ $sFromEncoding = \MailSo\Base\Utils::NormalizeCharset($sInputFromEncoding);
+ $sToEncoding = \MailSo\Base\Utils::NormalizeCharset($sInputToEncoding);
+
+ if ('' === \trim($sResult) || ($sFromEncoding === $sToEncoding && \MailSo\Base\Enumerations\Charset::UTF_8 !== $sFromEncoding))
+ {
+ return $sResult;
+ }
+
+ $bUnknown = false;
+ switch (true)
+ {
+ default:
+ $bUnknown = true;
+ break;
+
+ case ($sFromEncoding === \MailSo\Base\Enumerations\Charset::ISO_8859_1 &&
+ $sToEncoding === \MailSo\Base\Enumerations\Charset::UTF_8 &&
+ \function_exists('utf8_encode')):
+
+ $sResult = \utf8_encode($sResult);
+ break;
+
+ case ($sFromEncoding === \MailSo\Base\Enumerations\Charset::UTF_8 &&
+ $sToEncoding === \MailSo\Base\Enumerations\Charset::ISO_8859_1 &&
+ \function_exists('utf8_decode')):
+
+ $sResult = \utf8_decode($sResult);
+ break;
+
+ case ($sFromEncoding === \MailSo\Base\Enumerations\Charset::UTF_7_IMAP &&
+ $sToEncoding === \MailSo\Base\Enumerations\Charset::UTF_8):
+
+ $sResult = \MailSo\Base\Utils::Utf7ModifiedToUtf8($sResult);
+ if (false === $sResult)
+ {
+ $sResult = $sInputString;
+ }
+ break;
+
+ case ($sFromEncoding === \MailSo\Base\Enumerations\Charset::UTF_8 &&
+ $sToEncoding === \MailSo\Base\Enumerations\Charset::UTF_7_IMAP):
+
+ $sResult = \MailSo\Base\Utils::Utf8ToUtf7Modified($sResult);
+ if (false === $sResult)
+ {
+ $sResult = $sInputString;
+ }
+ break;
+
+ case ($sFromEncoding === \MailSo\Base\Enumerations\Charset::UTF_7_IMAP):
+
+ $sResult = \MailSo\Base\Utils::ConvertEncoding(
+ \MailSo\Base\Utils::ModifiedToPlainUtf7($sResult),
+ \MailSo\Base\Enumerations\Charset::UTF_7,
+ $sToEncoding
+ );
+ break;
+
+ case (\in_array(\strtolower($sFromEncoding), \MailSo\Base\Utils::$SuppostedCharsets)):
+
+ if (\MailSo\Base\Utils::IsIconvSupported())
+ {
+ $sResult = \MailSo\Base\Utils::IconvConvertEncoding($sResult, $sFromEncoding, $sToEncoding);
+ }
+ else if (\MailSo\Base\Utils::IsMbStringSupported())
+ {
+ $sResult = \MailSo\Base\Utils::MbConvertEncoding($sResult, $sFromEncoding, $sToEncoding);
+ }
+
+ $sResult = (false !== $sResult) ? $sResult : $sInputString;
+ break;
+ }
+
+ if ($bUnknown && \MailSo\Base\Utils::IsMbStringSupported())
+ {
+ $sResult = @\mb_convert_encoding($sResult, $sToEncoding);
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @param string $sValue
+ *
+ * @return bool
+ */
+ public static function IsAscii($sValue)
+ {
+ if ('' === \trim($sValue))
+ {
+ return true;
+ }
+
+ return !\preg_match('/[^\x09\x10\x13\x0A\x0D\x20-\x7E]/', $sValue);
+ }
+
+ /**
+ * @param string $sValue
+ *
+ * @return string
+ */
+ public static function StrToLowerIfAscii($sValue)
+ {
+ return \MailSo\Base\Utils::IsAscii($sValue) ? \strtolower($sValue) : $sValue;
+ }
+
+ /**
+ * @param string $sValue
+ *
+ * @return string
+ */
+ public static function StrToUpperIfAscii($sValue)
+ {
+ return \MailSo\Base\Utils::IsAscii($sValue) ? \strtoupper($sValue) : $sValue;
+ }
+
+ /**
+ * @param string $sValue
+ *
+ * @return string
+ */
+ public static function StrMailDomainToLowerIfAscii($sValue)
+ {
+ $aParts = \explode('@', $sValue, 2);
+ if (!empty($aParts[1]))
+ {
+ $aParts[1] = \MailSo\Base\Utils::IsAscii($aParts[1]) ? \strtolower($aParts[1]) : $aParts[1];
+ }
+
+ return \implode('@', $aParts);
+ }
+
+ /**
+ * @param string $sValue
+ *
+ * @return string
+ */
+ public static function StripSpaces($sValue)
+ {
+ return \MailSo\Base\Utils::Trim(
+ \preg_replace('/[\s]+/u', ' ', $sValue));
+ }
+
+ /**
+ * @param string $sValue
+ *
+ * @return bool
+ */
+ public static function IsUtf8($sValue)
+ {
+ return (bool) (\function_exists('mb_check_encoding') ?
+ \mb_check_encoding($sValue, 'UTF-8') : \preg_match('//u', $sValue));
+ }
+
+ /**
+ * @param int $iSize
+ * @param int $iRound
+ *
+ * @return string
+ */
+ public static function FormatFileSize($iSize, $iRound = 0)
+ {
+ $aSizes = array('B', 'KB', 'MB');
+ for ($iIndex = 0; $iSize > 1024 && isset($aSizes[$iIndex + 1]); $iIndex++)
+ {
+ $iSize /= 1024;
+ }
+ return \round($iSize, $iRound).$aSizes[$iIndex];
+ }
+
+ /**
+ * @param string $sEncodedValue
+ * @param string $sEncodeingType
+ *
+ * @return string
+ */
+ public static function DecodeEncodingValue($sEncodedValue, $sEncodeingType)
+ {
+ $sResult = $sEncodedValue;
+ switch (\strtolower($sEncodeingType))
+ {
+ case 'q':
+ case 'quoted_printable':
+ case 'quoted-printable':
+ $sResult = \quoted_printable_decode($sResult);
+ break;
+ case 'b':
+ case 'base64':
+ $sResult = \MailSo\Base\Utils::Base64Decode($sResult);
+ break;
+ }
+ return $sResult;
+ }
+
+ /**
+ * @param string $sInputValue
+ *
+ * @return string
+ */
+ public static function DecodeFlowedFormat($sInputValue)
+ {
+ return \preg_replace('/ ([\r]?[\n])/m', ' ', $sInputValue);
+ }
+
+ /**
+ * @param string $sEncodedValue
+ * @param string $sIncomingCharset = ''
+ * @param string $sForcedIncomingCharset = ''
+ *
+ * @return string
+ */
+ public static function DecodeHeaderValue($sEncodedValue, $sIncomingCharset = '', $sForcedIncomingCharset = '')
+ {
+ $sValue = $sEncodedValue;
+ if (0 < \strlen($sIncomingCharset))
+ {
+ $sIncomingCharset = \MailSo\Base\Utils::NormalizeCharsetByValue($sIncomingCharset, $sValue);
+
+ $sValue = \MailSo\Base\Utils::ConvertEncoding($sValue, $sIncomingCharset,
+ \MailSo\Base\Enumerations\Charset::UTF_8);
+ }
+
+ $sValue = \preg_replace('/\?=[\n\r\t\s]{1,5}=\?/m', '?==?', $sValue);
+ $sValue = \preg_replace('/[\r\n\t]+/m', ' ', $sValue);
+
+ $aEncodeArray = array('');
+ $aMatch = array();
+// \preg_match_all('/=\?[^\?]+\?[q|b|Q|B]\?[^\?]*?\?=/', $sValue, $aMatch);
+ \preg_match_all('/=\?[^\?]+\?[q|b|Q|B]\?.*?\?=/', $sValue, $aMatch);
+
+ if (isset($aMatch[0]) && \is_array($aMatch[0]))
+ {
+ for ($iIndex = 0, $iLen = \count($aMatch[0]); $iIndex < $iLen; $iIndex++)
+ {
+ if (isset($aMatch[0][$iIndex]))
+ {
+ $iPos = @\strpos($aMatch[0][$iIndex], '*');
+ if (false !== $iPos)
+ {
+ $aMatch[0][$iIndex][0] = \substr($aMatch[0][$iIndex][0], 0, $iPos);
+ }
+ }
+ }
+
+ $aEncodeArray = $aMatch[0];
+ }
+
+ $aParts = array();
+
+ $sMainCharset = '';
+ $bOneCharset = true;
+
+ for ($iIndex = 0, $iLen = \count($aEncodeArray); $iIndex < $iLen; $iIndex++)
+ {
+ $aTempArr = array('', $aEncodeArray[$iIndex]);
+ if ('=?' === \substr(\trim($aTempArr[1]), 0, 2))
+ {
+ $iPos = \strpos($aTempArr[1], '?', 2);
+ $aTempArr[0] = \substr($aTempArr[1], 2, $iPos - 2);
+ $sEncType = \strtoupper($aTempArr[1]{$iPos + 1});
+ switch ($sEncType)
+ {
+ case 'Q':
+ $sHeaderValuePart = \str_replace('_', ' ', $aTempArr[1]);
+ $aTempArr[1] = \quoted_printable_decode(\substr(
+ $sHeaderValuePart, $iPos + 3, \strlen($sHeaderValuePart) - $iPos - 5));
+ break;
+ case 'B':
+ $sHeaderValuePart = $aTempArr[1];
+ $aTempArr[1] = \MailSo\Base\Utils::Base64Decode(\substr(
+ $sHeaderValuePart, $iPos + 3, \strlen($sHeaderValuePart) - $iPos - 5));
+ break;
+ }
+ }
+
+ if (0 < \strlen($aTempArr[0]))
+ {
+ $sCharset = 0 === \strlen($sForcedIncomingCharset) ? $aTempArr[0] : $sForcedIncomingCharset;
+ $sCharset = \MailSo\Base\Utils::NormalizeCharset($sCharset, true);
+
+ if ('' === $sMainCharset)
+ {
+ $sMainCharset = $sCharset;
+ }
+ else if ($sMainCharset !== $sCharset)
+ {
+ $bOneCharset = false;
+ }
+ }
+
+ $aParts[] = array(
+ $aEncodeArray[$iIndex],
+ $aTempArr[1],
+ $sCharset
+ );
+
+ unset($aTempArr);
+ }
+
+ for ($iIndex = 0, $iLen = \count($aParts); $iIndex < $iLen; $iIndex++)
+ {
+ if ($bOneCharset)
+ {
+ $sValue = \str_replace($aParts[$iIndex][0], $aParts[$iIndex][1], $sValue);
+ }
+ else
+ {
+ $aParts[$iIndex][2] = \MailSo\Base\Utils::NormalizeCharsetByValue($aParts[$iIndex][2], $aParts[$iIndex][1]);
+
+ $sValue = \str_replace($aParts[$iIndex][0],
+ \MailSo\Base\Utils::ConvertEncoding($aParts[$iIndex][1], $aParts[$iIndex][2], \MailSo\Base\Enumerations\Charset::UTF_8),
+ $sValue);
+ }
+ }
+
+ if ($bOneCharset && 0 < \strlen($sMainCharset))
+ {
+ $sMainCharset = \MailSo\Base\Utils::NormalizeCharsetByValue($sMainCharset, $sValue);
+ $sValue = \MailSo\Base\Utils::ConvertEncoding($sValue, $sMainCharset, \MailSo\Base\Enumerations\Charset::UTF_8);
+ }
+
+ return $sValue;
+ }
+
+ /**
+ * @param string $sIncHeaders
+ * @param string $aHeadersToRemove = array()
+ *
+ * @return string
+ */
+ public static function RemoveHeaderFromHeaders($sIncHeaders, $aHeadersToRemove = array())
+ {
+ $sResultHeaders = $sIncHeaders;
+
+ if (\is_array($aHeadersToRemove) && 0 < \count($aHeadersToRemove))
+ {
+ $aHeadersToRemove = \array_map('strtolower', $aHeadersToRemove);
+
+ $sIncHeaders = \preg_replace('/[\r\n]+/', "\n", $sIncHeaders);
+ $aHeaders = \explode("\n", $sIncHeaders);
+
+ $bSkip = false;
+ $aResult = array();
+
+ foreach ($aHeaders as $sLine)
+ {
+ if (0 < \strlen($sLine))
+ {
+ $sFirst = \substr($sLine,0,1);
+ if (' ' === $sFirst || "\t" === $sFirst)
+ {
+ if (!$bSkip)
+ {
+ $aResult[] = $sLine;
+ }
+ }
+ else
+ {
+ $bSkip = false;
+ $aParts = \explode(':', $sLine, 2);
+
+ if (!empty($aParts) && !empty($aParts[0]))
+ {
+ if (\in_array(\strtolower(\trim($aParts[0])), $aHeadersToRemove))
+ {
+ $bSkip = true;
+ }
+ else
+ {
+ $aResult[] = $sLine;
+ }
+ }
+ }
+ }
+ }
+
+ $sResultHeaders = \implode("\r\n", $aResult);
+ }
+
+ return $sResultHeaders;
+ }
+
+ /**
+ * @param string $sEncodeType
+ * @param string $sValue
+ *
+ * @return string
+ */
+ public static function EncodeUnencodedValue($sEncodeType, $sValue)
+ {
+ $sValue = \trim($sValue);
+ if (0 < \strlen($sValue) && !\MailSo\Base\Utils::IsAscii($sValue))
+ {
+ switch (\strtoupper($sEncodeType))
+ {
+ case 'B':
+ $sValue = '=?'.\strtolower(\MailSo\Base\Enumerations\Charset::UTF_8).
+ '?B?'.\base64_encode($sValue).'?=';
+ break;
+
+ case 'Q':
+ $sValue = '=?'.\strtolower(\MailSo\Base\Enumerations\Charset::UTF_8).
+ '?Q?'.\str_replace(array('?', ' ', '_'), array('=3F', '_', '=5F'),
+ \quoted_printable_encode($sValue)).'?=';
+ break;
+ }
+ }
+
+ return $sValue;
+ }
+
+ /**
+ * @unused
+ *
+ * @param string $sEncodeType
+ * @param string $sEncodeCharset
+ * @param string $sValue
+ *
+ * @return string
+ */
+ public static function EncodeHeaderValue($sEncodeType, $sEncodeCharset, $sValue)
+ {
+ $sValue = \trim($sValue);
+ if (0 < \strlen($sValue) && !\MailSo\Base\Utils::IsAscii($sValue))
+ {
+ switch (\strtoupper($sEncodeType))
+ {
+ case 'B':
+ $sValue = '=?'.\strtolower($sEncodeCharset).'?B?'.\base64_encode($sValue).'?=';
+ break;
+
+ case 'Q':
+ $sValue = '=?'.\strtolower($sEncodeCharset).'?Q?'.\str_replace(
+ array('?', ' ', '_'), array('=3F', '_', '=5F'),
+ \quoted_printable_encode($sValue)).'?=';
+ break;
+ }
+ }
+
+ return \trim($sValue);
+ }
+
+ /**
+ * @param string $sAttrName
+ * @param string $sValue = 'utf-8'
+ * @param string $sCharset = ''
+ * @param string $sLang = ''
+ * @param int $iLen = 78
+ *
+ * @return string|bool
+ */
+ public static function AttributeRfc2231Encode($sAttrName, $sValue, $sCharset = 'utf-8', $sLang = '', $iLen = 1000)
+ {
+ $sValue = \strtoupper($sCharset).'\''.$sLang.'\''.
+ \preg_replace_callback('/[\x00-\x20*\'%()<>@,;:\\\\"\/[\]?=\x80-\xFF]/', function ($match) {
+ return \rawurlencode($match[0]);
+ }, $sValue);
+
+ $iNlen = \strlen($sAttrName);
+ $iVlen = \strlen($sValue);
+
+ if (\strlen($sAttrName) + $iVlen > $iLen - 3)
+ {
+ $sections = array();
+ $section = 0;
+
+ for ($i = 0, $j = 0; $i < $iVlen; $i += $j)
+ {
+ $j = $iLen - $iNlen - \strlen($section) - 4;
+ $sections[$section++] = \substr($sValue, $i, $j);
+ }
+
+ for ($i = 0, $n = $section; $i < $n; $i++)
+ {
+ $sections[$i] = ' '.$sAttrName.'*'.$i.'*='.$sections[$i];
+ }
+
+ return \implode(";\r\n", $sections);
+ }
+ else
+ {
+ return $sAttrName.'*='.$sValue;
+ }
+ }
+ /**
+ * @param string $sAttrName
+ * @param string $sValue
+ *
+ * @return string
+ */
+ public static function EncodeHeaderUtf8AttributeValue($sAttrName, $sValue)
+ {
+ $sAttrName = \trim($sAttrName);
+ $sValue = \trim($sValue);
+
+ if (0 < \strlen($sValue) && !\MailSo\Base\Utils::IsAscii($sValue))
+ {
+ if (!empty($_SERVER['HTTP_USER_AGENT']) && 0 < \strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE'))
+ {
+ $sValue = $sAttrName.'="'.\preg_replace('/[+\s]+/', '%20', \urlencode($sValue)).'"';
+ }
+ else
+ {
+ $sValue = \MailSo\Base\Utils::AttributeRfc2231Encode($sAttrName, $sValue);
+ }
+ }
+ else
+ {
+ $sValue = $sAttrName.'="'.\str_replace('"', '\\"', $sValue).'"';
+ }
+
+ return \trim($sValue);
+ }
+
+ /**
+ * @param string $sEmail
+ *
+ * @return string
+ */
+ public static function GetAccountNameFromEmail($sEmail)
+ {
+ $sResult = '';
+ if (0 < \strlen($sEmail))
+ {
+ $iPos = \strrpos($sEmail, '@');
+ $sResult = (false === $iPos) ? $sEmail : \substr($sEmail, 0, $iPos);
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @param string $sEmail
+ *
+ * @return string
+ */
+ public static function GetDomainFromEmail($sEmail)
+ {
+ $sResult = '';
+ if (0 < \strlen($sEmail))
+ {
+ $iPos = \strrpos($sEmail, '@');
+ if (false !== $iPos && 0 < $iPos)
+ {
+ $sResult = \substr($sEmail, $iPos + 1);
+ }
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @param string $sDomain
+ *
+ * @return string
+ */
+ public static function GetClearDomainName($sDomain)
+ {
+ $sResultDomain = \preg_replace(
+ '/^(webmail|email|mail|www|imap4|pop3|imap|pop|demo|client|ssl|secure|test|cloud|box|m)\./i',
+ '', $sDomain);
+
+ return false === \strpos($sResultDomain, '.') ? $sDomain : $sResultDomain;
+ }
+
+ /**
+ * @param string $sFileName
+ *
+ * @return string
+ */
+ public static function GetFileExtension($sFileName)
+ {
+ $iLast = \strrpos($sFileName, '.');
+ return false === $iLast ? '' : \strtolower(\substr($sFileName, $iLast + 1));
+ }
+
+ /**
+ * @param string $sFileName
+ *
+ * @return string
+ */
+ public static function MimeContentType($sFileName)
+ {
+ $sResult = 'application/octet-stream';
+ $sFileName = \trim(\strtolower($sFileName));
+
+ if ('winmail.dat' === $sFileName)
+ {
+ return 'application/ms-tnef';
+ }
+
+ $aMimeTypes = array(
+
+ 'eml' => 'message/rfc822',
+ 'mime' => 'message/rfc822',
+ 'txt' => 'text/plain',
+ 'text' => 'text/plain',
+ 'def' => 'text/plain',
+ 'list' => 'text/plain',
+ 'in' => 'text/plain',
+ 'ini' => 'text/plain',
+ 'log' => 'text/plain',
+ 'sql' => 'text/plain',
+ 'cfg' => 'text/plain',
+ 'conf' => 'text/plain',
+ 'asc' => 'text/plain',
+ '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' => 'application/json',
+ 'swf' => 'application/x-shockwave-flash',
+ 'hlp' => 'application/winhlp',
+ 'wgt' => 'application/widget',
+ 'chm' => 'application/vnd.ms-htmlhelp',
+ 'p10' => 'application/pkcs10',
+ 'p7c' => 'application/pkcs7-mime',
+ 'p7m' => 'application/pkcs7-mime',
+ 'p7s' => 'application/pkcs7-signature',
+ 'torrent' => 'application/x-bittorrent',
+
+ // scripts
+ 'js' => 'application/javascript',
+ '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',
+
+ // images
+ 'png' => 'image/png',
+ 'jpg' => 'image/jpeg',
+ 'jpeg' => 'image/jpeg',
+ 'jpe' => 'image/jpeg',
+ 'jfif' => 'image/jpeg',
+ 'gif' => 'image/gif',
+ 'bmp' => 'image/bmp',
+ 'cgm' => 'image/cgm',
+ 'ief' => 'image/ief',
+ 'ico' => 'image/x-icon',
+ 'tif' => 'image/tiff',
+ 'tiff' => 'image/tiff',
+ 'svg' => 'image/svg+xml',
+ 'svgz' => 'image/svg+xml',
+ 'djv' => 'image/vnd.djvu',
+ 'djvu' => 'image/vnd.djvu',
+ 'webp' => 'image/webp',
+
+ // archives
+ 'zip' => 'application/zip',
+ '7z' => 'application/x-7z-compressed',
+ 'rar' => 'application/x-rar-compressed',
+ 'exe' => 'application/x-msdownload',
+ 'dll' => 'application/x-msdownload',
+ 'scr' => 'application/x-msdownload',
+ 'com' => 'application/x-msdownload',
+ 'bat' => 'application/x-msdownload',
+ 'msi' => 'application/x-msdownload',
+ 'cab' => 'application/vnd.ms-cab-compressed',
+ 'gz' => 'application/x-gzip',
+ 'tgz' => 'application/x-gzip',
+ 'bz' => 'application/x-bzip',
+ 'bz2' => 'application/x-bzip2',
+ 'deb' => 'application/x-debian-package',
+
+ // fonts
+ 'psf' => 'application/x-font-linux-psf',
+ 'otf' => 'application/x-font-otf',
+ 'pcf' => 'application/x-font-pcf',
+ 'snf' => 'application/x-font-snf',
+ 'ttf' => 'application/x-font-ttf',
+ 'ttc' => 'application/x-font-ttf',
+
+ // audio
+ 'mp3' => 'audio/mpeg',
+ 'amr' => 'audio/amr',
+ 'aac' => 'audio/x-aac',
+ 'aif' => 'audio/x-aiff',
+ 'aifc' => 'audio/x-aiff',
+ 'aiff' => 'audio/x-aiff',
+ 'wav' => 'audio/x-wav',
+ 'wma' => 'audio/x-ms-wma',
+ 'wax' => 'audio/x-ms-wax',
+ 'midi' => 'audio/midi',
+ 'mp4a' => 'audio/mp4',
+ 'ogg' => 'audio/ogg',
+ 'weba' => 'audio/webm',
+ 'ra' => 'audio/x-pn-realaudio',
+ 'ram' => 'audio/x-pn-realaudio',
+ 'rmp' => 'audio/x-pn-realaudio-plugin',
+ 'm3u' => 'audio/x-mpegurl',
+
+ // video
+ 'flv' => 'video/x-flv',
+ 'qt' => 'video/quicktime',
+ 'mov' => 'video/quicktime',
+ 'avi' => 'video/x-msvideo',
+ 'mpg' => 'video/mpeg',
+ 'mpeg' => 'video/mpeg',
+ 'mpe' => 'video/mpeg',
+ 'm1v' => 'video/mpeg',
+ 'm2v' => 'video/mpeg',
+ '3gp' => 'video/3gpp',
+ '3g2' => 'video/3gpp2',
+ 'h261' => 'video/h261',
+ 'h263' => 'video/h263',
+ 'h264' => 'video/h264',
+ 'jpgv' => 'video/jpgv',
+ 'mp4' => 'video/mp4',
+ 'mp4v' => 'video/mp4',
+ 'mpg4' => 'video/mp4',
+ 'ogv' => 'video/ogg',
+ 'webm' => 'video/webm',
+ 'm4v' => 'video/x-m4v',
+ 'asf' => 'video/x-ms-asf',
+ 'asx' => 'video/x-ms-asf',
+ 'wm' => 'video/x-ms-wm',
+ 'wmv' => 'video/x-ms-wmv',
+ 'wmx' => 'video/x-ms-wmx',
+ 'wvx' => 'video/x-ms-wvx',
+ 'movie' => 'video/x-sgi-movie',
+
+ // adobe
+ 'pdf' => 'application/pdf',
+ 'psd' => 'image/vnd.adobe.photoshop',
+ 'ai' => 'application/postscript',
+ 'eps' => 'application/postscript',
+ 'ps' => 'application/postscript',
+
+ // ms office
+ 'doc' => 'application/msword',
+ 'dot' => 'application/msword',
+ 'rtf' => 'application/rtf',
+ 'xls' => 'application/vnd.ms-excel',
+ 'ppt' => 'application/vnd.ms-powerpoint',
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+
+ // open office
+ 'odt' => 'application/vnd.oasis.opendocument.text',
+ 'ods' => 'application/vnd.oasis.opendocument.spreadsheet'
+
+ );
+
+ $sExt = \MailSo\Base\Utils::GetFileExtension($sFileName);
+ if (0 < \strlen($sExt) && isset($aMimeTypes[$sExt]))
+ {
+ $sResult = $aMimeTypes[$sExt];
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @param string $sContentType
+ * @param string $sFileName
+ *
+ * @return string
+ */
+ public static function ContentTypeType($sContentType, $sFileName)
+ {
+ $sResult = '';
+ $sContentType = \strtolower($sContentType);
+ if (0 === \strpos($sContentType, 'image/'))
+ {
+ $sResult = 'image';
+ }
+ else
+ {
+ switch ($sContentType)
+ {
+ case 'application/zip':
+ case 'application/x-7z-compressed':
+ case 'application/x-rar-compressed':
+ case 'application/x-msdownload':
+ case 'application/vnd.ms-cab-compressed':
+ case 'application/x-gzip':
+ case 'application/x-bzip':
+ case 'application/x-bzip2':
+ case 'application/x-debian-package':
+ $sResult = 'archive';
+ break;
+ case 'application/msword':
+ case 'application/rtf':
+ case 'application/vnd.ms-excel':
+ case 'application/vnd.ms-powerpoint':
+ case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document':
+ case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
+ case 'application/vnd.openxmlformats-officedocument.wordprocessingml.template':
+ case 'application/vnd.openxmlformats-officedocument.presentationml.presentation':
+ case 'application/vnd.oasis.opendocument.text':
+ case 'application/vnd.oasis.opendocument.spreadsheet':
+ $sResult = 'doc';
+ break;
+ case 'application/pdf':
+ case 'application/x-pdf':
+ $sResult = 'pdf';
+ break;
+ }
+
+ if ('' === $sResult)
+ {
+ switch (\strtolower(\MailSo\Base\Utils::GetFileExtension($sFileName)))
+ {
+ case 'zip':
+ case '7z':
+ case 'rar':
+ $sResult = 'archive';
+ break;
+ }
+ }
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @staticvar bool $bValidateAction
+ *
+ * @param int $iTimeToReset = 15
+ * @param int $iTimeToAdd = 120
+ *
+ * @return bool
+ */
+ public static function ResetTimeLimit($iTimeToReset = 15, $iTimeToAdd = 120)
+ {
+ $iTime = \time();
+ if ($iTime < \MailSo\Base\Loader::$InitTime + 5)
+ {
+ // do nothing first 5s
+ return true;
+ }
+
+ static $bValidateAction = null;
+ static $iResetTimer = null;
+
+ if (null === $bValidateAction)
+ {
+ $iResetTimer = 0;
+
+ $sSafeMode = \strtolower(\trim(@\ini_get('safe_mode')));
+ $bSafeMode = 'on' === $sSafeMode || '1' === $sSafeMode || 'true' === $sSafeMode;
+
+ $bValidateAction = !$bSafeMode && \MailSo\Base\Utils::FunctionExistsAndEnabled('set_time_limit');
+ }
+
+ if ($bValidateAction && $iTimeToReset < $iTime - $iResetTimer)
+ {
+ $iResetTimer = $iTime;
+ if (!@\set_time_limit($iTimeToAdd))
+ {
+ $bValidateAction = false;
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string $sText
+ *
+ * @return string
+ */
+ public static function InlineRebuildStringToJsString($sText)
+ {
+ static $aJsonReplaces = array(
+ array('\\', "\n", "\t", "\r", '\b', "\f", '"'),
+ array('\\\\', '\\n', '\\t', '\\r', '\\b', '\\f', '\"')
+ );
+
+ return \str_replace('', '<\/script>',
+ \str_replace($aJsonReplaces[0], $aJsonReplaces[1], $sText));
+ }
+
+ /**
+ * @param array $aInput
+ */
+ public static function ClearArrayUtf8Values(&$aInput)
+ {
+ if (\is_array($aInput))
+ {
+ foreach ($aInput as $mKey => $mItem)
+ {
+ if (\is_string($mItem))
+ {
+ $aInput[$mKey] = \MailSo\Base\Utils::Utf8Clear($mItem);
+ }
+ else if (\is_array($mItem))
+ {
+ \MailSo\Base\Utils::ClearArrayUtf8Values($mItem);
+ $aInput[$mKey] = $mItem;
+ }
+ }
+ }
+ }
+
+ /**
+ * @param mixed $mInput
+ * @param \MailSo\Log\Logger|null $oLogger = null
+ *
+ * @return string
+ */
+ public static function Php2js($mInput, $oLogger = null)
+ {
+ static $iOpt = null;
+ if (null === $iOpt)
+ {
+ $iOpt = \defined('JSON_UNESCAPED_UNICODE') ? JSON_UNESCAPED_UNICODE : 0;
+ }
+
+ $sResult = @\json_encode($mInput, $iOpt);
+ if (!\is_string($sResult) || '' === $sResult)
+ {
+ if (!$oLogger && \MailSo\Log\Logger::IsSystemEnabled())
+ {
+ $oLogger = \MailSo\Config::$SystemLogger;
+ }
+
+ if (!($oLogger instanceof \MailSo\Log\Logger))
+ {
+ $oLogger = null;
+ }
+
+ if ($oLogger)
+ {
+ $oLogger->Write('json_encode: '.\trim(
+ (\MailSo\Base\Utils::FunctionExistsAndEnabled('json_last_error') ? ' [Error Code: '.\json_last_error().']' : '').
+ (\MailSo\Base\Utils::FunctionExistsAndEnabled('json_last_error_msg') ? ' [Error Message: '.\json_last_error_msg().']' : '')
+ ), \MailSo\Log\Enumerations\Type::WARNING, 'JSON'
+ );
+ }
+
+ if (\is_array($mInput))
+ {
+ if ($oLogger)
+ {
+ $oLogger->WriteDump($mInput, \MailSo\Log\Enumerations\Type::INFO, 'JSON');
+ $oLogger->Write('Trying to clear Utf8 before json_encode', \MailSo\Log\Enumerations\Type::INFO, 'JSON');
+ }
+
+ \MailSo\Base\Utils::ClearArrayUtf8Values($mInput);
+ $sResult = @\json_encode($mInput, $iOpt);
+ }
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @param string $sFileName
+ *
+ * @return string
+ */
+ public static function ClearFileName($sFileName)
+ {
+ return \MailSo\Base\Utils::Trim(\MailSo\Base\Utils::ClearNullBite(
+ \MailSo\Base\Utils::StripSpaces(
+ \str_replace(array('"', '/', '\\', '*', '?', '<', '>', '|', ':'), ' ', $sFileName))));
+ }
+
+ /**
+ * @param string $sValue
+ *
+ * @return string
+ */
+ public static function ClearXss($sValue)
+ {
+ return \MailSo\Base\Utils::Trim(\MailSo\Base\Utils::ClearNullBite(
+ \str_replace(array('"', '/', '\\', '*', '?', '<', '>', '|', ':'), ' ', $sValue)));
+ }
+
+ /**
+ * @param string $sValue
+ *
+ * @return string
+ */
+ public static function Trim($sValue)
+ {
+ return \trim(\preg_replace('/^[\x00-\x1F]+/u', '',
+ \preg_replace('/[\x00-\x1F]+$/u', '', \trim($sValue))));
+ }
+
+ /**
+ * @param string $sDir
+ *
+ * @return bool
+ */
+ public static function RecRmDir($sDir)
+ {
+ if (@\is_dir($sDir))
+ {
+ $aObjects = \scandir($sDir);
+ foreach ($aObjects as $sObject)
+ {
+ if ('.' !== $sObject && '..' !== $sObject)
+ {
+// if ('dir' === \filetype($sDir.'/'.$sObject))
+ if (\is_dir($sDir.'/'.$sObject))
+ {
+ self::RecRmDir($sDir.'/'.$sObject);
+ }
+ else
+ {
+ @\unlink($sDir.'/'.$sObject);
+ }
+ }
+ }
+
+ return @\rmdir($sDir);
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string $sSource
+ * @param string $sDestination
+ */
+ public static function CopyDir($sSource, $sDestination)
+ {
+ if (\is_dir($sSource))
+ {
+ if (!\is_dir($sDestination))
+ {
+ \mkdir($sDestination);
+ }
+
+ $oDirectory = \dir($sSource);
+ if ($oDirectory)
+ {
+ while (false !== ($sRead = $oDirectory->read()))
+ {
+ if ('.' === $sRead || '..' === $sRead)
+ {
+ continue;
+ }
+
+ $sPathDir = $sSource.'/'.$sRead;
+ if (\is_dir($sPathDir))
+ {
+ \MailSo\Base\Utils::CopyDir($sPathDir, $sDestination.'/'.$sRead);
+ continue;
+ }
+
+ \copy($sPathDir, $sDestination.'/'.$sRead);
+ }
+
+ $oDirectory->close();
+ }
+ }
+ }
+
+ /**
+ * @param string $sTempPath
+ * @param int $iTime2Kill
+ * @param int $iNow
+ *
+ * @return bool
+ */
+ public static function RecTimeDirRemove($sTempPath, $iTime2Kill, $iNow)
+ {
+ $iFileCount = 0;
+
+ $sTempPath = rtrim($sTempPath, '\\/');
+ if (@\is_dir($sTempPath))
+ {
+ $rDirH = @\opendir($sTempPath);
+ if ($rDirH)
+ {
+ $bRemoveAllDirs = true;
+ while (($sFile = @\readdir($rDirH)) !== false)
+ {
+ if ('.' !== $sFile && '..' !== $sFile)
+ {
+ if (@\is_dir($sTempPath.'/'.$sFile))
+ {
+ if (!\MailSo\Base\Utils::RecTimeDirRemove($sTempPath.'/'.$sFile, $iTime2Kill, $iNow))
+ {
+ $bRemoveAllDirs = false;
+ }
+ }
+ else
+ {
+ $iFileCount++;
+ }
+ }
+ }
+
+ @\closedir($rDirH);
+ }
+
+ if ($iFileCount > 0)
+ {
+ if (\MailSo\Base\Utils::TimeFilesRemove($sTempPath, $iTime2Kill, $iNow))
+ {
+ return @\rmdir($sTempPath);
+ }
+ }
+ else
+ {
+ return $bRemoveAllDirs ? @\rmdir($sTempPath) : false;
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @param string $sTempPath
+ * @param int $iTime2Kill
+ * @param int $iNow
+ */
+ public static function TimeFilesRemove($sTempPath, $iTime2Kill, $iNow)
+ {
+ $bResult = true;
+
+ $sTempPath = rtrim($sTempPath, '\\/');
+ if (@\is_dir($sTempPath))
+ {
+ $rDirH = @\opendir($sTempPath);
+ if ($rDirH)
+ {
+ while (($sFile = @\readdir($rDirH)) !== false)
+ {
+ if ($sFile !== '.' && $sFile !== '..')
+ {
+ if ($iNow - \filemtime($sTempPath.'/'.$sFile) > $iTime2Kill)
+ {
+ @\unlink($sTempPath.'/'.$sFile);
+ }
+ else
+ {
+ $bResult = false;
+ }
+ }
+ }
+
+ @\closedir($rDirH);
+ }
+ }
+
+ return $bResult;
+ }
+
+ /**
+ * @param string $sUtfString
+ * @param int $iLength
+ *
+ * @return string
+ */
+ public static function Utf8Truncate($sUtfString, $iLength)
+ {
+ if (\strlen($sUtfString) <= $iLength)
+ {
+ return $sUtfString;
+ }
+
+ while ($iLength >= 0)
+ {
+ if ((\ord($sUtfString[$iLength]) < 0x80) || (\ord($sUtfString[$iLength]) >= 0xC0))
+ {
+ return \substr($sUtfString, 0, $iLength);
+ }
+
+ $iLength--;
+ }
+
+ return '';
+ }
+
+ /**
+ * @param string $sUtfString
+ * @param string $sReplaceOn = ''
+ *
+ * @return string
+ */
+ public static function Utf8Clear($sUtfString, $sReplaceOn = '')
+ {
+ if ('' === $sUtfString)
+ {
+ return $sUtfString;
+ }
+
+ $sUtfString = \preg_replace(\MailSo\Base\Utils::$sValidUtf8Regexp, '$1', $sUtfString);
+
+ $sUtfString = \preg_replace(
+ '/\xE0[\x80-\x9F][\x80-\xBF]'.
+ '|\xEF\xBF\xBF'.
+ '|\xED[\xA0-\xBF][\x80-\xBF]/S', $sReplaceOn, $sUtfString);
+
+ $sUtfString = \preg_replace('/\xEF\xBF\xBD/', '?', $sUtfString);
+
+ $sNewUtfString = false;
+ if (false === $sNewUtfString && \MailSo\Base\Utils::IsMbStringSupported())
+ {
+ $sNewUtfString = \MailSo\Base\Utils::MbConvertEncoding($sUtfString, 'UTF-8', 'UTF-8');
+ }
+
+ if (false === $sNewUtfString && \MailSo\Base\Utils::IsIconvSupported())
+ {
+ $sNewUtfString = \MailSo\Base\Utils::IconvConvertEncoding($sUtfString, 'UTF-8', 'UTF-8');
+ }
+
+ if (false !== $sNewUtfString)
+ {
+ $sUtfString = $sNewUtfString;
+ }
+
+ return $sUtfString;
+ }
+
+ /**
+ * @param string $sUtfString
+ *
+ * @return bool
+ */
+ public static function IsRTL($sUtfString)
+ {
+ // \x{0591}-\x{05F4} - Hebrew
+ // \x{0600}-\x{068F} - Arabic
+ // \x{0750}-\x{077F} - Arabic
+ // \x{08A0}-\x{08FF} - Arabic
+ // \x{103A0}-\x{103DF} - Old Persian
+ return 0 < (int) preg_match('/[\x{0591}-\x{05F4}\x{0600}-\x{068F}\x{0750}-\x{077F}\x{08A0}-\x{08FF}\x{103A0}-\x{103DF}]/u', $sUtfString);
+ }
+
+ /**
+ * @param string $sString
+ *
+ * @return string
+ */
+ public static function Base64Decode($sString)
+ {
+ $sResultString = \base64_decode($sString, true);
+ if (false === $sResultString)
+ {
+ $sString = \str_replace(array(' ', "\r", "\n", "\t"), '', $sString);
+ $sString = \preg_replace('/[^a-zA-Z0-9=+\/](.*)$/', '', $sString);
+
+ if (false !== \strpos(\trim(\trim($sString), '='), '='))
+ {
+ $sString = \preg_replace('/=([^=])/', '= $1', $sString);
+ $aStrings = \explode(' ', $sString);
+ foreach ($aStrings as $iIndex => $sParts)
+ {
+ $aStrings[$iIndex] = \base64_decode($sParts);
+ }
+
+ $sResultString = \implode('', $aStrings);
+ }
+ else
+ {
+ $sResultString = \base64_decode($sString);
+ }
+ }
+
+ return $sResultString;
+ }
+
+ /**
+ * @param string $sValue
+ *
+ * @return string
+ */
+ public static function UrlSafeBase64Encode($sValue)
+ {
+ return \rtrim(\strtr(\base64_encode($sValue), '+/', '-_'), '=');
+ }
+
+ /**
+ * @param string $sValue
+ *
+ * @return string
+ */
+ public static function UrlSafeBase64Decode($sValue)
+ {
+ $sValue = \rtrim(\strtr($sValue, '-_.', '+/='), '=');
+ return \MailSo\Base\Utils::Base64Decode(\str_pad($sValue, \strlen($sValue) + (\strlen($sValue) % 4), '=', STR_PAD_RIGHT));
+ }
+
+ /**
+ * @param string $sSequence
+ *
+ * @return array
+ */
+ public static function ParseFetchSequence($sSequence)
+ {
+ $aResult = array();
+ $sSequence = \trim($sSequence);
+ if (0 < \strlen($sSequence))
+ {
+ $aSequence = \explode(',', $sSequence);
+ foreach ($aSequence as $sItem)
+ {
+ if (false === \strpos($sItem, ':'))
+ {
+ $aResult[] = (int) $sItem;
+ }
+ else
+ {
+ $aItems = \explode(':', $sItem);
+ $iMax = \max($aItems[0], $aItems[1]);
+
+ for ($iIndex = $aItems[0]; $iIndex <= $iMax; $iIndex++)
+ {
+ $aResult[] = (int) $iIndex;
+ }
+ }
+ }
+ }
+
+ return $aResult;
+ }
+ /**
+ * @param array $aSequence
+ *
+ * @return string
+ */
+ public static function PrepearFetchSequence($aSequence)
+ {
+ $aResult = array();
+ if (\is_array($aSequence) && 0 < \count($aSequence))
+ {
+ $iStart = null;
+ $iPrev = null;
+
+ foreach ($aSequence as $sItem)
+ {
+ // simple protection
+ if (false !== \strpos($sItem, ':'))
+ {
+ $aResult[] = $sItem;
+ continue;
+ }
+
+ $iItem = (int) $sItem;
+ if (null === $iStart || null === $iPrev)
+ {
+ $iStart = $iItem;
+ $iPrev = $iItem;
+ continue;
+ }
+
+ if ($iPrev === $iItem - 1)
+ {
+ $iPrev = $iItem;
+ }
+ else
+ {
+ $aResult[] = $iStart === $iPrev ? $iStart : $iStart.':'.$iPrev;
+ $iStart = $iItem;
+ $iPrev = $iItem;
+ }
+ }
+
+ if (null !== $iStart && null !== $iPrev)
+ {
+ $aResult[] = $iStart === $iPrev ? $iStart : $iStart.':'.$iPrev;
+ }
+ }
+
+ return \implode(',', $aResult);
+ }
+
+ /**
+ *
+ * @param resource $fResource
+ * @param int $iBufferLen = 8192
+ *
+ * @return bool
+ */
+ public static function FpassthruWithTimeLimitReset($fResource, $iBufferLen = 8192)
+ {
+ $bResult = false;
+ if (\is_resource($fResource))
+ {
+ while (!\feof($fResource))
+ {
+ $sBuffer = @\fread($fResource, $iBufferLen);
+ if (false !== $sBuffer)
+ {
+ echo $sBuffer;
+ \MailSo\Base\Utils::ResetTimeLimit();
+ continue;
+ }
+
+ break;
+ }
+
+ $bResult = true;
+ }
+
+ return $bResult;
+ }
+
+ /**
+ * @param resource $rRead
+ * @param array $aWrite
+ * @param int $iBufferLen = 8192
+ * @param bool $bResetTimeLimit = true
+ * @param bool $bFixCrLf = false
+ * @param bool $bRewindOnComplete = false
+ *
+ * @return int|bool
+ */
+ public static function MultipleStreamWriter($rRead, $aWrite, $iBufferLen = 8192, $bResetTimeLimit = true, $bFixCrLf = false, $bRewindOnComplete = false)
+ {
+ $mResult = false;
+ if ($rRead && \is_array($aWrite) && 0 < \count($aWrite))
+ {
+ $mResult = 0;
+ while (!\feof($rRead))
+ {
+ $sBuffer = \fread($rRead, $iBufferLen);
+ if (false === $sBuffer)
+ {
+ $mResult = false;
+ break;
+ }
+
+ if (0 === $iBufferLen || '' === $sBuffer)
+ {
+ break;
+ }
+
+ if ($bFixCrLf)
+ {
+ $sBuffer = \str_replace("\n", "\r\n", \str_replace("\r", '', $sBuffer));
+ }
+
+ $mResult += \strlen($sBuffer);
+
+ foreach ($aWrite as $rWriteStream)
+ {
+ $mWriteResult = \fwrite($rWriteStream, $sBuffer);
+ if (false === $mWriteResult)
+ {
+ $mResult = false;
+ break 2;
+ }
+ }
+
+ if ($bResetTimeLimit)
+ {
+ \MailSo\Base\Utils::ResetTimeLimit();
+ }
+ }
+ }
+
+ if ($mResult && $bRewindOnComplete)
+ {
+ foreach ($aWrite as $rWriteStream)
+ {
+ if (\is_resource($rWriteStream))
+ {
+ @\rewind($rWriteStream);
+ }
+ }
+ }
+
+ return $mResult;
+ }
+
+ /**
+ * @param string $sUtfModifiedString
+ *
+ * @return string
+ */
+ public static function ModifiedToPlainUtf7($sUtfModifiedString)
+ {
+ $sUtf = '';
+ $bBase = false;
+
+ for ($iIndex = 0, $iLen = \strlen($sUtfModifiedString); $iIndex < $iLen; $iIndex++)
+ {
+ if ('&' === $sUtfModifiedString[$iIndex])
+ {
+ if (isset($sUtfModifiedString[$iIndex+1]) && '-' === $sUtfModifiedString[$iIndex + 1])
+ {
+ $sUtf .= '&';
+ $iIndex++;
+ }
+ else
+ {
+ $sUtf .= '+';
+ $bBase = true;
+ }
+ }
+ else if ($sUtfModifiedString[$iIndex] == '-' && $bBase)
+ {
+ $bBase = false;
+ }
+ else
+ {
+ if ($bBase && ',' === $sUtfModifiedString[$iIndex])
+ {
+ $sUtf .= '/';
+ }
+ else if (!$bBase && '+' === $sUtfModifiedString[$iIndex])
+ {
+ $sUtf .= '+-';
+ }
+ else
+ {
+ $sUtf .= $sUtfModifiedString[$iIndex];
+ }
+ }
+ }
+
+ return $sUtf;
+ }
+
+ /**
+ * @param string $sStr
+ *
+ * @return string|bool
+ */
+ public static function Utf7ModifiedToUtf8($sStr)
+ {
+ $aArray = array(-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,62, 63,-1,-1,-1,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,
+ 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
+ 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1);
+
+ $sResult = '';
+ $bError = false;
+ $iLen = \strlen($sStr);
+
+ for ($iIndex = 0; $iLen > 0; $iIndex++, $iLen--)
+ {
+ $sChar = $sStr{$iIndex};
+ if ($sChar == '&')
+ {
+ $iIndex++;
+ $iLen--;
+
+ $sChar = isset($sStr{$iIndex}) ? $sStr{$iIndex} : null;
+ if ($sChar === null)
+ {
+ break;
+ }
+
+ if ($iLen && $sChar == '-')
+ {
+ $sResult .= '&';
+ continue;
+ }
+
+ $iCh = 0;
+ $iK = 10;
+ for (; $iLen > 0; $iIndex++, $iLen--)
+ {
+ $sChar = $sStr{$iIndex};
+
+ $iB = $aArray[\ord($sChar)];
+ if ((\ord($sChar) & 0x80) || $iB == -1)
+ {
+ break;
+ }
+
+ if ($iK > 0)
+ {
+ $iCh |= $iB << $iK;
+ $iK -= 6;
+ }
+ else
+ {
+ $iCh |= $iB >> (-$iK);
+ if ($iCh < 0x80)
+ {
+ if (0x20 <= $iCh && $iCh < 0x7f)
+ {
+ return $bError;
+ }
+
+ $sResult .= \chr($iCh);
+ }
+ else if ($iCh < 0x800)
+ {
+ $sResult .= \chr(0xc0 | ($iCh >> 6));
+ $sResult .= \chr(0x80 | ($iCh & 0x3f));
+ }
+ else
+ {
+ $sResult .= \chr(0xe0 | ($iCh >> 12));
+ $sResult .= \chr(0x80 | (($iCh >> 6) & 0x3f));
+ $sResult .= \chr(0x80 | ($iCh & 0x3f));
+ }
+
+ $iCh = ($iB << (16 + $iK)) & 0xffff;
+ $iK += 10;
+ }
+ }
+
+ if (($iCh || $iK < 6) ||
+ (!$iLen || $sChar != '-') ||
+ ($iLen > 2 && '&' === $sStr{$iIndex+1} && '-' !== $sStr{$iIndex+2}))
+ {
+ return $bError;
+ }
+ }
+ else if (\ord($sChar) < 0x20 || \ord($sChar) >= 0x7f)
+ {
+ return $bError;
+ }
+ else
+ {
+ $sResult .= $sChar;
+ }
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @param string $sStr
+ *
+ * @return string|bool
+ */
+ public static function Utf8ToUtf7Modified($sStr)
+ {
+ $sArray = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S',
+ 'T','U','V','W','X','Y','Z', 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
+ 'p','q','r','s','t','u','v','w','x','y','z', '0','1','2','3','4','5','6','7','8','9','+',',');
+
+ $sLen = \strlen($sStr);
+ $bIsB = false;
+ $iIndex = $iN = 0;
+ $sReturn = '';
+ $bError = false;
+ $iCh = $iB = $iK = 0;
+
+ while ($sLen)
+ {
+ $iC = \ord($sStr{$iIndex});
+ if ($iC < 0x80)
+ {
+ $iCh = $iC;
+ $iN = 0;
+ }
+ else if ($iC < 0xc2)
+ {
+ return $bError;
+ }
+ else if ($iC < 0xe0)
+ {
+ $iCh = $iC & 0x1f;
+ $iN = 1;
+ }
+ else if ($iC < 0xf0)
+ {
+ $iCh = $iC & 0x0f;
+ $iN = 2;
+ }
+ else if ($iC < 0xf8)
+ {
+ $iCh = $iC & 0x07;
+ $iN = 3;
+ }
+ else if ($iC < 0xfc)
+ {
+ $iCh = $iC & 0x03;
+ $iN = 4;
+ }
+ else if ($iC < 0xfe)
+ {
+ $iCh = $iC & 0x01;
+ $iN = 5;
+ }
+ else
+ {
+ return $bError;
+ }
+
+ $iIndex++;
+ $sLen--;
+
+ if ($iN > $sLen)
+ {
+ return $bError;
+ }
+
+ for ($iJ = 0; $iJ < $iN; $iJ++)
+ {
+ $iO = \ord($sStr{$iIndex+$iJ});
+ if (($iO & 0xc0) != 0x80)
+ {
+ return $bError;
+ }
+
+ $iCh = ($iCh << 6) | ($iO & 0x3f);
+ }
+
+ if ($iN > 1 && !($iCh >> ($iN * 5 + 1)))
+ {
+ return $bError;
+ }
+
+ $iIndex += $iN;
+ $sLen -= $iN;
+
+ if ($iCh < 0x20 || $iCh >= 0x7f)
+ {
+ if (!$bIsB)
+ {
+ $sReturn .= '&';
+ $bIsB = true;
+ $iB = 0;
+ $iK = 10;
+ }
+
+ if ($iCh & ~0xffff)
+ {
+ $iCh = 0xfffe;
+ }
+
+ $sReturn .= $sArray[($iB | $iCh >> $iK)];
+ $iK -= 6;
+ for (; $iK >= 0; $iK -= 6)
+ {
+ $sReturn .= $sArray[(($iCh >> $iK) & 0x3f)];
+ }
+
+ $iB = ($iCh << (-$iK)) & 0x3f;
+ $iK += 16;
+ }
+ else
+ {
+ if ($bIsB)
+ {
+ if ($iK > 10)
+ {
+ $sReturn .= $sArray[$iB];
+ }
+ $sReturn .= '-';
+ $bIsB = false;
+ }
+
+ $sReturn .= \chr($iCh);
+ if ('&' === \chr($iCh))
+ {
+ $sReturn .= '-';
+ }
+ }
+ }
+
+ if ($bIsB)
+ {
+ if ($iK > 10)
+ {
+ $sReturn .= $sArray[$iB];
+ }
+
+ $sReturn .= '-';
+ }
+
+ return $sReturn;
+ }
+
+ /**
+ * @param string|array $mFunctionNameOrNames
+ *
+ * @return bool
+ */
+ public static function FunctionExistsAndEnabled($mFunctionNameOrNames)
+ {
+ static $aCache = null;
+
+ if (\is_array($mFunctionNameOrNames))
+ {
+ foreach ($mFunctionNameOrNames as $sFunctionName)
+ {
+ if (!\MailSo\Base\Utils::FunctionExistsAndEnabled($sFunctionName))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ if (empty($mFunctionNameOrNames) || !\function_exists($mFunctionNameOrNames) || !\is_callable($mFunctionNameOrNames))
+ {
+ return false;
+ }
+
+ if (null === $aCache)
+ {
+ $sDisableFunctions = @\ini_get('disable_functions');
+ $sDisableFunctions = \is_string($sDisableFunctions) && 0 < \strlen($sDisableFunctions) ? $sDisableFunctions : '';
+
+ $aCache = \explode(',', $sDisableFunctions);
+ $aCache = \is_array($aCache) && 0 < \count($aCache) ? $aCache : array();
+
+ if (\extension_loaded('suhosin'))
+ {
+ $sSuhosin = @\ini_get('suhosin.executor.func.blacklist');
+ $sSuhosin = \is_string($sSuhosin) && 0 < \strlen($sSuhosin) ? $sSuhosin : '';
+
+ $aSuhosinCache = \explode(',', $sSuhosin);
+ $aSuhosinCache = \is_array($aSuhosinCache) && 0 < \count($aSuhosinCache) ? $aSuhosinCache : array();
+
+ if (0 < \count($aSuhosinCache))
+ {
+ $aCache = \array_merge($aCache, $aSuhosinCache);
+ $aCache = \array_unique($aCache);
+ }
+ }
+ }
+
+ return !\in_array($mFunctionNameOrNames, $aCache);
+ }
+
+ /**
+ * @param string $mValue
+ *
+ * @return string
+ */
+ public static function ClearNullBite($mValue)
+ {
+ return \str_replace('%00', '', $mValue);
+ }
+
+ /**
+ * @param mixed $mValue
+ * @param bool $bClearNullBite = false
+ *
+ * @return mixed
+ */
+ public static function StripSlashesValue($mValue, $bClearNullBite = false)
+ {
+ static $bIsMagicQuotesOn = null;
+ if (null === $bIsMagicQuotesOn)
+ {
+ $bIsMagicQuotesOn = (bool) @\ini_get('magic_quotes_gpc');
+ }
+
+ if (!$bIsMagicQuotesOn)
+ {
+ return $bClearNullBite && \is_string($mValue) ? \MailSo\Base\Utils::ClearNullBite($mValue) : $mValue;
+ }
+
+ $sType = \gettype($mValue);
+ if ('string' === $sType)
+ {
+ return \stripslashes($bClearNullBite ? \MailSo\Base\Utils::ClearNullBite($mValue) : $mValue);
+ }
+ else if ('array' === $sType)
+ {
+ $aReturnValue = array();
+ $mValueKeys = \array_keys($mValue);
+ foreach ($mValueKeys as $sKey)
+ {
+ $aReturnValue[$sKey] = \MailSo\Base\Utils::StripSlashesValue($mValue[$sKey], $bClearNullBite);
+ }
+
+ return $aReturnValue;
+ }
+
+ return $mValue;
+ }
+
+ /**
+ * @param string $sStr
+ *
+ * @return string
+ */
+ public static function CharsetDetect($sStr)
+ {
+ $mResult = '';
+ if (!\MailSo\Base\Utils::IsAscii($sStr))
+ {
+ $mResult = \MailSo\Base\Utils::IsMbStringSupported() &&
+ \MailSo\Base\Utils::FunctionExistsAndEnabled('mb_detect_encoding') ?
+ @\mb_detect_encoding($sStr, 'auto', true) : false;
+
+ if (false === $mResult && \MailSo\Base\Utils::IsIconvSupported())
+ {
+ $mResult = \md5(@\iconv('utf-8', 'utf-8//IGNORE', $sStr)) === \md5($sStr) ? 'utf-8' : '';
+ }
+ }
+
+ return \is_string($mResult) && 0 < \strlen($mResult) ? $mResult : '';
+ }
+
+ /**
+ * @param string $sAdditionalSalt = ''
+ *
+ * @return string
+ */
+ public static function Md5Rand($sAdditionalSalt = '')
+ {
+ return \md5(\microtime(true).\rand(10000, 99999).
+ \md5($sAdditionalSalt).\rand(10000, 99999).\microtime(true));
+ }
+
+ /**
+ * @param string $sAdditionalSalt = ''
+ *
+ * @return string
+ */
+ public static function Sha1Rand($sAdditionalSalt = '')
+ {
+ return \sha1(\microtime(true).\rand(10000, 99999).
+ \sha1($sAdditionalSalt).\rand(10000, 99999).\microtime(true));
+ }
+
+ /**
+ * @param string $sData
+ * @param string $sKey
+ *
+ * @return string
+ */
+ public static function Hmac($sData, $sKey)
+ {
+ if (\function_exists('hash_hmac'))
+ {
+ return \hash_hmac('md5', $sData, $sKey);
+ }
+
+ $iLen = 64;
+ if ($iLen < \strlen($sKey))
+ {
+ $sKey = \pack('H*', \md5($sKey));
+ }
+
+ $sKey = \str_pad($sKey, $iLen, \chr(0x00));
+ $sIpad = \str_pad('', $iLen, \chr(0x36));
+ $sOpad = \str_pad('', $iLen, \chr(0x5c));
+
+ return \md5(($sKey ^ $sOpad).\pack('H*', \md5(($sKey ^ $sIpad).$sData)));
+ }
+
+ /**
+ * @param string $sDomain
+ * @param bool $bSimple = false
+ *
+ * @return bool
+ */
+ public static function ValidateDomain($sDomain, $bSimple = false)
+ {
+ $aMatch = array();
+ if ($bSimple)
+ {
+ return \preg_match('/.+(\.[a-zA-Z]+)$/', $sDomain, $aMatch) && !empty($aMatch[1]);
+ }
+
+ return \preg_match('/.+(\.[a-zA-Z]+)$/', $sDomain, $aMatch) && !empty($aMatch[1]) && \in_array($aMatch[1], \explode(' ',
+ '.academy .actor .agency .audio .bar .beer .bike .blue .boutique .cab .camera .camp .capital .cards .careers .cash .catering .center .cheap .city .cleaning .clinic .clothing .club .coffee .community .company .computer .construction .consulting .contractors .cool .credit .dance .dating .democrat .dental .diamonds .digital .direct .directory .discount .domains .education .email .energy .equipment .estate .events .expert .exposed .fail .farm .fish .fitness .florist .fund .futbol .gallery .gift .glass .graphics .guru .help .holdings .holiday .host .hosting .house .institute .international .kitchen .land .life .lighting .limo .link .management .market .marketing .media .menu .moda .partners .parts .photo .photography .photos .pics .pink .press .productions .pub .red .rentals .repair .report .rest .sexy .shoes .social .solar .solutions .space .support .systems .tattoo .tax .technology .tips .today .tools .town .toys .trade .training .university .uno .vacations .vision .vodka .voyage .watch .webcam .wiki .work .works .wtf .zone .aero .asia .biz .cat .com .coop .edu .gov .info .int .jobs .mil .mobi .museum .name .net .org .pro .tel .travel .xxx .xyz '.
+ '.ac .ad .ae .af .ag .ai .al .am .an .ao .aq .ar .as .at .au .aw .ax .az .ba .bb .bd .be .bf .bg .bh .bi .bj .bm .bn .bo .br .bs .bt .bv .bw .by .bz .ca .cc .cd .cf .cg .ch .ci .ck .cl .cm .cn .co .cr .cs .cu .cv .cx .cy .cz .dd .de .dj .dk .dm .do .dz .ec .ee .eg .er .es .et .eu .fi .fj .fk .fm .fo .fr .ga .gb .gd .ge .gf .gg .gh .gi .gl .gm .gn .gp .gq .gr .gs .gt .gu .gw .gy .hk .hm .hn .hr .ht .hu .id .ie .il .im .in .io .iq .ir .is .it .je .jm .jo .jp .ke .kg .kh .ki .km .kn .kp .kr .kw .ky .kz .la .lb .lc .li .lk .lr .ls .lt .lu .lv .ly .ma .mc .md .me .mg .mh .mk .ml .mm .mn .mo .mp .mq .mr .ms .mt .mu .mv .mw .mx .my .mz .na .nc .ne .nf .ng .ni .nl .no .np .nr .nu .nz .om .pa .pe .pf .pg .ph .pk .pl .pm .pn .pr .ps .pt .pw .py .qa .re .ro .rs .ru . .rw .sa .sb .sc .sd .se .sg .sh .si .sj .sk .sl .sm .sn .so .sr .st .su .sv .sy .sz .tc .td .tf .tg .th .tj .tk .tl .tm .tn .to .tp .tr .tt .tv .tw .tz .ua .ug .uk .us .uy .uz .va .vc .ve .vg .vi .vn .vu .wf .ws .ye .yt .za .zm .zw'
+ ));
+ }
+
+ /**
+ * @param string $sIp
+ *
+ * @return bool
+ */
+ public static function ValidateIP($sIp)
+ {
+ return !empty($sIp) && $sIp === @\filter_var($sIp, FILTER_VALIDATE_IP);
+ }
+
+ /**
+ * @return \Net_IDNA2
+ */
+ private static function idn()
+ {
+ static $oIdn = null;
+ if (null === $oIdn)
+ {
+ include_once MAILSO_LIBRARY_ROOT_PATH.'Vendors/Net/IDNA2.php';
+ $oIdn = new \Net_IDNA2();
+ $oIdn->setParams('utf8', true);
+ }
+
+ return $oIdn;
+ }
+
+ /**
+ * @param string $sStr
+ * @param bool $bLowerIfAscii = false
+ *
+ * @return string
+ */
+ public static function IdnToUtf8($sStr, $bLowerIfAscii = false)
+ {
+ if (0 < \strlen($sStr) && \preg_match('/(^|\.|@)xn--/i', $sStr))
+ {
+ try
+ {
+ $sStr = self::idn()->decode($sStr);
+ }
+ catch (\Exception $oException) {}
+ }
+
+ return $bLowerIfAscii ? \MailSo\Base\Utils::StrMailDomainToLowerIfAscii($sStr) : $sStr;
+ }
+
+ /**
+ * @param string $sStr
+ * @param bool $bLowerIfAscii = false
+ *
+ * @return string
+ */
+ public static function IdnToAscii($sStr, $bLowerIfAscii = false)
+ {
+ $sStr = $bLowerIfAscii ? \MailSo\Base\Utils::StrMailDomainToLowerIfAscii($sStr) : $sStr;
+
+ $sUser = '';
+ $sDomain = $sStr;
+ if (false !== \strpos($sStr, '@'))
+ {
+ $sUser = \MailSo\Base\Utils::GetAccountNameFromEmail($sStr);
+ $sDomain = \MailSo\Base\Utils::GetDomainFromEmail($sStr);
+ }
+
+ if (0 < \strlen($sDomain) && \preg_match('/[^\x20-\x7E]/', $sDomain))
+ {
+ try
+ {
+ $sDomain = self::idn()->encode($sDomain);
+ }
+ catch (\Exception $oException) {}
+ }
+
+ return ('' === $sUser ? '' : $sUser.'@').$sDomain;
+ }
+
+ /**
+ * @param string $sHash
+ * @param string $sSalt
+ *
+ * @return int
+ */
+ public static function HashToId($sHash, $sSalt = '')
+ {
+ $sData = $sHash ? @\MailSo\Base\Crypt::XxteaDecrypt(\hex2bin($sHash), \md5($sSalt)) : null;
+
+ $aMatch = array();
+ if ($sData && preg_match('/^id:(\d+)$/', $sData, $aMatch) && isset($aMatch[1]))
+ {
+ return is_numeric($aMatch[1]) ? (int) $aMatch[1] : null;
+ }
+
+ return null;
+ }
+
+ /**
+ * @param int $iID
+ * @param string $sSalt
+ *
+ * @return string
+ */
+ public static function IdToHash($iID, $sSalt = '')
+ {
+ return is_int($iID) ?
+ \bin2hex(\MailSo\Base\Crypt::XxteaEncrypt('id:'.$iID, \md5($sSalt))) : null
+ ;
+ }
+
+ /**
+ * @param string $sPassword
+ *
+ * @return bool
+ */
+ public static function PasswordWeaknessCheck($sPassword)
+ {
+ $sPassword = \trim($sPassword);
+ if (6 > \strlen($sPassword))
+ {
+ return false;
+ }
+
+ $sLine = 'password 123.456 12345678 abc123 qwerty monkey letmein dragon 111.111 baseball iloveyou trustno1 1234567 sunshine master 123.123 welcome shadow ashley football jesus michael ninja mustang password1 123456 123456789 qwerty 111111 1234567 666666 12345678 7777777 123321 654321 1234567890 123123 555555 vkontakte gfhjkm 159753 777777 temppassword qazwsx 1q2w3e 1234 112233 121212 qwertyuiop qq18ww899 987654321 12345 zxcvbn zxcvbnm 999999 samsung ghbdtn 1q2w3e4r 1111111 123654 159357 131313 qazwsxedc 123qwe 222222 asdfgh 333333 9379992 asdfghjkl 4815162342 12344321 88888888 11111111 knopka 789456 qwertyu 1q2w3e4r5t iloveyou vfhbyf marina password qweasdzxc 10203 987654 yfnfif cjkysirj nikita 888888 vfrcbv k.,jdm qwertyuiop[] qwe123 qweasd natasha 123123123 fylhtq q1w2e3 stalker 1111111111 q1w2e3r4 nastya 147258369 147258 fyfcnfcbz 1234554321 1qaz2wsx andrey 111222 147852 genius sergey 7654321 232323 123789 fktrcfylh spartak admin test 123 azerty abc123 lol123 easytocrack1 hello saravn holysh!t test123 tundra_cool2 456 dragon thomas killer root 1111 pass master aaaaaa a monkey daniel asdasd e10adc3949ba59abbe56e057f20f883e changeme computer jessica letmein mirage loulou lol superman shadow admin123 secret administrator sophie kikugalanetroot doudou liverpool hallo sunshine charlie parola 100827092 michael andrew password1 fuckyou matrix cjmasterinf internet hallo123 eminem demo gewinner pokemon abcd1234 guest ngockhoa martin sandra asdf hejsan george qweqwe lollipop lovers q1q1q1 tecktonik naruto 12 password12 password123 password1234 password12345 password123456 password1234567 password12345678 password123456789 000000 maximius 123abc baseball1 football1 soccer princess slipknot 11111 nokia super star 666999 12341234 1234321 135790 159951 212121 zzzzzz 121314 134679 142536 19921992 753951 7007 1111114 124578 19951995 258456 qwaszx zaqwsx 55555 77777 54321 qwert 22222 33333 99999 88888 66666';
+ return false === \strpos($sLine, \strtolower($sPassword));
+ }
+}
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Base/Validator.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Base/Validator.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Base/Validator.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Base/Validator.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Cache/CacheClient.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Cache/CacheClient.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Cache/CacheClient.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Cache/CacheClient.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Cache/DriverInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Cache/DriverInterface.php
similarity index 93%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Cache/DriverInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Cache/DriverInterface.php
index 4789cd6c19aaf1c620708aa46eeec5522593f006..8751ba1db31ac9b11f9f64c3f26c6104cde75272 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Cache/DriverInterface.php
+++ b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Cache/DriverInterface.php
@@ -1,48 +1,48 @@
-oImapResponse = $oImapResponse;
- $this->aEnvelopeCache = null;
- }
-
- /**
- * @param \MailSo\Imap\Response $oImapResponse
- * @return \MailSo\Imap\FetchResponse
- */
- public static function NewInstance($oImapResponse)
- {
- return new self($oImapResponse);
- }
-
- /**
- * @param bool $bForce = false
- *
- * @return array|null
- */
- public function GetEnvelope($bForce = false)
- {
- if (null === $this->aEnvelopeCache || $bForce)
- {
- $this->aEnvelopeCache = $this->GetFetchValue(Enumerations\FetchType::ENVELOPE);
- }
- return $this->aEnvelopeCache;
- }
-
- /**
- * @param int $iIndex
- * @param mixed $mNullResult = null
- *
- * @return mixed
- */
- public function GetFetchEnvelopeValue($iIndex, $mNullResult)
- {
- return self::findEnvelopeIndex($this->GetEnvelope(), $iIndex, $mNullResult);
- }
-
- /**
- * @param int $iIndex
- * @param string $sParentCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1
- *
- * @return \MailSo\Mime\EmailCollection|null
- */
- public function GetFetchEnvelopeEmailCollection($iIndex, $sParentCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1)
- {
- $oResult = null;
- $aEmails = $this->GetFetchEnvelopeValue($iIndex, null);
- if (is_array($aEmails) && 0 < count($aEmails))
- {
- $oResult = \MailSo\Mime\EmailCollection::NewInstance();
- foreach ($aEmails as $aEmailItem)
- {
- if (is_array($aEmailItem) && 4 === count($aEmailItem))
- {
- $sDisplayName = \MailSo\Base\Utils::DecodeHeaderValue(
- self::findEnvelopeIndex($aEmailItem, 0, ''), $sParentCharset);
-
-// $sRemark = \MailSo\Base\Utils::DecodeHeaderValue(
-// self::findEnvelopeIndex($aEmailItem, 1, ''), $sParentCharset);
-
- $sLocalPart = self::findEnvelopeIndex($aEmailItem, 2, '');
- $sDomainPart = self::findEnvelopeIndex($aEmailItem, 3, '');
-
- if (0 < strlen($sLocalPart) && 0 < strlen($sDomainPart))
- {
- $oResult->Add(
- \MailSo\Mime\Email::NewInstance($sLocalPart.'@'.$sDomainPart, $sDisplayName)
- );
- }
- }
- }
- }
-
- return $oResult;
- }
-
- /**
- * @param string $sRfc822SubMimeIndex = ''
- *
- * @return \MailSo\Imap\BodyStructure|null
- */
- public function GetFetchBodyStructure($sRfc822SubMimeIndex = '')
- {
- $oBodyStructure = null;
- $aBodyStructureArray = $this->GetFetchValue(Enumerations\FetchType::BODYSTRUCTURE);
-
- if (is_array($aBodyStructureArray))
- {
- if (0 < strlen($sRfc822SubMimeIndex))
- {
- $oBodyStructure = BodyStructure::NewInstanceFromRfc822SubPart($aBodyStructureArray, $sRfc822SubMimeIndex);
- }
- else
- {
- $oBodyStructure = BodyStructure::NewInstance($aBodyStructureArray);
- }
- }
-
- return $oBodyStructure;
- }
-
- /**
- * @param string $sFetchItemName
- *
- * @return mixed
- */
- public function GetFetchValue($sFetchItemName)
- {
- $mReturn = null;
- $bNextIsValue = false;
-
- if (Enumerations\FetchType::INDEX === $sFetchItemName)
- {
- $mReturn = $this->oImapResponse->ResponseList[1];
- }
- else if (isset($this->oImapResponse->ResponseList[3]) && \is_array($this->oImapResponse->ResponseList[3]))
- {
- foreach ($this->oImapResponse->ResponseList[3] as $mItem)
- {
- if ($bNextIsValue)
- {
- $mReturn = $mItem;
- break;
- }
-
- if ($sFetchItemName === $mItem)
- {
- $bNextIsValue = true;
- }
- }
- }
-
- return $mReturn;
- }
-
- /**
- * @param string $sRfc822SubMimeIndex = ''
- *
- * @return string
- */
- public function GetHeaderFieldsValue($sRfc822SubMimeIndex = '')
- {
- $sReturn = '';
- $bNextIsValue = false;
-
- $sRfc822SubMimeIndex = 0 < \strlen($sRfc822SubMimeIndex) ? ''.$sRfc822SubMimeIndex.'.' : '';
-
- if (isset($this->oImapResponse->ResponseList[3]) && \is_array($this->oImapResponse->ResponseList[3]))
- {
- foreach ($this->oImapResponse->ResponseList[3] as $mItem)
- {
- if ($bNextIsValue)
- {
- $sReturn = (string) $mItem;
- break;
- }
-
- if (\is_string($mItem) && (
- $mItem === 'BODY['.$sRfc822SubMimeIndex.'HEADER]' ||
- 0 === \strpos($mItem, 'BODY['.$sRfc822SubMimeIndex.'HEADER.FIELDS') ||
- $mItem === 'BODY['.$sRfc822SubMimeIndex.'MIME]'))
- {
- $bNextIsValue = true;
- }
- }
- }
-
- return $sReturn;
- }
-
- private static function findFetchUidAndSize($aList)
- {
- $bUid = false;
- $bSize = false;
- if (is_array($aList))
- {
- foreach ($aList as $mItem)
- {
- if (\MailSo\Imap\Enumerations\FetchType::UID === $mItem)
- {
- $bUid = true;
- }
- else if (\MailSo\Imap\Enumerations\FetchType::RFC822_SIZE === $mItem)
- {
- $bSize = true;
- }
- }
- }
-
- return $bUid && $bSize;
- }
-
- /**
- * @param \MailSo\Imap\Response $oImapResponse
- *
- * @return bool
- */
- public static function IsValidFetchImapResponse($oImapResponse)
- {
- return (
- $oImapResponse
- && true !== $oImapResponse->IsStatusResponse
- && \MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType
- && 3 < count($oImapResponse->ResponseList) && 'FETCH' === $oImapResponse->ResponseList[2]
- && is_array($oImapResponse->ResponseList[3])
- );
- }
-
- /**
- * @param \MailSo\Imap\Response $oImapResponse
- *
- * @return bool
- */
- public static function IsNotEmptyFetchImapResponse($oImapResponse)
- {
- return (
- $oImapResponse
- && self::IsValidFetchImapResponse($oImapResponse)
- && isset($oImapResponse->ResponseList[3])
- && self::findFetchUidAndSize($oImapResponse->ResponseList[3])
- );
- }
-
- /**
- * @param array $aEnvelope
- * @param int $iIndex
- * @param mixed $mNullResult = null
- *
- * @return mixed
- */
- private static function findEnvelopeIndex($aEnvelope, $iIndex, $mNullResult)
- {
- return (isset($aEnvelope[$iIndex]) && 'NIL' !== $aEnvelope[$iIndex] && '' !== $aEnvelope[$iIndex])
- ? $aEnvelope[$iIndex] : $mNullResult;
- }
-}
+oImapResponse = $oImapResponse;
+ $this->aEnvelopeCache = null;
+ }
+
+ /**
+ * @param \MailSo\Imap\Response $oImapResponse
+ * @return \MailSo\Imap\FetchResponse
+ */
+ public static function NewInstance($oImapResponse)
+ {
+ return new self($oImapResponse);
+ }
+
+ /**
+ * @param bool $bForce = false
+ *
+ * @return array|null
+ */
+ public function GetEnvelope($bForce = false)
+ {
+ if (null === $this->aEnvelopeCache || $bForce)
+ {
+ $this->aEnvelopeCache = $this->GetFetchValue(Enumerations\FetchType::ENVELOPE);
+ }
+ return $this->aEnvelopeCache;
+ }
+
+ /**
+ * @param int $iIndex
+ * @param mixed $mNullResult = null
+ *
+ * @return mixed
+ */
+ public function GetFetchEnvelopeValue($iIndex, $mNullResult)
+ {
+ return self::findEnvelopeIndex($this->GetEnvelope(), $iIndex, $mNullResult);
+ }
+
+ /**
+ * @param int $iIndex
+ * @param string $sParentCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1
+ *
+ * @return \MailSo\Mime\EmailCollection|null
+ */
+ public function GetFetchEnvelopeEmailCollection($iIndex, $sParentCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1)
+ {
+ $oResult = null;
+ $aEmails = $this->GetFetchEnvelopeValue($iIndex, null);
+ if (is_array($aEmails) && 0 < count($aEmails))
+ {
+ $oResult = \MailSo\Mime\EmailCollection::NewInstance();
+ foreach ($aEmails as $aEmailItem)
+ {
+ if (is_array($aEmailItem) && 4 === count($aEmailItem))
+ {
+ $sDisplayName = \MailSo\Base\Utils::DecodeHeaderValue(
+ self::findEnvelopeIndex($aEmailItem, 0, ''), $sParentCharset);
+
+// $sRemark = \MailSo\Base\Utils::DecodeHeaderValue(
+// self::findEnvelopeIndex($aEmailItem, 1, ''), $sParentCharset);
+
+ $sLocalPart = self::findEnvelopeIndex($aEmailItem, 2, '');
+ $sDomainPart = self::findEnvelopeIndex($aEmailItem, 3, '');
+
+ if (0 < strlen($sLocalPart) && 0 < strlen($sDomainPart))
+ {
+ $oResult->Add(
+ \MailSo\Mime\Email::NewInstance($sLocalPart.'@'.$sDomainPart, $sDisplayName)
+ );
+ }
+ }
+ }
+ }
+
+ return $oResult;
+ }
+
+ /**
+ * @param string $sRfc822SubMimeIndex = ''
+ *
+ * @return \MailSo\Imap\BodyStructure|null
+ */
+ public function GetFetchBodyStructure($sRfc822SubMimeIndex = '')
+ {
+ $oBodyStructure = null;
+ $aBodyStructureArray = $this->GetFetchValue(Enumerations\FetchType::BODYSTRUCTURE);
+
+ if (is_array($aBodyStructureArray))
+ {
+ if (0 < strlen($sRfc822SubMimeIndex))
+ {
+ $oBodyStructure = BodyStructure::NewInstanceFromRfc822SubPart($aBodyStructureArray, $sRfc822SubMimeIndex);
+ }
+ else
+ {
+ $oBodyStructure = BodyStructure::NewInstance($aBodyStructureArray);
+ }
+ }
+
+ return $oBodyStructure;
+ }
+
+ /**
+ * @param string $sFetchItemName
+ *
+ * @return mixed
+ */
+ public function GetFetchValue($sFetchItemName)
+ {
+ $mReturn = null;
+ $bNextIsValue = false;
+
+ if (Enumerations\FetchType::INDEX === $sFetchItemName)
+ {
+ $mReturn = $this->oImapResponse->ResponseList[1];
+ }
+ else if (isset($this->oImapResponse->ResponseList[3]) && \is_array($this->oImapResponse->ResponseList[3]))
+ {
+ foreach ($this->oImapResponse->ResponseList[3] as $mItem)
+ {
+ if ($bNextIsValue)
+ {
+ $mReturn = $mItem;
+ break;
+ }
+
+ if ($sFetchItemName === $mItem)
+ {
+ $bNextIsValue = true;
+ }
+ }
+ }
+
+ return $mReturn;
+ }
+
+ /**
+ * @param string $sRfc822SubMimeIndex = ''
+ *
+ * @return string
+ */
+ public function GetHeaderFieldsValue($sRfc822SubMimeIndex = '')
+ {
+ $sReturn = '';
+ $bNextIsValue = false;
+
+ $sRfc822SubMimeIndex = 0 < \strlen($sRfc822SubMimeIndex) ? ''.$sRfc822SubMimeIndex.'.' : '';
+
+ if (isset($this->oImapResponse->ResponseList[3]) && \is_array($this->oImapResponse->ResponseList[3]))
+ {
+ foreach ($this->oImapResponse->ResponseList[3] as $mItem)
+ {
+ if ($bNextIsValue)
+ {
+ $sReturn = (string) $mItem;
+ break;
+ }
+
+ if (\is_string($mItem) && (
+ $mItem === 'BODY['.$sRfc822SubMimeIndex.'HEADER]' ||
+ 0 === \strpos($mItem, 'BODY['.$sRfc822SubMimeIndex.'HEADER.FIELDS') ||
+ $mItem === 'BODY['.$sRfc822SubMimeIndex.'MIME]'))
+ {
+ $bNextIsValue = true;
+ }
+ }
+ }
+
+ return $sReturn;
+ }
+
+ private static function findFetchUidAndSize($aList)
+ {
+ $bUid = false;
+ $bSize = false;
+ if (is_array($aList))
+ {
+ foreach ($aList as $mItem)
+ {
+ if (\MailSo\Imap\Enumerations\FetchType::UID === $mItem)
+ {
+ $bUid = true;
+ }
+ else if (\MailSo\Imap\Enumerations\FetchType::RFC822_SIZE === $mItem)
+ {
+ $bSize = true;
+ }
+ }
+ }
+
+ return $bUid && $bSize;
+ }
+
+ /**
+ * @param \MailSo\Imap\Response $oImapResponse
+ *
+ * @return bool
+ */
+ public static function IsValidFetchImapResponse($oImapResponse)
+ {
+ return (
+ $oImapResponse
+ && true !== $oImapResponse->IsStatusResponse
+ && \MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType
+ && 3 < count($oImapResponse->ResponseList) && 'FETCH' === $oImapResponse->ResponseList[2]
+ && is_array($oImapResponse->ResponseList[3])
+ );
+ }
+
+ /**
+ * @param \MailSo\Imap\Response $oImapResponse
+ *
+ * @return bool
+ */
+ public static function IsNotEmptyFetchImapResponse($oImapResponse)
+ {
+ return (
+ $oImapResponse
+ && self::IsValidFetchImapResponse($oImapResponse)
+ && isset($oImapResponse->ResponseList[3])
+ && self::findFetchUidAndSize($oImapResponse->ResponseList[3])
+ );
+ }
+
+ /**
+ * @param array $aEnvelope
+ * @param int $iIndex
+ * @param mixed $mNullResult = null
+ *
+ * @return mixed
+ */
+ private static function findEnvelopeIndex($aEnvelope, $iIndex, $mNullResult)
+ {
+ return (isset($aEnvelope[$iIndex]) && 'NIL' !== $aEnvelope[$iIndex] && '' !== $aEnvelope[$iIndex])
+ ? $aEnvelope[$iIndex] : $mNullResult;
+ }
+}
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Imap/Folder.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/Folder.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Imap/Folder.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/Folder.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Imap/FolderInformation.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/FolderInformation.php
similarity index 93%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Imap/FolderInformation.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/FolderInformation.php
index bc7118d593d49dc2ac2f91ea71c6675d18da1a72..d8fe5a0e2c0f09692202d903f9436447bd6cbe1b 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Imap/FolderInformation.php
+++ b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/FolderInformation.php
@@ -1,112 +1,112 @@
-FolderName = $sFolderName;
- $this->IsWritable = $bIsWritable;
- $this->Exists = null;
- $this->Recent = null;
- $this->Flags = array();
- $this->PermanentFlags = array();
-
- $this->Unread = null;
- $this->Uidnext = null;
- $this->HighestModSeq = null;
- }
-
- /**
- * @param string $sFolderName
- * @param bool $bIsWritable
- *
- * @return \MailSo\Imap\FolderInformation
- */
- public static function NewInstance($sFolderName, $bIsWritable)
- {
- return new self($sFolderName, $bIsWritable);
- }
-
- /**
- * @param string $sFlag
- *
- * @return bool
- */
- public function IsFlagSupported($sFlag)
- {
- return \in_array('\\*', $this->PermanentFlags) ||
- \in_array($sFlag, $this->PermanentFlags) ||
- \in_array($sFlag, $this->Flags);
- }
-}
+FolderName = $sFolderName;
+ $this->IsWritable = $bIsWritable;
+ $this->Exists = null;
+ $this->Recent = null;
+ $this->Flags = array();
+ $this->PermanentFlags = array();
+
+ $this->Unread = null;
+ $this->Uidnext = null;
+ $this->HighestModSeq = null;
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param bool $bIsWritable
+ *
+ * @return \MailSo\Imap\FolderInformation
+ */
+ public static function NewInstance($sFolderName, $bIsWritable)
+ {
+ return new self($sFolderName, $bIsWritable);
+ }
+
+ /**
+ * @param string $sFlag
+ *
+ * @return bool
+ */
+ public function IsFlagSupported($sFlag)
+ {
+ return \in_array('\\*', $this->PermanentFlags) ||
+ \in_array($sFlag, $this->PermanentFlags) ||
+ \in_array($sFlag, $this->Flags);
+ }
+}
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Imap/ImapClient.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/ImapClient.php
similarity index 96%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Imap/ImapClient.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/ImapClient.php
index 9e01e2c12df69a01001081872df18ce876ad2f12..19aa9a51e93b0377c0b7dad2cf6e4867ff094a3c 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Imap/ImapClient.php
+++ b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/ImapClient.php
@@ -1,2667 +1,2667 @@
-iTagCount = 0;
- $this->aCapabilityItems = null;
- $this->oCurrentFolderInfo = null;
- $this->aFetchCallbacks = null;
- $this->iResponseBufParsedPos = 0;
-
- $this->aLastResponse = array();
- $this->bNeedNext = true;
- $this->aPartialResponses = array();
-
- $this->aTagTimeouts = array();
-
- $this->bIsLoggined = false;
- $this->bIsSelected = false;
- $this->sLogginedUser = '';
-
- $this->__FORCE_SELECT_ON_EXAMINE__ = false;
-
- @\ini_set('xdebug.max_nesting_level', 500);
- }
-
- /**
- * @return \MailSo\Imap\ImapClient
- */
- public static function NewInstance()
- {
- return new self();
- }
-
- /**
- * @return string
- */
- public function GetLogginedUser()
- {
- return $this->sLogginedUser;
- }
-
- /**
- * @param string $sServerName
- * @param int $iPort = 143
- * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT
- * @param bool $bVerifySsl = false
- * @param bool $bAllowSelfSigned = true
- *
- * @return \MailSo\Imap\ImapClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function Connect($sServerName, $iPort = 143,
- $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT,
- $bVerifySsl = false, $bAllowSelfSigned = true)
- {
- $this->aTagTimeouts['*'] = \microtime(true);
-
- parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned);
-
- $this->parseResponseWithValidation('*', true);
-
- if (\MailSo\Net\Enumerations\ConnectionSecurityType::UseStartTLS(
- $this->IsSupported('STARTTLS'), $this->iSecurityType))
- {
- $this->SendRequestWithCheck('STARTTLS');
- $this->EnableCrypto();
-
- $this->aCapabilityItems = null;
- }
- else if (\MailSo\Net\Enumerations\ConnectionSecurityType::STARTTLS === $this->iSecurityType)
- {
- $this->writeLogException(
- new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('STARTTLS is not supported'),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- return $this;
- }
-
- protected function _xor($string, $string2)
- {
- $result = '';
- $size = strlen($string);
- for ($i=0; $i<$size; $i++) {
- $result .= chr(ord($string[$i]) ^ ord($string2[$i]));
- }
- return $result;
- }
-
- /**
- * @param string $sLogin
- * @param string $sPassword
- * @param string $sProxyAuthUser = ''
- * @param bool $bUseAuthPlainIfSupported = true
- * @param bool $bUseAuthCramMd5IfSupported = true
- *
- * @return \MailSo\Imap\ImapClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function Login($sLogin, $sPassword, $sProxyAuthUser = '',
- $bUseAuthPlainIfSupported = true, $bUseAuthCramMd5IfSupported = true)
- {
- if (!\MailSo\Base\Validator::NotEmptyString($sLogin, true) ||
- !\MailSo\Base\Validator::NotEmptyString($sPassword, true))
- {
- $this->writeLogException(
- new \MailSo\Base\Exceptions\InvalidArgumentException(),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- $sLogin = \MailSo\Base\Utils::IdnToAscii(\MailSo\Base\Utils::Trim($sLogin));
-
- $sPassword = $sPassword;
-
- $this->sLogginedUser = $sLogin;
-
- try
- {
- if ($bUseAuthCramMd5IfSupported && $this->IsSupported('AUTH=CRAM-MD5'))
- {
- $this->SendRequest('AUTHENTICATE', array('CRAM-MD5'));
-
- $aResponse = $this->parseResponseWithValidation();
- if ($aResponse && \is_array($aResponse) && 0 < \count($aResponse) &&
- \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $aResponse[\count($aResponse) - 1]->ResponseType)
- {
- $oContinuationResponse = null;
- foreach ($aResponse as $oResponse)
- {
- if ($oResponse && \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oResponse->ResponseType)
- {
- $oContinuationResponse = $oResponse;
- }
- }
-
- if ($oContinuationResponse && !empty($oContinuationResponse->ResponseList[1]))
- {
- $sTicket = @\base64_decode($oContinuationResponse->ResponseList[1]);
- $this->oLogger->Write('ticket: '.$sTicket);
-
- $sToken = \base64_encode($sLogin.' '.\MailSo\Base\Utils::Hmac($sTicket, $sPassword));
-
- if ($this->oLogger)
- {
- $this->oLogger->AddSecret($sToken);
- }
-
- $this->sendRaw($sToken, true, '*******');
- $this->parseResponseWithValidation();
- }
- else
- {
- $this->writeLogException(
- new \MailSo\Imap\Exceptions\LoginException(),
- \MailSo\Log\Enumerations\Type::NOTICE, true);
- }
- }
- else
- {
- $this->writeLogException(
- new \MailSo\Imap\Exceptions\LoginException(),
- \MailSo\Log\Enumerations\Type::NOTICE, true);
- }
- }
- else if ($bUseAuthPlainIfSupported && $this->IsSupported('AUTH=PLAIN'))
- {
- $sToken = \base64_encode("\0".$sLogin."\0".$sPassword);
- if ($this->oLogger)
- {
- $this->oLogger->AddSecret($sToken);
- }
-
- if ($this->IsSupported('AUTH=SASL-IR') && false)
- {
- $this->SendRequestWithCheck('AUTHENTICATE', array('PLAIN', $sToken));
- }
- else
- {
- $this->SendRequest('AUTHENTICATE', array('PLAIN'));
- $this->parseResponseWithValidation();
-
- $this->sendRaw($sToken, true, '*******');
- $this->parseResponseWithValidation();
- }
- }
- else
- {
- if ($this->oLogger)
- {
- $this->oLogger->AddSecret($this->EscapeString($sPassword));
- }
-
- $this->SendRequestWithCheck('LOGIN',
- array(
- $this->EscapeString($sLogin),
- $this->EscapeString($sPassword)
- ));
- }
-// else
-// {
-// $this->writeLogException(
-// new \MailSo\Imap\Exceptions\LoginBadMethodException(),
-// \MailSo\Log\Enumerations\Type::NOTICE, true);
-// }
-
- if (0 < \strlen($sProxyAuthUser))
- {
- $this->SendRequestWithCheck('PROXYAUTH', array($this->EscapeString($sProxyAuthUser)));
- }
- }
- catch (\MailSo\Imap\Exceptions\NegativeResponseException $oException)
- {
- $this->writeLogException(
- new \MailSo\Imap\Exceptions\LoginBadCredentialsException(
- $oException->GetResponses(), '', 0, $oException),
- \MailSo\Log\Enumerations\Type::NOTICE, true);
- }
-
- $this->bIsLoggined = true;
- $this->aCapabilityItems = null;
-
- return $this;
- }
-
- /**
- * @param string $sXOAuth2Token
- *
- * @return \MailSo\Imap\ImapClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function LoginWithXOauth2($sXOAuth2Token)
- {
- if (!\MailSo\Base\Validator::NotEmptyString($sXOAuth2Token, true))
- {
- $this->writeLogException(
- new \MailSo\Base\Exceptions\InvalidArgumentException(),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- if (!$this->IsSupported('AUTH=XOAUTH2'))
- {
- $this->writeLogException(
- new \MailSo\Imap\Exceptions\LoginBadMethodException(),
- \MailSo\Log\Enumerations\Type::NOTICE, true);
- }
-
- try
- {
- $this->SendRequest('AUTHENTICATE', array('XOAUTH2', \trim($sXOAuth2Token)));
- $aR = $this->parseResponseWithValidation();
-
- if (\is_array($aR) && 0 < \count($aR) && isset($aR[\count($aR) - 1]))
- {
- $oR = $aR[\count($aR) - 1];
- if (\MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oR->ResponseType)
- {
- if (!empty($oR->ResponseList[1]) && preg_match('/^[a-zA-Z0-9=+\/]+$/', $oR->ResponseList[1]))
- {
- $this->Logger()->Write(\base64_decode($oR->ResponseList[1]),
- \MailSo\Log\Enumerations\Type::WARNING);
- }
-
- $this->sendRaw('');
- $this->parseResponseWithValidation();
- }
- }
- }
- catch (\MailSo\Imap\Exceptions\NegativeResponseException $oException)
- {
- $this->writeLogException(
- new \MailSo\Imap\Exceptions\LoginBadCredentialsException(
- $oException->GetResponses(), '', 0, $oException),
- \MailSo\Log\Enumerations\Type::NOTICE, true);
- }
-
- $this->bIsLoggined = true;
- $this->aCapabilityItems = null;
-
- return $this;
- }
-
- /**
- * @return \MailSo\Imap\ImapClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- */
- public function Logout()
- {
- if ($this->bIsLoggined)
- {
- $this->bIsLoggined = false;
- $this->SendRequestWithCheck('LOGOUT', array());
- }
-
- return $this;
- }
-
- /**
- * @return \MailSo\Imap\ImapClient
- */
- public function ForceCloseConnection()
- {
- $this->Disconnect();
-
- return $this;
- }
-
- /**
- * @return bool
- */
- public function IsLoggined()
- {
- return $this->IsConnected() && $this->bIsLoggined;
- }
-
- /**
- * @return bool
- */
- public function IsSelected()
- {
- return $this->IsLoggined() && $this->bIsSelected;
- }
-
- /**
- * @return array|null
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function Capability()
- {
- $this->SendRequestWithCheck('CAPABILITY', array(), true);
- return $this->aCapabilityItems;
- }
-
- /**
- * @param string $sExtentionName
- * @return bool
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function IsSupported($sExtentionName)
- {
- $bResult = \MailSo\Base\Validator::NotEmptyString($sExtentionName, true);
- if ($bResult && null === $this->aCapabilityItems)
- {
- $this->aCapabilityItems = $this->Capability();
- }
-
- return $bResult && \is_array($this->aCapabilityItems) &&
- \in_array(\strtoupper($sExtentionName), $this->aCapabilityItems);
- }
-
- /**
- * @return \MailSo\Imap\NamespaceResult|null
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function GetNamespace()
- {
- if (!$this->IsSupported('NAMESPACE'))
- {
- return null;
- }
-
- $oReturn = false;
-
- $this->SendRequest('NAMESPACE');
- $aResult = $this->parseResponseWithValidation();
-
- $oImapResponse = null;
- foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
- {
- if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType &&
- 'NAMESPACE' === $oImapResponse->StatusOrIndex)
- {
- $oReturn = NamespaceResult::NewInstance();
- $oReturn->InitByImapResponse($oImapResponse);
- break;
- }
- }
-
- if (false === $oReturn)
- {
- $this->writeLogException(
- new \MailSo\Imap\Exceptions\ResponseException(),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- return $oReturn;
- }
-
- /**
- * @return \MailSo\Imap\ImapClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function Noop()
- {
- return $this->SendRequestWithCheck('NOOP');
- }
-
- /**
- * @param string $sFolderName
- *
- * @return \MailSo\Imap\ImapClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function FolderCreate($sFolderName)
- {
- return $this->SendRequestWithCheck('CREATE',
- array($this->EscapeString($sFolderName)));
- }
-
- /**
- * @param string $sFolderName
- *
- * @return \MailSo\Imap\ImapClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function FolderDelete($sFolderName)
- {
- return $this->SendRequestWithCheck('DELETE',
- array($this->EscapeString($sFolderName)));
- }
-
- /**
- * @param string $sFolderName
- *
- * @return \MailSo\Imap\ImapClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function FolderSubscribe($sFolderName)
- {
- return $this->SendRequestWithCheck('SUBSCRIBE',
- array($this->EscapeString($sFolderName)));
- }
-
- /**
- * @param string $sFolderName
- *
- * @return \MailSo\Imap\ImapClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function FolderUnSubscribe($sFolderName)
- {
- return $this->SendRequestWithCheck('UNSUBSCRIBE',
- array($this->EscapeString($sFolderName)));
- }
-
- /**
- * @param string $sOldFolderName
- * @param string $sNewFolderName
- *
- * @return \MailSo\Imap\ImapClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function FolderRename($sOldFolderName, $sNewFolderName)
- {
- return $this->SendRequestWithCheck('RENAME', array(
- $this->EscapeString($sOldFolderName),
- $this->EscapeString($sNewFolderName)));
- }
-
- /**
- * @param array $aResult
- *
- * @return array
- */
- protected function getStatusFolderInformation($aResult)
- {
- $aReturn = array();
-
- if (\is_array($aResult))
- {
- $oImapResponse = null;
- foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
- {
- if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType &&
- 'STATUS' === $oImapResponse->StatusOrIndex && isset($oImapResponse->ResponseList[3]) &&
- \is_array($oImapResponse->ResponseList[3]))
- {
- $sName = null;
- foreach ($oImapResponse->ResponseList[3] as $sArrayItem)
- {
- if (null === $sName)
- {
- $sName = $sArrayItem;
- }
- else
- {
- $aReturn[$sName] = $sArrayItem;
- $sName = null;
- }
- }
- }
- }
- }
-
- return $aReturn;
- }
-
- /**
- * @param string $sFolderName
- * @param array $aStatusItems
- *
- * @return array|bool
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function FolderStatus($sFolderName, array $aStatusItems)
- {
- $aResult = false;
- if (\count($aStatusItems) > 0)
- {
- $this->SendRequest('STATUS',
- array($this->EscapeString($sFolderName), $aStatusItems));
-
- $aResult = $this->getStatusFolderInformation(
- $this->parseResponseWithValidation());
- }
-
- return $aResult;
- }
-
- /**
- * @param array $aResult
- * @param string $sStatus
- * @param bool $bUseListStatus = false
- *
- * @return array
- */
- private function getFoldersFromResult(array $aResult, $sStatus, $bUseListStatus = false)
- {
- $aReturn = array();
-
- $sDelimiter = '';
- $bInbox = false;
-
- $oImapResponse = null;
- foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
- {
- if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType &&
- $sStatus === $oImapResponse->StatusOrIndex && 5 === count($oImapResponse->ResponseList))
- {
- try
- {
- $oFolder = Folder::NewInstance($oImapResponse->ResponseList[4],
- $oImapResponse->ResponseList[3], $oImapResponse->ResponseList[2]);
-
- if ($oFolder->IsInbox())
- {
- $bInbox = true;
- }
-
- if (empty($sDelimiter))
- {
- $sDelimiter = $oFolder->Delimiter();
- }
-
- $aReturn[] = $oFolder;
- }
- catch (\MailSo\Base\Exceptions\InvalidArgumentException $oException)
- {
- $this->writeLogException($oException, \MailSo\Log\Enumerations\Type::WARNING, false);
- }
- }
- }
-
- if (!$bInbox && !empty($sDelimiter))
- {
- $aReturn[] = Folder::NewInstance('INBOX', $sDelimiter);
- }
-
- if ($bUseListStatus)
- {
- foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
- {
- if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType &&
- 'STATUS' === $oImapResponse->StatusOrIndex &&
- isset($oImapResponse->ResponseList[2]) &&
- isset($oImapResponse->ResponseList[3]) &&
- \is_array($oImapResponse->ResponseList[3]))
- {
- $sFolderNameRaw = $oImapResponse->ResponseList[2];
-
- $oCurrentFolder = null;
- foreach ($aReturn as &$oFolder)
- {
- if ($oFolder && $sFolderNameRaw === $oFolder->FullNameRaw())
- {
- $oCurrentFolder =& $oFolder;
- break;
- }
- }
-
- if (null !== $oCurrentFolder)
- {
- $sName = null;
- $aStatus = array();
-
- foreach ($oImapResponse->ResponseList[3] as $sArrayItem)
- {
- if (null === $sName)
- {
- $sName = $sArrayItem;
- }
- else
- {
- $aStatus[$sName] = $sArrayItem;
- $sName = null;
- }
- }
-
- if (0 < count($aStatus))
- {
- $oCurrentFolder->SetExtended('STATUS', $aStatus);
- }
- }
-
- unset($oCurrentFolder);
- }
- }
- }
-
- return $aReturn;
- }
-
- /**
- * @param bool $bIsSubscribeList
- * @param string $sParentFolderName = ''
- * @param string $sListPattern = '*'
- * @param bool $bUseListStatus = false
- *
- * @return array
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- private function specificFolderList($bIsSubscribeList, $sParentFolderName = '', $sListPattern = '*', $bUseListStatus = false)
- {
- $sCmd = 'LSUB';
- if (!$bIsSubscribeList)
- {
- $sCmd = 'LIST';
- }
-
- $sListPattern = 0 === strlen(trim($sListPattern)) ? '*' : $sListPattern;
-
- $aParameters = array(
- $this->EscapeString($sParentFolderName),
- $this->EscapeString($sListPattern)
- );
-
- if ($bUseListStatus && !$bIsSubscribeList && $this->IsSupported('LIST-STATUS'))
- {
- $aL = array(
- \MailSo\Imap\Enumerations\FolderStatus::MESSAGES,
- \MailSo\Imap\Enumerations\FolderStatus::UNSEEN,
- \MailSo\Imap\Enumerations\FolderStatus::UIDNEXT
- );
-
-// if ($this->IsSupported('CONDSTORE'))
-// {
-// $aL[] = \MailSo\Imap\Enumerations\FolderStatus::HIGHESTMODSEQ;
-// }
-
- $aParameters[] = 'RETURN';
- $aParameters[] = array('STATUS', $aL);
- }
- else
- {
- $bUseListStatus = false;
- }
-
- $this->SendRequest($sCmd, $aParameters);
-
- return $this->getFoldersFromResult(
- $this->parseResponseWithValidation(), $sCmd, $bUseListStatus);
- }
-
- /**
- * @param string $sParentFolderName = ''
- * @param string $sListPattern = '*'
- *
- * @return array
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function FolderList($sParentFolderName = '', $sListPattern = '*')
- {
- return $this->specificFolderList(false, $sParentFolderName, $sListPattern);
- }
-
- /**
- * @param string $sParentFolderName = ''
- * @param string $sListPattern = '*'
- *
- * @return array
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function FolderSubscribeList($sParentFolderName = '', $sListPattern = '*')
- {
- return $this->specificFolderList(true, $sParentFolderName, $sListPattern);
- }
-
- /**
- * @param string $sParentFolderName = ''
- * @param string $sListPattern = '*'
- *
- * @return array
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function FolderStatusList($sParentFolderName = '', $sListPattern = '*')
- {
- return $this->specificFolderList(false, $sParentFolderName, $sListPattern, true);
- }
-
- /**
- * @param array $aResult
- * @param string $sFolderName
- * @param bool $bIsWritable
- *
- * @return void
- */
- protected function initCurrentFolderInformation($aResult, $sFolderName, $bIsWritable)
- {
- if (\is_array($aResult))
- {
- $oImapResponse = null;
- $oResult = FolderInformation::NewInstance($sFolderName, $bIsWritable);
-
- foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
- {
- if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType)
- {
- if (\count($oImapResponse->ResponseList) > 2 &&
- 'FLAGS' === $oImapResponse->ResponseList[1] && \is_array($oImapResponse->ResponseList[2]))
- {
- $oResult->Flags = $oImapResponse->ResponseList[2];
- }
-
- if (is_array($oImapResponse->OptionalResponse) && \count($oImapResponse->OptionalResponse) > 1)
- {
- if ('PERMANENTFLAGS' === $oImapResponse->OptionalResponse[0] &&
- is_array($oImapResponse->OptionalResponse[1]))
- {
- $oResult->PermanentFlags = $oImapResponse->OptionalResponse[1];
- }
- else if ('UIDVALIDITY' === $oImapResponse->OptionalResponse[0] &&
- isset($oImapResponse->OptionalResponse[1]))
- {
- $oResult->Uidvalidity = $oImapResponse->OptionalResponse[1];
- }
- else if ('UNSEEN' === $oImapResponse->OptionalResponse[0] &&
- isset($oImapResponse->OptionalResponse[1]) &&
- is_numeric($oImapResponse->OptionalResponse[1]))
- {
- $oResult->Unread = (int) $oImapResponse->OptionalResponse[1];
- }
- else if ('UIDNEXT' === $oImapResponse->OptionalResponse[0] &&
- isset($oImapResponse->OptionalResponse[1]))
- {
- $oResult->Uidnext = $oImapResponse->OptionalResponse[1];
- }
- else if ('HIGHESTMODSEQ' === $oImapResponse->OptionalResponse[0] &&
- isset($oImapResponse->OptionalResponse[1]) &&
- \is_numeric($oImapResponse->OptionalResponse[1]))
- {
- $oResult->HighestModSeq = \trim($oImapResponse->OptionalResponse[1]);
- }
- }
-
- if (\count($oImapResponse->ResponseList) > 2 &&
- \is_string($oImapResponse->ResponseList[2]) &&
- \is_numeric($oImapResponse->ResponseList[1]))
- {
- switch($oImapResponse->ResponseList[2])
- {
- case 'EXISTS':
- $oResult->Exists = (int) $oImapResponse->ResponseList[1];
- break;
- case 'RECENT':
- $oResult->Recent = (int) $oImapResponse->ResponseList[1];
- break;
- }
- }
- }
- }
-
- $this->oCurrentFolderInfo = $oResult;
- }
- }
-
- /**
- * @param string $sFolderName
- * @param bool $bIsWritable
- * @param bool $bReSelectSameFolders
- *
- * @return \MailSo\Imap\ImapClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- protected function selectOrExamineFolder($sFolderName, $bIsWritable, $bReSelectSameFolders)
- {
- if (!$bReSelectSameFolders)
- {
- if ($this->oCurrentFolderInfo &&
- $sFolderName === $this->oCurrentFolderInfo->FolderName &&
- $bIsWritable === $this->oCurrentFolderInfo->IsWritable)
- {
- return $this;
- }
- }
-
- if (!\MailSo\Base\Validator::NotEmptyString($sFolderName, true))
- {
- throw new \MailSo\Base\Exceptions\InvalidArgumentException();
- }
-
- $this->SendRequest(($bIsWritable) ? 'SELECT' : 'EXAMINE',
- array($this->EscapeString($sFolderName)));
-
- $this->initCurrentFolderInformation(
- $this->parseResponseWithValidation(), $sFolderName, $bIsWritable);
-
- $this->bIsSelected = true;
-
- return $this;
- }
-
- /**
- * @param string $sFolderName
- * @param bool $bReSelectSameFolders = false
- *
- * @return \MailSo\Imap\ImapClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function FolderSelect($sFolderName, $bReSelectSameFolders = false)
- {
- return $this->selectOrExamineFolder($sFolderName, true, $bReSelectSameFolders);
- }
-
- /**
- * @param string $sFolderName
- * @param bool $bReSelectSameFolders = false
- *
- * @return \MailSo\Imap\ImapClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function FolderExamine($sFolderName, $bReSelectSameFolders = false)
- {
- return $this->selectOrExamineFolder($sFolderName, $this->__FORCE_SELECT_ON_EXAMINE__, $bReSelectSameFolders);
- }
-
- /**
- * @return \MailSo\Imap\ImapClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function FolderUnSelect()
- {
- if ($this->IsSelected() && $this->IsSupported('UNSELECT'))
- {
- $this->SendRequestWithCheck('UNSELECT');
- $this->bIsSelected = false;
- }
-
- return $this;
- }
-
- /**
- * @param array $aInputFetchItems
- * @param string $sIndexRange
- * @param bool $bIndexIsUid
- *
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function Fetch(array $aInputFetchItems, $sIndexRange, $bIndexIsUid)
- {
- $sIndexRange = (string) $sIndexRange;
- if (!\MailSo\Base\Validator::NotEmptyString($sIndexRange, true))
- {
- $this->writeLogException(
- new \MailSo\Base\Exceptions\InvalidArgumentException(),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- $aFetchItems = \MailSo\Imap\Enumerations\FetchType::ChangeFetchItemsBefourRequest($aInputFetchItems);
- foreach ($aFetchItems as $sName => $mItem)
- {
- if (0 < \strlen($sName) && '' !== $mItem)
- {
- if (null === $this->aFetchCallbacks)
- {
- $this->aFetchCallbacks = array();
- }
-
- $this->aFetchCallbacks[$sName] = $mItem;
- }
- }
-
- $this->SendRequest((($bIndexIsUid) ? 'UID ' : '').'FETCH', array($sIndexRange, \array_keys($aFetchItems)));
- $aResult = $this->validateResponse($this->parseResponse());
- $this->aFetchCallbacks = null;
-
- $aReturn = array();
- $oImapResponse = null;
- foreach ($aResult as $oImapResponse)
- {
- if (FetchResponse::IsValidFetchImapResponse($oImapResponse))
- {
- if (FetchResponse::IsNotEmptyFetchImapResponse($oImapResponse))
- {
- $aReturn[] = FetchResponse::NewInstance($oImapResponse);
- }
- else
- {
- if ($this->oLogger)
- {
- $this->oLogger->Write('Skipped Imap Response! ['.$oImapResponse->ToLine().']', \MailSo\Log\Enumerations\Type::NOTICE);
- }
- }
- }
- }
-
- return $aReturn;
- }
-
-
- /**
- * @return array|false
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function Quota()
- {
- $aReturn = false;
- if ($this->IsSupported('QUOTA'))
- {
- $this->SendRequest('GETQUOTAROOT "INBOX"');
- $aResult = $this->parseResponseWithValidation();
-
- $aReturn = array(0, 0);
- $oImapResponse = null;
- foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
- {
- if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType
- && 'QUOTA' === $oImapResponse->StatusOrIndex
- && \is_array($oImapResponse->ResponseList)
- && isset($oImapResponse->ResponseList[3])
- && \is_array($oImapResponse->ResponseList[3])
- && 2 < \count($oImapResponse->ResponseList[3])
- && 'STORAGE' === \strtoupper($oImapResponse->ResponseList[3][0])
- && \is_numeric($oImapResponse->ResponseList[3][1])
- && \is_numeric($oImapResponse->ResponseList[3][2])
- )
- {
- $aReturn = array(
- (int) $oImapResponse->ResponseList[3][1],
- (int) $oImapResponse->ResponseList[3][2],
- 0,
- 0
- );
-
- if (5 < \count($oImapResponse->ResponseList[3])
- && 'MESSAGE' === \strtoupper($oImapResponse->ResponseList[3][3])
- && \is_numeric($oImapResponse->ResponseList[3][4])
- && \is_numeric($oImapResponse->ResponseList[3][5])
- )
- {
- $aReturn[2] = (int) $oImapResponse->ResponseList[3][4];
- $aReturn[3] = (int) $oImapResponse->ResponseList[3][5];
- }
- }
- }
- }
-
- return $aReturn;
- }
-
- /**
- * @param array $aSortTypes
- * @param string $sSearchCriterias
- * @param bool $bReturnUid
- *
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function MessageSimpleSort($aSortTypes, $sSearchCriterias = 'ALL', $bReturnUid = true)
- {
- $sCommandPrefix = ($bReturnUid) ? 'UID ' : '';
- $sSearchCriterias = !\MailSo\Base\Validator::NotEmptyString($sSearchCriterias, true) || '*' === $sSearchCriterias
- ? 'ALL' : $sSearchCriterias;
-
- if (!\is_array($aSortTypes) || 0 === \count($aSortTypes))
- {
- $this->writeLogException(
- new \MailSo\Base\Exceptions\InvalidArgumentException(),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
- else if (!$this->IsSupported('SORT'))
- {
- $this->writeLogException(
- new \MailSo\Base\Exceptions\InvalidArgumentException(),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- $aRequest = array();
- $aRequest[] = $aSortTypes;
- $aRequest[] = \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? 'US-ASCII' : 'UTF-8';
- $aRequest[] = $sSearchCriterias;
-
- $sCmd = 'SORT';
-
- $this->SendRequest($sCommandPrefix.$sCmd, $aRequest);
- $aResult = $this->parseResponseWithValidation();
-
- $aReturn = array();
- $oImapResponse = null;
- foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
- {
- if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType
- && ($sCmd === $oImapResponse->StatusOrIndex ||
- ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex) && !empty($oImapResponse->ResponseList[2]) &&
- $sCmd === $oImapResponse->ResponseList[2])
- && \is_array($oImapResponse->ResponseList)
- && 2 < \count($oImapResponse->ResponseList))
- {
- $iStart = 2;
- if ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex &&
- !empty($oImapResponse->ResponseList[2]) &&
- $sCmd === $oImapResponse->ResponseList[2])
- {
- $iStart = 3;
- }
-
- for ($iIndex = $iStart, $iLen = \count($oImapResponse->ResponseList); $iIndex < $iLen; $iIndex++)
- {
- $aReturn[] = (int) $oImapResponse->ResponseList[$iIndex];
- }
- }
- }
-
- return $aReturn;
- }
-
- /**
- * @param bool $bSort = false
- * @param string $sSearchCriterias = 'ALL'
- * @param array $aSearchOrSortReturn = null
- * @param bool $bReturnUid = true
- * @param string $sLimit = ''
- * @param string $sCharset = ''
- * @param array $aSortTypes = null
- *
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- private function simpleESearchOrESortHelper($bSort = false, $sSearchCriterias = 'ALL', $aSearchOrSortReturn = null, $bReturnUid = true, $sLimit = '', $sCharset = '', $aSortTypes = null)
- {
- $sCommandPrefix = ($bReturnUid) ? 'UID ' : '';
- $sSearchCriterias = 0 === \strlen($sSearchCriterias) || '*' === $sSearchCriterias
- ? 'ALL' : $sSearchCriterias;
-
- $sCmd = $bSort ? 'SORT': 'SEARCH';
- if ($bSort && (!\is_array($aSortTypes) || 0 === \count($aSortTypes) || !$this->IsSupported('SORT')))
- {
- $this->writeLogException(
- new \MailSo\Base\Exceptions\InvalidArgumentException(),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- if (!$this->IsSupported($bSort ? 'ESORT' : 'ESEARCH'))
- {
- $this->writeLogException(
- new \MailSo\Base\Exceptions\InvalidArgumentException(),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- if (!\is_array($aSearchOrSortReturn) || 0 === \count($aSearchOrSortReturn))
- {
- $aSearchOrSortReturn = array('ALL');
- }
-
- $aRequest = array();
- if ($bSort)
- {
- $aRequest[] = 'RETURN';
- $aRequest[] = $aSearchOrSortReturn;
-
- $aRequest[] = $aSortTypes;
- $aRequest[] = \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? 'US-ASCII' : 'UTF-8';
- }
- else
- {
- if (0 < \strlen($sCharset))
- {
- $aRequest[] = 'CHARSET';
- $aRequest[] = \strtoupper($sCharset);
- }
-
- $aRequest[] = 'RETURN';
- $aRequest[] = $aSearchOrSortReturn;
- }
-
- $aRequest[] = $sSearchCriterias;
-
- if (0 < \strlen($sLimit))
- {
- $aRequest[] = $sLimit;
- }
-
- $this->SendRequest($sCommandPrefix.$sCmd, $aRequest);
- $sRequestTag = $this->getCurrentTag();
-
- $aResult = array();
- $aResponse = $this->parseResponseWithValidation();
-
- if (\is_array($aResponse))
- {
- $oImapResponse = null;
- foreach ($aResponse as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
- {
- if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType
- && ('ESEARCH' === $oImapResponse->StatusOrIndex || 'ESORT' === $oImapResponse->StatusOrIndex)
- && \is_array($oImapResponse->ResponseList)
- && isset($oImapResponse->ResponseList[2], $oImapResponse->ResponseList[2][0], $oImapResponse->ResponseList[2][1])
- && 'TAG' === $oImapResponse->ResponseList[2][0] && $sRequestTag === $oImapResponse->ResponseList[2][1]
- && (!$bReturnUid || ($bReturnUid && !empty($oImapResponse->ResponseList[3]) && 'UID' === $oImapResponse->ResponseList[3]))
- )
- {
- $iStart = 3;
- foreach ($oImapResponse->ResponseList as $iIndex => $mItem)
- {
- if ($iIndex >= $iStart)
- {
- switch ($mItem)
- {
- case 'ALL':
- case 'MAX':
- case 'MIN':
- case 'COUNT':
- if (isset($oImapResponse->ResponseList[$iIndex + 1]))
- {
- $aResult[$mItem] = $oImapResponse->ResponseList[$iIndex + 1];
- }
- break;
- }
- }
- }
- }
- }
- }
-
- return $aResult;
- }
-
- /**
- * @param string $sSearchCriterias = 'ALL'
- * @param array $aSearchReturn = null
- * @param bool $bReturnUid = true
- * @param string $sLimit = ''
- * @param string $sCharset = ''
- *
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function MessageSimpleESearch($sSearchCriterias = 'ALL', $aSearchReturn = null, $bReturnUid = true, $sLimit = '', $sCharset = '')
- {
- return $this->simpleESearchOrESortHelper(false, $sSearchCriterias, $aSearchReturn, $bReturnUid, $sLimit, $sCharset);
- }
-
- /**
- * @param array $aSortTypes
- * @param string $sSearchCriterias = 'ALL'
- * @param array $aSearchReturn = null
- * @param bool $bReturnUid = true
- * @param string $sLimit = ''
- *
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function MessageSimpleESort($aSortTypes, $sSearchCriterias = 'ALL', $aSearchReturn = null, $bReturnUid = true, $sLimit = '')
- {
- return $this->simpleESearchOrESortHelper(true, $sSearchCriterias, $aSearchReturn, $bReturnUid, $sLimit, '', $aSortTypes);
- }
-
- /**
- * @param array $aResult
- * @return \MailSo\Imap\Response
- */
- private function findLastResponse($aResult)
- {
- $oResult = null;
- if (\is_array($aResult) && 0 < \count($aResult))
- {
- $oResult = $aResult[\count($aResult) - 1];
- if (!($oResult instanceof \MailSo\Imap\Response))
- {
- $oResult = null;
- }
- }
-
- return $oResult;
- }
-
- /**
- * @param string $sSearchCriterias
- * @param bool $bReturnUid = true
- * @param string $sCharset = ''
- *
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function MessageSimpleSearch($sSearchCriterias = 'ALL', $bReturnUid = true, $sCharset = '')
- {
- $sCommandPrefix = ($bReturnUid) ? 'UID ' : '';
- $sSearchCriterias = 0 === \strlen($sSearchCriterias) || '*' === $sSearchCriterias
- ? 'ALL' : $sSearchCriterias;
-
- $aRequest = array();
- if (0 < \strlen($sCharset))
- {
- $aRequest[] = 'CHARSET';
- $aRequest[] = \strtoupper($sCharset);
- }
-
- $aRequest[] = $sSearchCriterias;
-
- $sCmd = 'SEARCH';
-
- $sCont = $this->SendRequest($sCommandPrefix.$sCmd, $aRequest, true);
- if ('' !== $sCont)
- {
- $aResult = $this->parseResponseWithValidation();
- $oItem = $this->findLastResponse($aResult);
-
- if ($oItem && \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oItem->ResponseType)
- {
- $aParts = explode("\r\n", $sCont);
- foreach ($aParts as $sLine)
- {
- $this->sendRaw($sLine);
-
- $aResult = $this->parseResponseWithValidation();
- $oItem = $this->findLastResponse($aResult);
- if ($oItem && \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oItem->ResponseType)
- {
- continue;
- }
- }
- }
- }
- else
- {
- $aResult = $this->parseResponseWithValidation();
- }
-
- $aReturn = array();
- $oImapResponse = null;
- foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
- {
- if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType
- && ($sCmd === $oImapResponse->StatusOrIndex ||
- ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex) && !empty($oImapResponse->ResponseList[2]) &&
- $sCmd === $oImapResponse->ResponseList[2])
- && \is_array($oImapResponse->ResponseList)
- && 2 < count($oImapResponse->ResponseList))
- {
- $iStart = 2;
- if ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex &&
- !empty($oImapResponse->ResponseList[2]) &&
- $sCmd === $oImapResponse->ResponseList[2])
- {
- $iStart = 3;
- }
-
- for ($iIndex = $iStart, $iLen = \count($oImapResponse->ResponseList); $iIndex < $iLen; $iIndex++)
- {
- $aReturn[] = (int) $oImapResponse->ResponseList[$iIndex];
- }
- }
- }
-
- $aReturn = \array_reverse($aReturn);
- return $aReturn;
- }
-
- /**
- * @param mixed $aValue
- *
- * @return mixed
- */
- private function validateThreadItem($aValue)
- {
- $mResult = false;
- if (\is_numeric($aValue))
- {
- $mResult = (int) $aValue;
- if (0 >= $mResult)
- {
- $mResult = false;
- }
- }
- else if (\is_array($aValue))
- {
- if (1 === \count($aValue) && \is_numeric($aValue[0]))
- {
- $mResult = (int) $aValue[0];
- if (0 >= $mResult)
- {
- $mResult = false;
- }
- }
- else
- {
- $mResult = array();
- foreach ($aValue as $aValueItem)
- {
- $mTemp = $this->validateThreadItem($aValueItem);
- if (false !== $mTemp)
- {
- $mResult[] = $mTemp;
- }
- }
- }
- }
-
- return $mResult;
- }
-
- /**
- * @param string $sSearchCriterias = 'ALL'
- * @param bool $bReturnUid = true
- * @param string $sCharset = \MailSo\Base\Enumerations\Charset::UTF_8
- *
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function MessageSimpleThread($sSearchCriterias = 'ALL', $bReturnUid = true, $sCharset = \MailSo\Base\Enumerations\Charset::UTF_8)
- {
- $sCommandPrefix = ($bReturnUid) ? 'UID ' : '';
- $sSearchCriterias = !\MailSo\Base\Validator::NotEmptyString($sSearchCriterias, true) || '*' === $sSearchCriterias
- ? 'ALL' : $sSearchCriterias;
-
- $sThreadType = '';
- switch (true)
- {
- case $this->IsSupported('THREAD=REFS'):
- $sThreadType = 'REFS';
- break;
- case $this->IsSupported('THREAD=REFERENCES'):
- $sThreadType = 'REFERENCES';
- break;
- case $this->IsSupported('THREAD=ORDEREDSUBJECT'):
- $sThreadType = 'ORDEREDSUBJECT';
- break;
- default:
- $this->writeLogException(
- new Exceptions\RuntimeException('Thread is not supported'),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- break;
- }
-
- $aRequest = array();
- $aRequest[] = $sThreadType;
- $aRequest[] = \strtoupper($sCharset);
- $aRequest[] = $sSearchCriterias;
-
- $sCmd = 'THREAD';
-
- $this->SendRequest($sCommandPrefix.$sCmd, $aRequest);
- $aResult = $this->parseResponseWithValidation();
-
- $aReturn = array();
- $oImapResponse = null;
-
- foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
- {
- if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType
- && ($sCmd === $oImapResponse->StatusOrIndex ||
- ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex) && !empty($oImapResponse->ResponseList[2]) &&
- $sCmd === $oImapResponse->ResponseList[2])
- && \is_array($oImapResponse->ResponseList)
- && 2 < \count($oImapResponse->ResponseList))
- {
- $iStart = 2;
- if ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex &&
- !empty($oImapResponse->ResponseList[2]) &&
- $sCmd === $oImapResponse->ResponseList[2])
- {
- $iStart = 3;
- }
-
- for ($iIndex = $iStart, $iLen = \count($oImapResponse->ResponseList); $iIndex < $iLen; $iIndex++)
- {
- $aNewValue = $this->validateThreadItem($oImapResponse->ResponseList[$iIndex]);
- if (false !== $aNewValue)
- {
- $aReturn[] = $aNewValue;
- }
- }
- }
- }
-
- return $aReturn;
- }
-
- /**
- * @param string $sToFolder
- * @param string $sIndexRange
- * @param bool $bIndexIsUid
- *
- * @return \MailSo\Imap\ImapClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function MessageCopy($sToFolder, $sIndexRange, $bIndexIsUid)
- {
- if (0 === \strlen($sIndexRange))
- {
- $this->writeLogException(
- new \MailSo\Base\Exceptions\InvalidArgumentException(),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- $sCommandPrefix = ($bIndexIsUid) ? 'UID ' : '';
- return $this->SendRequestWithCheck($sCommandPrefix.'COPY',
- array($sIndexRange, $this->EscapeString($sToFolder)));
- }
-
- /**
- * @param string $sToFolder
- * @param string $sIndexRange
- * @param bool $bIndexIsUid
- *
- * @return \MailSo\Imap\ImapClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function MessageMove($sToFolder, $sIndexRange, $bIndexIsUid)
- {
- if (0 === \strlen($sIndexRange))
- {
- $this->writeLogException(
- new \MailSo\Base\Exceptions\InvalidArgumentException(),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- if (!$this->IsSupported('MOVE'))
- {
- $this->writeLogException(
- new Exceptions\RuntimeException('Move is not supported'),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- $sCommandPrefix = ($bIndexIsUid) ? 'UID ' : '';
- return $this->SendRequestWithCheck($sCommandPrefix.'MOVE',
- array($sIndexRange, $this->EscapeString($sToFolder)));
- }
-
- /**
- * @param string $sUidRangeIfSupported = ''
- * @param bool $bForceUidExpunge = false
- * @param bool $bExpungeAll = false
- *
- * @return \MailSo\Imap\ImapClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function MessageExpunge($sUidRangeIfSupported = '', $bForceUidExpunge = false, $bExpungeAll = false)
- {
- $sUidRangeIfSupported = \trim($sUidRangeIfSupported);
-
- $sCmd = 'EXPUNGE';
- $aArguments = array();
-
- if (!$bExpungeAll && $bForceUidExpunge && 0 < \strlen($sUidRangeIfSupported) && $this->IsSupported('UIDPLUS'))
- {
- $sCmd = 'UID '.$sCmd;
- $aArguments = array($sUidRangeIfSupported);
- }
-
- return $this->SendRequestWithCheck($sCmd, $aArguments);
- }
-
- /**
- * @param string $sIndexRange
- * @param bool $bIndexIsUid
- * @param array $aInputStoreItems
- * @param string $sStoreAction
- *
- * @return \MailSo\Imap\ImapClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function MessageStoreFlag($sIndexRange, $bIndexIsUid, $aInputStoreItems, $sStoreAction)
- {
- if (!\MailSo\Base\Validator::NotEmptyString($sIndexRange, true) ||
- !\MailSo\Base\Validator::NotEmptyString($sStoreAction, true) ||
- 0 === \count($aInputStoreItems))
- {
- return false;
- }
-
- $sCmd = ($bIndexIsUid) ? 'UID STORE' : 'STORE';
- return $this->SendRequestWithCheck($sCmd, array($sIndexRange, $sStoreAction, $aInputStoreItems));
- }
-
- /**
- * @param string $sFolderName
- * @param resource $rMessageAppendStream
- * @param int $iStreamSize
- * @param array $aAppendFlags = null
- * @param int $iUid = null
- * @param int $sDateTime = 0
- *
- * @return \MailSo\Imap\ImapClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function MessageAppendStream($sFolderName, $rMessageAppendStream, $iStreamSize, $aAppendFlags = null, &$iUid = null, $sDateTime = 0)
- {
- $aData = array($this->EscapeString($sFolderName), $aAppendFlags);
- if (0 < $sDateTime)
- {
- $aData[] = $this->EscapeString(\gmdate('d-M-Y H:i:s', $sDateTime).' +0000');
- }
-
- $aData[] = '{'.$iStreamSize.'}';
-
- $this->SendRequest('APPEND', $aData);
- $this->parseResponseWithValidation();
-
- $this->writeLog('Write to connection stream', \MailSo\Log\Enumerations\Type::NOTE);
-
- \MailSo\Base\Utils::MultipleStreamWriter($rMessageAppendStream, array($this->rConnect));
-
- $this->sendRaw('');
- $this->parseResponseWithValidation();
-
- if (null !== $iUid)
- {
- $aLastResponse = $this->GetLastResponse();
- if (\is_array($aLastResponse) && 0 < \count($aLastResponse) && $aLastResponse[\count($aLastResponse) - 1])
- {
- $oLast = $aLastResponse[count($aLastResponse) - 1];
- if ($oLast && \MailSo\Imap\Enumerations\ResponseType::TAGGED === $oLast->ResponseType && \is_array($oLast->OptionalResponse))
- {
- if (0 < \strlen($oLast->OptionalResponse[0]) &&
- 0 < \strlen($oLast->OptionalResponse[2]) &&
- 'APPENDUID' === strtoupper($oLast->OptionalResponse[0]) &&
- \is_numeric($oLast->OptionalResponse[2])
- )
- {
- $iUid = (int) $oLast->OptionalResponse[2];
- }
- }
- }
- }
-
- return $this;
- }
-
- /**
- * @return \MailSo\Imap\FolderInformation
- */
- public function FolderCurrentInformation()
- {
- return $this->oCurrentFolderInfo;
- }
-
- /**
- * @param string $sCommand
- * @param array $aParams = array()
- * @param bool $bBreakOnLiteral = false
- *
- * @return string
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- */
- public function SendRequest($sCommand, $aParams = array(), $bBreakOnLiteral = false)
- {
- if (!\MailSo\Base\Validator::NotEmptyString($sCommand, true) || !\is_array($aParams))
- {
- $this->writeLogException(
- new \MailSo\Base\Exceptions\InvalidArgumentException(),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- $this->IsConnected(true);
-
- $sTag = $this->getNewTag();
-
- $sCommand = \trim($sCommand);
- $sRealCommand = $sTag.' '.$sCommand.$this->prepearParamLine($aParams);
-
- $sFakeCommand = '';
- $aFakeParams = $this->secureRequestParams($sCommand, $aParams);
- if (null !== $aFakeParams)
- {
- $sFakeCommand = $sTag.' '.$sCommand.$this->prepearParamLine($aFakeParams);
- }
-
- $this->aTagTimeouts[$sTag] = \microtime(true);
-
- if ($bBreakOnLiteral && !\preg_match('/\d\+\}\r\n/', $sRealCommand))
- {
- $iPos = \strpos($sRealCommand, "}\r\n");
- if (false !== $iPos)
- {
- $iFakePos = \strpos($sFakeCommand, "}\r\n");
-
- $this->sendRaw(\substr($sRealCommand, 0, $iPos + 1), true,
- false !== $iFakePos ? \substr($sFakeCommand, 0, $iFakePos + 3) : '');
-
- return \substr($sRealCommand, $iPos + 3);
- }
- }
-
- $this->sendRaw($sRealCommand, true, $sFakeCommand);
- return '';
- }
-
- /**
- * @param string $sCommand
- * @param array $aParams
- *
- * @return array|null
- */
- private function secureRequestParams($sCommand, $aParams)
- {
- $aResult = null;
- switch ($sCommand)
- {
- case 'LOGIN':
- $aResult = $aParams;
- if (\is_array($aResult) && 2 === count($aResult))
- {
- $aResult[1] = '"********"';
- }
- break;
- }
-
- return $aResult;
- }
-
- /**
- * @param string $sCommand
- * @param array $aParams = array()
- * @param bool $bFindCapa = false
- *
- * @return \MailSo\Imap\ImapClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function SendRequestWithCheck($sCommand, $aParams = array(), $bFindCapa = false)
- {
- $this->SendRequest($sCommand, $aParams);
- $this->parseResponseWithValidation(null, $bFindCapa);
-
- return $this;
- }
-
- /**
- * @return array
- */
- public function GetLastResponse()
- {
- return $this->aLastResponse;
- }
-
- /**
- * @param mixed $aResult
- *
- * @return array
- *
- * @throws \MailSo\Imap\Exceptions\ResponseNotFoundException
- * @throws \MailSo\Imap\Exceptions\InvalidResponseException
- * @throws \MailSo\Imap\Exceptions\NegativeResponseException
- */
- private function validateResponse($aResult)
- {
- if (!\is_array($aResult) || 0 === $iCnt = \count($aResult))
- {
- $this->writeLogException(
- new Exceptions\ResponseNotFoundException(),
- \MailSo\Log\Enumerations\Type::WARNING, true);
- }
-
- if ($aResult[$iCnt - 1]->ResponseType !== \MailSo\Imap\Enumerations\ResponseType::CONTINUATION)
- {
- if (!$aResult[$iCnt - 1]->IsStatusResponse)
- {
- $this->writeLogException(
- new Exceptions\InvalidResponseException($aResult),
- \MailSo\Log\Enumerations\Type::WARNING, true);
- }
-
- if (\MailSo\Imap\Enumerations\ResponseStatus::OK !== $aResult[$iCnt - 1]->StatusOrIndex)
- {
- $this->writeLogException(
- new Exceptions\NegativeResponseException($aResult),
- \MailSo\Log\Enumerations\Type::WARNING, true);
- }
- }
-
- return $aResult;
- }
-
- /**
- * @param string $sEndTag = null
- * @param bool $bFindCapa = false
- *
- * @return array|bool
- */
- protected function parseResponse($sEndTag = null, $bFindCapa = false)
- {
- if (\is_resource($this->rConnect))
- {
- $oImapResponse = null;
- $sEndTag = (null === $sEndTag) ? $this->getCurrentTag() : $sEndTag;
-
- while (true)
- {
- $oImapResponse = Response::NewInstance();
-
- $this->partialParseResponseBranch($oImapResponse);
-
- if ($oImapResponse)
- {
- if (\MailSo\Imap\Enumerations\ResponseType::UNKNOWN === $oImapResponse->ResponseType)
- {
- return false;
- }
-
- if ($bFindCapa)
- {
- $this->initCapabilityImapResponse($oImapResponse);
- }
-
- $this->aPartialResponses[] = $oImapResponse;
- if ($sEndTag === $oImapResponse->Tag || \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oImapResponse->ResponseType)
- {
- if (isset($this->aTagTimeouts[$sEndTag]))
- {
- $this->writeLog((\microtime(true) - $this->aTagTimeouts[$sEndTag]).' ('.$sEndTag.')',
- \MailSo\Log\Enumerations\Type::TIME);
-
- unset($this->aTagTimeouts[$sEndTag]);
- }
-
- break;
- }
- }
- else
- {
- return false;
- }
-
- unset($oImapResponse);
- }
- }
-
- $this->iResponseBufParsedPos = 0;
- $this->aLastResponse = $this->aPartialResponses;
- $this->aPartialResponses = array();
-
- return $this->aLastResponse;
- }
-
- /**
- * @param string $sEndTag = null
- * @param bool $bFindCapa = false
- *
- * @return array
- */
- private function parseResponseWithValidation($sEndTag = null, $bFindCapa = false)
- {
- return $this->validateResponse($this->parseResponse($sEndTag, $bFindCapa));
- }
-
- /**
- * @param \MailSo\Imap\Response $oImapResponse
- *
- * @return void
- */
- private function initCapabilityImapResponse($oImapResponse)
- {
- if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType
- && \is_array($oImapResponse->ResponseList))
- {
- $aList = null;
- if (isset($oImapResponse->ResponseList[1]) && \is_string($oImapResponse->ResponseList[1]) &&
- 'CAPABILITY' === \strtoupper($oImapResponse->ResponseList[1]))
- {
- $aList = \array_slice($oImapResponse->ResponseList, 2);
- }
- else if ($oImapResponse->OptionalResponse && \is_array($oImapResponse->OptionalResponse) &&
- 1 < \count($oImapResponse->OptionalResponse) && \is_string($oImapResponse->OptionalResponse[0]) &&
- 'CAPABILITY' === \strtoupper($oImapResponse->OptionalResponse[0]))
- {
- $aList = \array_slice($oImapResponse->OptionalResponse, 1);
- }
-
- if (\is_array($aList) && 0 < \count($aList))
- {
- $this->aCapabilityItems = \array_map('strtoupper', $aList);
- }
- }
- }
-
- /**
- * @return array|string
- *
- * @throws \MailSo\Net\Exceptions\Exception
- */
- private function partialParseResponseBranch(&$oImapResponse, $iStackIndex = -1,
- $bTreatAsAtom = false, $sParentToken = '', $sOpenBracket = '')
- {
- $mNull = null;
-
- $iStackIndex++;
- $iPos = $this->iResponseBufParsedPos;
-
- $sPreviousAtomUpperCase = null;
- $bIsEndOfList = false;
- $bIsClosingBracketSquare = false;
- $iLiteralLen = 0;
- $iBufferEndIndex = 0;
- $iDebugCount = 0;
-
- $rImapLiteralStream = null;
-
- $bIsGotoDefault = false;
- $bIsGotoLiteral = false;
- $bIsGotoLiteralEnd = false;
- $bIsGotoAtomBracket = false;
- $bIsGotoNotAtomBracket = false;
-
- $bCountOneInited = false;
- $bCountTwoInited = false;
-
- $sAtomBuilder = $bTreatAsAtom ? '' : null;
- $aList = array();
- if (null !== $oImapResponse)
- {
- $aList =& $oImapResponse->ResponseList;
- }
-
- while (!$bIsEndOfList)
- {
- $iDebugCount++;
- if (100000 === $iDebugCount)
- {
- $this->Logger()->Write('PartialParseOver: '.$iDebugCount, \MailSo\Log\Enumerations\Type::ERROR);
- }
-
- if ($this->bNeedNext)
- {
- $iPos = 0;
- $this->getNextBuffer();
- $this->iResponseBufParsedPos = $iPos;
- $this->bNeedNext = false;
- }
-
- $sChar = null;
- if ($bIsGotoDefault)
- {
- $sChar = 'GOTO_DEFAULT';
- $bIsGotoDefault = false;
- }
- else if ($bIsGotoLiteral)
- {
- $bIsGotoLiteral = false;
- $bIsGotoLiteralEnd = true;
-
- if ($this->partialResponseLiteralCallbackCallable(
- $sParentToken, null === $sPreviousAtomUpperCase ? '' : \strtoupper($sPreviousAtomUpperCase), $this->rConnect, $iLiteralLen))
- {
- if (!$bTreatAsAtom)
- {
- $aList[] = '';
- }
- }
- else
- {
- $sLiteral = '';
- $iRead = $iLiteralLen;
-
- while (0 < $iRead)
- {
- $sAddRead = \fread($this->rConnect, $iRead);
- if (false === $sAddRead)
- {
- $sLiteral = false;
- break;
- }
-
- $sLiteral .= $sAddRead;
- $iRead -= \strlen($sAddRead);
-
- \MailSo\Base\Utils::ResetTimeLimit();
- }
-
- if (false !== $sLiteral)
- {
- $iLiteralSize = \strlen($sLiteral);
- \MailSo\Base\Loader::IncStatistic('NetRead', $iLiteralSize);
- if ($iLiteralLen !== $iLiteralSize)
- {
- $this->writeLog('Literal stream read warning "read '.$iLiteralSize.' of '.
- $iLiteralLen.'" bytes', \MailSo\Log\Enumerations\Type::WARNING);
- }
-
- if (!$bTreatAsAtom)
- {
- $aList[] = $sLiteral;
-
- if (\MailSo\Config::$LogSimpleLiterals)
- {
- $this->writeLog('{'.\strlen($sLiteral).'} '.$sLiteral, \MailSo\Log\Enumerations\Type::INFO);
- }
- }
- }
- else
- {
- $this->writeLog('Can\'t read imap stream', \MailSo\Log\Enumerations\Type::NOTE);
- }
-
- unset($sLiteral);
- }
-
- continue;
- }
- else if ($bIsGotoLiteralEnd)
- {
- $rImapLiteralStream = null;
- $sPreviousAtomUpperCase = null;
- $this->bNeedNext = true;
- $bIsGotoLiteralEnd = false;
-
- continue;
- }
- else if ($bIsGotoAtomBracket)
- {
- if ($bTreatAsAtom)
- {
- $sAtomBlock = $this->partialParseResponseBranch($mNull, $iStackIndex, true,
- null === $sPreviousAtomUpperCase ? '' : \strtoupper($sPreviousAtomUpperCase), $sOpenBracket);
-
- $sAtomBuilder .= $sAtomBlock;
- $iPos = $this->iResponseBufParsedPos;
- $sAtomBuilder .= ($bIsClosingBracketSquare) ? ']' : ')';
- }
-
- $sPreviousAtomUpperCase = null;
- $bIsGotoAtomBracket = false;
-
- continue;
- }
- else if ($bIsGotoNotAtomBracket)
- {
- $aSubItems = $this->partialParseResponseBranch($mNull, $iStackIndex, false,
- null === $sPreviousAtomUpperCase ? '' : \strtoupper($sPreviousAtomUpperCase), $sOpenBracket);
-
- $aList[] = $aSubItems;
- $iPos = $this->iResponseBufParsedPos;
- $sPreviousAtomUpperCase = null;
- if (null !== $oImapResponse && $oImapResponse->IsStatusResponse)
- {
- $oImapResponse->OptionalResponse = $aSubItems;
-
- $bIsGotoDefault = true;
- $bIsGotoNotAtomBracket = false;
- continue;
- }
- $bIsGotoNotAtomBracket = false;
-
- continue;
- }
- else
- {
- $iBufferEndIndex = \strlen($this->sResponseBuffer) - 3;
- $this->bResponseBufferChanged = false;
-
- if ($iPos > $iBufferEndIndex)
- {
- break;
- }
-
- $sChar = $this->sResponseBuffer[$iPos];
- }
-
- switch (true)
- {
- case ']' === $sChar:
- $iPos++;
- $sPreviousAtomUpperCase = null;
- $bIsEndOfList = true;
- break;
- case ')' === $sChar:
- $iPos++;
- $sPreviousAtomUpperCase = null;
- $bIsEndOfList = true;
- break;
- case ' ' === $sChar:
- if ($bTreatAsAtom)
- {
- $sAtomBuilder .= ' ';
- }
- $iPos++;
- break;
- case '[' === $sChar:
- $bIsClosingBracketSquare = true;
- case '(' === $sChar:
- if ('(' === $sChar)
- {
- $bIsClosingBracketSquare = false;
- }
-
- if ($bTreatAsAtom)
- {
- $sAtomBuilder .= $bIsClosingBracketSquare ? '[' : '(';
- }
- $iPos++;
-
- $this->iResponseBufParsedPos = $iPos;
- if ($bTreatAsAtom)
- {
- $bIsGotoAtomBracket = true;
- $sOpenBracket = $bIsClosingBracketSquare ? '[' : '(';
- }
- else
- {
- $bIsGotoNotAtomBracket = true;
- $sOpenBracket = $bIsClosingBracketSquare ? '[' : '(';
- }
- break;
- case '{' === $sChar:
- $bIsLiteralParsed = false;
- $mLiteralEndPos = \strpos($this->sResponseBuffer, '}', $iPos);
- if (false !== $mLiteralEndPos && $mLiteralEndPos > $iPos)
- {
- $sLiteralLenAsString = \substr($this->sResponseBuffer, $iPos + 1, $mLiteralEndPos - $iPos - 1);
- if (\is_numeric($sLiteralLenAsString))
- {
- $iLiteralLen = (int) $sLiteralLenAsString;
- $bIsLiteralParsed = true;
- $iPos = $mLiteralEndPos + 3;
- $bIsGotoLiteral = true;
- break;
- }
- }
- if (!$bIsLiteralParsed)
- {
- $iPos = $iBufferEndIndex;
- }
- $sPreviousAtomUpperCase = null;
- break;
- case '"' === $sChar:
- $bIsQuotedParsed = false;
- while (true)
- {
- $iClosingPos = $iPos + 1;
- if ($iClosingPos > $iBufferEndIndex)
- {
- break;
- }
-
- while (true)
- {
- $iClosingPos = \strpos($this->sResponseBuffer, '"', $iClosingPos);
- if (false === $iClosingPos)
- {
- break;
- }
-
- // TODO
- $iClosingPosNext = $iClosingPos + 1;
- if (
- isset($this->sResponseBuffer[$iClosingPosNext]) &&
- ' ' !== $this->sResponseBuffer[$iClosingPosNext] &&
- "\r" !== $this->sResponseBuffer[$iClosingPosNext] &&
- "\n" !== $this->sResponseBuffer[$iClosingPosNext] &&
- ']' !== $this->sResponseBuffer[$iClosingPosNext] &&
- ')' !== $this->sResponseBuffer[$iClosingPosNext]
- )
- {
- $iClosingPos++;
- continue;
- }
-
- $iSlashCount = 0;
- while ('\\' === $this->sResponseBuffer[$iClosingPos - $iSlashCount - 1])
- {
- $iSlashCount++;
- }
-
- if ($iSlashCount % 2 == 1)
- {
- $iClosingPos++;
- continue;
- }
- else
- {
- break;
- }
- }
-
- if (false === $iClosingPos)
- {
- break;
- }
- else
- {
-// $iSkipClosingPos = 0;
- $bIsQuotedParsed = true;
- if ($bTreatAsAtom)
- {
- $sAtomBuilder .= \strtr(
- \substr($this->sResponseBuffer, $iPos, $iClosingPos - $iPos + 1),
- array('\\\\' => '\\', '\\"' => '"')
- );
- }
- else
- {
- $aList[] = \strtr(
- \substr($this->sResponseBuffer, $iPos + 1, $iClosingPos - $iPos - 1),
- array('\\\\' => '\\', '\\"' => '"')
- );
- }
-
- $iPos = $iClosingPos + 1;
- break;
- }
- }
-
- if (!$bIsQuotedParsed)
- {
- $iPos = $iBufferEndIndex;
- }
-
- $sPreviousAtomUpperCase = null;
- break;
-
- case 'GOTO_DEFAULT' === $sChar:
- default:
- $iCharBlockStartPos = $iPos;
-
- if (null !== $oImapResponse && $oImapResponse->IsStatusResponse)
- {
- $iPos = $iBufferEndIndex;
-
- while ($iPos > $iCharBlockStartPos && $this->sResponseBuffer[$iCharBlockStartPos] === ' ')
- {
- $iCharBlockStartPos++;
- }
- }
-
- $bIsAtomDone = false;
- while (!$bIsAtomDone && ($iPos <= $iBufferEndIndex))
- {
- $sCharDef = $this->sResponseBuffer[$iPos];
- switch (true)
- {
- case '[' === $sCharDef:
- if (null === $sAtomBuilder)
- {
- $sAtomBuilder = '';
- }
-
- $sAtomBuilder .= \substr($this->sResponseBuffer, $iCharBlockStartPos, $iPos - $iCharBlockStartPos + 1);
-
- $iPos++;
- $this->iResponseBufParsedPos = $iPos;
-
- $sListBlock = $this->partialParseResponseBranch($mNull, $iStackIndex, true,
- null === $sPreviousAtomUpperCase ? '' : \strtoupper($sPreviousAtomUpperCase), '[');
-
- if (null !== $sListBlock)
- {
- $sAtomBuilder .= $sListBlock.']';
- }
-
- $iPos = $this->iResponseBufParsedPos;
- $iCharBlockStartPos = $iPos;
- break;
- case ' ' === $sCharDef:
- case ')' === $sCharDef && '(' === $sOpenBracket:
- case ']' === $sCharDef && '[' === $sOpenBracket:
- $bIsAtomDone = true;
- break;
- default:
- $iPos++;
- break;
- }
- }
-
- if ($iPos > $iCharBlockStartPos || null !== $sAtomBuilder)
- {
- $sLastCharBlock = \substr($this->sResponseBuffer, $iCharBlockStartPos, $iPos - $iCharBlockStartPos);
- if (null === $sAtomBuilder)
- {
- $aList[] = $sLastCharBlock;
- $sPreviousAtomUpperCase = $sLastCharBlock;
- }
- else
- {
- $sAtomBuilder .= $sLastCharBlock;
-
- if (!$bTreatAsAtom)
- {
- $aList[] = $sAtomBuilder;
- $sPreviousAtomUpperCase = $sAtomBuilder;
- $sAtomBuilder = null;
- }
- }
-
- if (null !== $oImapResponse)
- {
-// if (1 === \count($aList))
- if (!$bCountOneInited && 1 === \count($aList))
-// if (isset($aList[0]) && !isset($aList[1])) // fast 1 === \count($aList)
- {
- $bCountOneInited = true;
-
- $oImapResponse->Tag = $aList[0];
- if ('+' === $oImapResponse->Tag)
- {
- $oImapResponse->ResponseType = \MailSo\Imap\Enumerations\ResponseType::CONTINUATION;
- }
- else if ('*' === $oImapResponse->Tag)
- {
- $oImapResponse->ResponseType = \MailSo\Imap\Enumerations\ResponseType::UNTAGGED;
- }
- else if ($this->getCurrentTag() === $oImapResponse->Tag)
- {
- $oImapResponse->ResponseType = \MailSo\Imap\Enumerations\ResponseType::TAGGED;
- }
- else
- {
- $oImapResponse->ResponseType = \MailSo\Imap\Enumerations\ResponseType::UNKNOWN;
- }
- }
-// else if (2 === \count($aList))
- else if (!$bCountTwoInited && 2 === \count($aList))
-// else if (isset($aList[1]) && !isset($aList[2])) // fast 2 === \count($aList)
- {
- $bCountTwoInited = true;
-
- $oImapResponse->StatusOrIndex = strtoupper($aList[1]);
-
- if ($oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::OK ||
- $oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::NO ||
- $oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::BAD ||
- $oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::BYE ||
- $oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::PREAUTH)
- {
- $oImapResponse->IsStatusResponse = true;
- }
- }
- else if (\MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oImapResponse->ResponseType)
- {
- $oImapResponse->HumanReadable = $sLastCharBlock;
- }
- else if ($oImapResponse->IsStatusResponse)
- {
- $oImapResponse->HumanReadable = $sLastCharBlock;
- }
- }
- }
- }
- }
-
- $this->iResponseBufParsedPos = $iPos;
- if (null !== $oImapResponse)
- {
- $this->bNeedNext = true;
- $this->iResponseBufParsedPos = 0;
- }
-
- if (100000 < $iDebugCount)
- {
- $this->Logger()->Write('PartialParseOverResult: '.$iDebugCount, \MailSo\Log\Enumerations\Type::ERROR);
- }
-
- return $bTreatAsAtom ? $sAtomBuilder : $aList;
- }
-
- /**
- * @param string $sParent
- * @param string $sLiteralAtomUpperCase
- * @param resource $rImapStream
- * @param int $iLiteralLen
- *
- * @return bool
- */
- private function partialResponseLiteralCallbackCallable($sParent, $sLiteralAtomUpperCase, $rImapStream, $iLiteralLen)
- {
- $sLiteralAtomUpperCasePeek = '';
- if (0 === \strpos($sLiteralAtomUpperCase, 'BODY'))
- {
- $sLiteralAtomUpperCasePeek = \str_replace('BODY', 'BODY.PEEK', $sLiteralAtomUpperCase);
- }
-
- $sFetchKey = '';
- if (\is_array($this->aFetchCallbacks))
- {
- if (0 < \strlen($sLiteralAtomUpperCasePeek) && isset($this->aFetchCallbacks[$sLiteralAtomUpperCasePeek]))
- {
- $sFetchKey = $sLiteralAtomUpperCasePeek;
- }
- else if (0 < \strlen($sLiteralAtomUpperCase) && isset($this->aFetchCallbacks[$sLiteralAtomUpperCase]))
- {
- $sFetchKey = $sLiteralAtomUpperCase;
- }
- }
-
- $bResult = false;
- if (0 < \strlen($sFetchKey) && '' !== $this->aFetchCallbacks[$sFetchKey] &&
- \is_callable($this->aFetchCallbacks[$sFetchKey]))
- {
- $rImapLiteralStream =
- \MailSo\Base\StreamWrappers\Literal::CreateStream($rImapStream, $iLiteralLen);
-
- $bResult = true;
- $this->writeLog('Start Callback for '.$sParent.' / '.$sLiteralAtomUpperCase.
- ' - try to read '.$iLiteralLen.' bytes.', \MailSo\Log\Enumerations\Type::NOTE);
-
- $this->bRunningCallback = true;
-
- try
- {
- \call_user_func($this->aFetchCallbacks[$sFetchKey],
- $sParent, $sLiteralAtomUpperCase, $rImapLiteralStream);
- }
- catch (\Exception $oException)
- {
- $this->writeLog('Callback Exception', \MailSo\Log\Enumerations\Type::NOTICE);
- $this->writeLogException($oException);
- }
-
- if (\is_resource($rImapLiteralStream))
- {
- $iNotReadLiteralLen = 0;
-
- $bFeof = \feof($rImapLiteralStream);
- $this->writeLog('End Callback for '.$sParent.' / '.$sLiteralAtomUpperCase.
- ' - feof = '.($bFeof ? 'good' : 'BAD'), $bFeof ?
- \MailSo\Log\Enumerations\Type::NOTE : \MailSo\Log\Enumerations\Type::WARNING);
-
- if (!$bFeof)
- {
- while (!@\feof($rImapLiteralStream))
- {
- $sBuf = @\fread($rImapLiteralStream, 1024 * 1024);
- if (false === $sBuf || 0 === \strlen($sBuf) || null === $sBuf)
- {
- break;
- }
-
- \MailSo\Base\Utils::ResetTimeLimit();
- $iNotReadLiteralLen += \strlen($sBuf);
- }
-
- if (\is_resource($rImapLiteralStream) && !@\feof($rImapLiteralStream))
- {
- @\stream_get_contents($rImapLiteralStream);
- }
- }
-
- if (\is_resource($rImapLiteralStream))
- {
- @\fclose($rImapLiteralStream);
- }
-
- if ($iNotReadLiteralLen > 0)
- {
- $this->writeLog('Not read literal size is '.$iNotReadLiteralLen.' bytes.',
- \MailSo\Log\Enumerations\Type::WARNING);
- }
- }
- else
- {
- $this->writeLog('Literal stream is not resource after callback.',
- \MailSo\Log\Enumerations\Type::WARNING);
- }
-
- \MailSo\Base\Loader::IncStatistic('NetRead', $iLiteralLen);
-
- $this->bRunningCallback = false;
- }
-
- return $bResult;
- }
-
- /**
- * @param array $aParams = null
- *
- * @return string
- */
- private function prepearParamLine($aParams = array())
- {
- $sReturn = '';
- if (\is_array($aParams) && 0 < \count($aParams))
- {
- foreach ($aParams as $mParamItem)
- {
- if (\is_array($mParamItem) && 0 < \count($mParamItem))
- {
- $sReturn .= ' ('.\trim($this->prepearParamLine($mParamItem)).')';
- }
- else if (\is_string($mParamItem))
- {
- $sReturn .= ' '.$mParamItem;
- }
- }
- }
- return $sReturn;
- }
-
- /**
- * @return string
- */
- private function getNewTag()
- {
- $this->iTagCount++;
- return $this->getCurrentTag();
- }
-
- /**
- * @return string
- */
- private function getCurrentTag()
- {
- return self::TAG_PREFIX.$this->iTagCount;
- }
-
- /**
- * @param string $sStringForEscape
- *
- * @return string
- */
- public function EscapeString($sStringForEscape)
- {
- return '"'.\str_replace(array('\\', '"'), array('\\\\', '\\"'), $sStringForEscape).'"';
- }
-
- /**
- * @return string
- */
- protected function getLogName()
- {
- return 'IMAP';
- }
-
- /**
- * @param \MailSo\Log\Logger $oLogger
- *
- * @return \MailSo\Imap\ImapClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- */
- public function SetLogger($oLogger)
- {
- parent::SetLogger($oLogger);
-
- return $this;
- }
-
- /**
- * @param resource $rConnect
- * @param array $aCapabilityItems = array()
- *
- * @return \MailSo\Imap\ImapClient
- */
- public function TestSetValues($rConnect, $aCapabilityItems = array())
- {
- $this->rConnect = $rConnect;
- $this->aCapabilityItems = $aCapabilityItems;
-
- return $this;
- }
-
- /**
- * @param string $sEndTag = null
- * @param string $bFindCapa = false
- *
- * @return array
- */
- public function TestParseResponseWithValidationProxy($sEndTag = null, $bFindCapa = false)
- {
- return $this->parseResponseWithValidation($sEndTag, $bFindCapa);
- }
-}
+iTagCount = 0;
+ $this->aCapabilityItems = null;
+ $this->oCurrentFolderInfo = null;
+ $this->aFetchCallbacks = null;
+ $this->iResponseBufParsedPos = 0;
+
+ $this->aLastResponse = array();
+ $this->bNeedNext = true;
+ $this->aPartialResponses = array();
+
+ $this->aTagTimeouts = array();
+
+ $this->bIsLoggined = false;
+ $this->bIsSelected = false;
+ $this->sLogginedUser = '';
+
+ $this->__FORCE_SELECT_ON_EXAMINE__ = false;
+
+ @\ini_set('xdebug.max_nesting_level', 500);
+ }
+
+ /**
+ * @return \MailSo\Imap\ImapClient
+ */
+ public static function NewInstance()
+ {
+ return new self();
+ }
+
+ /**
+ * @return string
+ */
+ public function GetLogginedUser()
+ {
+ return $this->sLogginedUser;
+ }
+
+ /**
+ * @param string $sServerName
+ * @param int $iPort = 143
+ * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT
+ * @param bool $bVerifySsl = false
+ * @param bool $bAllowSelfSigned = true
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function Connect($sServerName, $iPort = 143,
+ $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT,
+ $bVerifySsl = false, $bAllowSelfSigned = true)
+ {
+ $this->aTagTimeouts['*'] = \microtime(true);
+
+ parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned);
+
+ $this->parseResponseWithValidation('*', true);
+
+ if (\MailSo\Net\Enumerations\ConnectionSecurityType::UseStartTLS(
+ $this->IsSupported('STARTTLS'), $this->iSecurityType))
+ {
+ $this->SendRequestWithCheck('STARTTLS');
+ $this->EnableCrypto();
+
+ $this->aCapabilityItems = null;
+ }
+ else if (\MailSo\Net\Enumerations\ConnectionSecurityType::STARTTLS === $this->iSecurityType)
+ {
+ $this->writeLogException(
+ new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('STARTTLS is not supported'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ return $this;
+ }
+
+ protected function _xor($string, $string2)
+ {
+ $result = '';
+ $size = strlen($string);
+ for ($i=0; $i<$size; $i++) {
+ $result .= chr(ord($string[$i]) ^ ord($string2[$i]));
+ }
+ return $result;
+ }
+
+ /**
+ * @param string $sLogin
+ * @param string $sPassword
+ * @param string $sProxyAuthUser = ''
+ * @param bool $bUseAuthPlainIfSupported = true
+ * @param bool $bUseAuthCramMd5IfSupported = true
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function Login($sLogin, $sPassword, $sProxyAuthUser = '',
+ $bUseAuthPlainIfSupported = true, $bUseAuthCramMd5IfSupported = true)
+ {
+ if (!\MailSo\Base\Validator::NotEmptyString($sLogin, true) ||
+ !\MailSo\Base\Validator::NotEmptyString($sPassword, true))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $sLogin = \MailSo\Base\Utils::IdnToAscii(\MailSo\Base\Utils::Trim($sLogin));
+
+ $sPassword = $sPassword;
+
+ $this->sLogginedUser = $sLogin;
+
+ try
+ {
+ if ($bUseAuthCramMd5IfSupported && $this->IsSupported('AUTH=CRAM-MD5'))
+ {
+ $this->SendRequest('AUTHENTICATE', array('CRAM-MD5'));
+
+ $aResponse = $this->parseResponseWithValidation();
+ if ($aResponse && \is_array($aResponse) && 0 < \count($aResponse) &&
+ \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $aResponse[\count($aResponse) - 1]->ResponseType)
+ {
+ $oContinuationResponse = null;
+ foreach ($aResponse as $oResponse)
+ {
+ if ($oResponse && \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oResponse->ResponseType)
+ {
+ $oContinuationResponse = $oResponse;
+ }
+ }
+
+ if ($oContinuationResponse && !empty($oContinuationResponse->ResponseList[1]))
+ {
+ $sTicket = @\base64_decode($oContinuationResponse->ResponseList[1]);
+ $this->oLogger->Write('ticket: '.$sTicket);
+
+ $sToken = \base64_encode($sLogin.' '.\MailSo\Base\Utils::Hmac($sTicket, $sPassword));
+
+ if ($this->oLogger)
+ {
+ $this->oLogger->AddSecret($sToken);
+ }
+
+ $this->sendRaw($sToken, true, '*******');
+ $this->parseResponseWithValidation();
+ }
+ else
+ {
+ $this->writeLogException(
+ new \MailSo\Imap\Exceptions\LoginException(),
+ \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+ }
+ else
+ {
+ $this->writeLogException(
+ new \MailSo\Imap\Exceptions\LoginException(),
+ \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+ }
+ else if ($bUseAuthPlainIfSupported && $this->IsSupported('AUTH=PLAIN'))
+ {
+ $sToken = \base64_encode("\0".$sLogin."\0".$sPassword);
+ if ($this->oLogger)
+ {
+ $this->oLogger->AddSecret($sToken);
+ }
+
+ if ($this->IsSupported('AUTH=SASL-IR') && false)
+ {
+ $this->SendRequestWithCheck('AUTHENTICATE', array('PLAIN', $sToken));
+ }
+ else
+ {
+ $this->SendRequest('AUTHENTICATE', array('PLAIN'));
+ $this->parseResponseWithValidation();
+
+ $this->sendRaw($sToken, true, '*******');
+ $this->parseResponseWithValidation();
+ }
+ }
+ else
+ {
+ if ($this->oLogger)
+ {
+ $this->oLogger->AddSecret($this->EscapeString($sPassword));
+ }
+
+ $this->SendRequestWithCheck('LOGIN',
+ array(
+ $this->EscapeString($sLogin),
+ $this->EscapeString($sPassword)
+ ));
+ }
+// else
+// {
+// $this->writeLogException(
+// new \MailSo\Imap\Exceptions\LoginBadMethodException(),
+// \MailSo\Log\Enumerations\Type::NOTICE, true);
+// }
+
+ if (0 < \strlen($sProxyAuthUser))
+ {
+ $this->SendRequestWithCheck('PROXYAUTH', array($this->EscapeString($sProxyAuthUser)));
+ }
+ }
+ catch (\MailSo\Imap\Exceptions\NegativeResponseException $oException)
+ {
+ $this->writeLogException(
+ new \MailSo\Imap\Exceptions\LoginBadCredentialsException(
+ $oException->GetResponses(), '', 0, $oException),
+ \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+
+ $this->bIsLoggined = true;
+ $this->aCapabilityItems = null;
+
+ return $this;
+ }
+
+ /**
+ * @param string $sXOAuth2Token
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function LoginWithXOauth2($sXOAuth2Token)
+ {
+ if (!\MailSo\Base\Validator::NotEmptyString($sXOAuth2Token, true))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ if (!$this->IsSupported('AUTH=XOAUTH2'))
+ {
+ $this->writeLogException(
+ new \MailSo\Imap\Exceptions\LoginBadMethodException(),
+ \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+
+ try
+ {
+ $this->SendRequest('AUTHENTICATE', array('XOAUTH2', \trim($sXOAuth2Token)));
+ $aR = $this->parseResponseWithValidation();
+
+ if (\is_array($aR) && 0 < \count($aR) && isset($aR[\count($aR) - 1]))
+ {
+ $oR = $aR[\count($aR) - 1];
+ if (\MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oR->ResponseType)
+ {
+ if (!empty($oR->ResponseList[1]) && preg_match('/^[a-zA-Z0-9=+\/]+$/', $oR->ResponseList[1]))
+ {
+ $this->Logger()->Write(\base64_decode($oR->ResponseList[1]),
+ \MailSo\Log\Enumerations\Type::WARNING);
+ }
+
+ $this->sendRaw('');
+ $this->parseResponseWithValidation();
+ }
+ }
+ }
+ catch (\MailSo\Imap\Exceptions\NegativeResponseException $oException)
+ {
+ $this->writeLogException(
+ new \MailSo\Imap\Exceptions\LoginBadCredentialsException(
+ $oException->GetResponses(), '', 0, $oException),
+ \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+
+ $this->bIsLoggined = true;
+ $this->aCapabilityItems = null;
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ public function Logout()
+ {
+ if ($this->bIsLoggined)
+ {
+ $this->bIsLoggined = false;
+ $this->SendRequestWithCheck('LOGOUT', array());
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Imap\ImapClient
+ */
+ public function ForceCloseConnection()
+ {
+ $this->Disconnect();
+
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsLoggined()
+ {
+ return $this->IsConnected() && $this->bIsLoggined;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsSelected()
+ {
+ return $this->IsLoggined() && $this->bIsSelected;
+ }
+
+ /**
+ * @return array|null
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function Capability()
+ {
+ $this->SendRequestWithCheck('CAPABILITY', array(), true);
+ return $this->aCapabilityItems;
+ }
+
+ /**
+ * @param string $sExtentionName
+ * @return bool
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function IsSupported($sExtentionName)
+ {
+ $bResult = \MailSo\Base\Validator::NotEmptyString($sExtentionName, true);
+ if ($bResult && null === $this->aCapabilityItems)
+ {
+ $this->aCapabilityItems = $this->Capability();
+ }
+
+ return $bResult && \is_array($this->aCapabilityItems) &&
+ \in_array(\strtoupper($sExtentionName), $this->aCapabilityItems);
+ }
+
+ /**
+ * @return \MailSo\Imap\NamespaceResult|null
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function GetNamespace()
+ {
+ if (!$this->IsSupported('NAMESPACE'))
+ {
+ return null;
+ }
+
+ $oReturn = false;
+
+ $this->SendRequest('NAMESPACE');
+ $aResult = $this->parseResponseWithValidation();
+
+ $oImapResponse = null;
+ foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType &&
+ 'NAMESPACE' === $oImapResponse->StatusOrIndex)
+ {
+ $oReturn = NamespaceResult::NewInstance();
+ $oReturn->InitByImapResponse($oImapResponse);
+ break;
+ }
+ }
+
+ if (false === $oReturn)
+ {
+ $this->writeLogException(
+ new \MailSo\Imap\Exceptions\ResponseException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ return $oReturn;
+ }
+
+ /**
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function Noop()
+ {
+ return $this->SendRequestWithCheck('NOOP');
+ }
+
+ /**
+ * @param string $sFolderName
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderCreate($sFolderName)
+ {
+ return $this->SendRequestWithCheck('CREATE',
+ array($this->EscapeString($sFolderName)));
+ }
+
+ /**
+ * @param string $sFolderName
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderDelete($sFolderName)
+ {
+ return $this->SendRequestWithCheck('DELETE',
+ array($this->EscapeString($sFolderName)));
+ }
+
+ /**
+ * @param string $sFolderName
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderSubscribe($sFolderName)
+ {
+ return $this->SendRequestWithCheck('SUBSCRIBE',
+ array($this->EscapeString($sFolderName)));
+ }
+
+ /**
+ * @param string $sFolderName
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderUnSubscribe($sFolderName)
+ {
+ return $this->SendRequestWithCheck('UNSUBSCRIBE',
+ array($this->EscapeString($sFolderName)));
+ }
+
+ /**
+ * @param string $sOldFolderName
+ * @param string $sNewFolderName
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderRename($sOldFolderName, $sNewFolderName)
+ {
+ return $this->SendRequestWithCheck('RENAME', array(
+ $this->EscapeString($sOldFolderName),
+ $this->EscapeString($sNewFolderName)));
+ }
+
+ /**
+ * @param array $aResult
+ *
+ * @return array
+ */
+ protected function getStatusFolderInformation($aResult)
+ {
+ $aReturn = array();
+
+ if (\is_array($aResult))
+ {
+ $oImapResponse = null;
+ foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType &&
+ 'STATUS' === $oImapResponse->StatusOrIndex && isset($oImapResponse->ResponseList[3]) &&
+ \is_array($oImapResponse->ResponseList[3]))
+ {
+ $sName = null;
+ foreach ($oImapResponse->ResponseList[3] as $sArrayItem)
+ {
+ if (null === $sName)
+ {
+ $sName = $sArrayItem;
+ }
+ else
+ {
+ $aReturn[$sName] = $sArrayItem;
+ $sName = null;
+ }
+ }
+ }
+ }
+ }
+
+ return $aReturn;
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param array $aStatusItems
+ *
+ * @return array|bool
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderStatus($sFolderName, array $aStatusItems)
+ {
+ $aResult = false;
+ if (\count($aStatusItems) > 0)
+ {
+ $this->SendRequest('STATUS',
+ array($this->EscapeString($sFolderName), $aStatusItems));
+
+ $aResult = $this->getStatusFolderInformation(
+ $this->parseResponseWithValidation());
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @param array $aResult
+ * @param string $sStatus
+ * @param bool $bUseListStatus = false
+ *
+ * @return array
+ */
+ private function getFoldersFromResult(array $aResult, $sStatus, $bUseListStatus = false)
+ {
+ $aReturn = array();
+
+ $sDelimiter = '';
+ $bInbox = false;
+
+ $oImapResponse = null;
+ foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType &&
+ $sStatus === $oImapResponse->StatusOrIndex && 5 === count($oImapResponse->ResponseList))
+ {
+ try
+ {
+ $oFolder = Folder::NewInstance($oImapResponse->ResponseList[4],
+ $oImapResponse->ResponseList[3], $oImapResponse->ResponseList[2]);
+
+ if ($oFolder->IsInbox())
+ {
+ $bInbox = true;
+ }
+
+ if (empty($sDelimiter))
+ {
+ $sDelimiter = $oFolder->Delimiter();
+ }
+
+ $aReturn[] = $oFolder;
+ }
+ catch (\MailSo\Base\Exceptions\InvalidArgumentException $oException)
+ {
+ $this->writeLogException($oException, \MailSo\Log\Enumerations\Type::WARNING, false);
+ }
+ }
+ }
+
+ if (!$bInbox && !empty($sDelimiter))
+ {
+ $aReturn[] = Folder::NewInstance('INBOX', $sDelimiter);
+ }
+
+ if ($bUseListStatus)
+ {
+ foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType &&
+ 'STATUS' === $oImapResponse->StatusOrIndex &&
+ isset($oImapResponse->ResponseList[2]) &&
+ isset($oImapResponse->ResponseList[3]) &&
+ \is_array($oImapResponse->ResponseList[3]))
+ {
+ $sFolderNameRaw = $oImapResponse->ResponseList[2];
+
+ $oCurrentFolder = null;
+ foreach ($aReturn as &$oFolder)
+ {
+ if ($oFolder && $sFolderNameRaw === $oFolder->FullNameRaw())
+ {
+ $oCurrentFolder =& $oFolder;
+ break;
+ }
+ }
+
+ if (null !== $oCurrentFolder)
+ {
+ $sName = null;
+ $aStatus = array();
+
+ foreach ($oImapResponse->ResponseList[3] as $sArrayItem)
+ {
+ if (null === $sName)
+ {
+ $sName = $sArrayItem;
+ }
+ else
+ {
+ $aStatus[$sName] = $sArrayItem;
+ $sName = null;
+ }
+ }
+
+ if (0 < count($aStatus))
+ {
+ $oCurrentFolder->SetExtended('STATUS', $aStatus);
+ }
+ }
+
+ unset($oCurrentFolder);
+ }
+ }
+ }
+
+ return $aReturn;
+ }
+
+ /**
+ * @param bool $bIsSubscribeList
+ * @param string $sParentFolderName = ''
+ * @param string $sListPattern = '*'
+ * @param bool $bUseListStatus = false
+ *
+ * @return array
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ private function specificFolderList($bIsSubscribeList, $sParentFolderName = '', $sListPattern = '*', $bUseListStatus = false)
+ {
+ $sCmd = 'LSUB';
+ if (!$bIsSubscribeList)
+ {
+ $sCmd = 'LIST';
+ }
+
+ $sListPattern = 0 === strlen(trim($sListPattern)) ? '*' : $sListPattern;
+
+ $aParameters = array(
+ $this->EscapeString($sParentFolderName),
+ $this->EscapeString($sListPattern)
+ );
+
+ if ($bUseListStatus && !$bIsSubscribeList && $this->IsSupported('LIST-STATUS'))
+ {
+ $aL = array(
+ \MailSo\Imap\Enumerations\FolderStatus::MESSAGES,
+ \MailSo\Imap\Enumerations\FolderStatus::UNSEEN,
+ \MailSo\Imap\Enumerations\FolderStatus::UIDNEXT
+ );
+
+// if ($this->IsSupported('CONDSTORE'))
+// {
+// $aL[] = \MailSo\Imap\Enumerations\FolderStatus::HIGHESTMODSEQ;
+// }
+
+ $aParameters[] = 'RETURN';
+ $aParameters[] = array('STATUS', $aL);
+ }
+ else
+ {
+ $bUseListStatus = false;
+ }
+
+ $this->SendRequest($sCmd, $aParameters);
+
+ return $this->getFoldersFromResult(
+ $this->parseResponseWithValidation(), $sCmd, $bUseListStatus);
+ }
+
+ /**
+ * @param string $sParentFolderName = ''
+ * @param string $sListPattern = '*'
+ *
+ * @return array
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderList($sParentFolderName = '', $sListPattern = '*')
+ {
+ return $this->specificFolderList(false, $sParentFolderName, $sListPattern);
+ }
+
+ /**
+ * @param string $sParentFolderName = ''
+ * @param string $sListPattern = '*'
+ *
+ * @return array
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderSubscribeList($sParentFolderName = '', $sListPattern = '*')
+ {
+ return $this->specificFolderList(true, $sParentFolderName, $sListPattern);
+ }
+
+ /**
+ * @param string $sParentFolderName = ''
+ * @param string $sListPattern = '*'
+ *
+ * @return array
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderStatusList($sParentFolderName = '', $sListPattern = '*')
+ {
+ return $this->specificFolderList(false, $sParentFolderName, $sListPattern, true);
+ }
+
+ /**
+ * @param array $aResult
+ * @param string $sFolderName
+ * @param bool $bIsWritable
+ *
+ * @return void
+ */
+ protected function initCurrentFolderInformation($aResult, $sFolderName, $bIsWritable)
+ {
+ if (\is_array($aResult))
+ {
+ $oImapResponse = null;
+ $oResult = FolderInformation::NewInstance($sFolderName, $bIsWritable);
+
+ foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType)
+ {
+ if (\count($oImapResponse->ResponseList) > 2 &&
+ 'FLAGS' === $oImapResponse->ResponseList[1] && \is_array($oImapResponse->ResponseList[2]))
+ {
+ $oResult->Flags = $oImapResponse->ResponseList[2];
+ }
+
+ if (is_array($oImapResponse->OptionalResponse) && \count($oImapResponse->OptionalResponse) > 1)
+ {
+ if ('PERMANENTFLAGS' === $oImapResponse->OptionalResponse[0] &&
+ is_array($oImapResponse->OptionalResponse[1]))
+ {
+ $oResult->PermanentFlags = $oImapResponse->OptionalResponse[1];
+ }
+ else if ('UIDVALIDITY' === $oImapResponse->OptionalResponse[0] &&
+ isset($oImapResponse->OptionalResponse[1]))
+ {
+ $oResult->Uidvalidity = $oImapResponse->OptionalResponse[1];
+ }
+ else if ('UNSEEN' === $oImapResponse->OptionalResponse[0] &&
+ isset($oImapResponse->OptionalResponse[1]) &&
+ is_numeric($oImapResponse->OptionalResponse[1]))
+ {
+ $oResult->Unread = (int) $oImapResponse->OptionalResponse[1];
+ }
+ else if ('UIDNEXT' === $oImapResponse->OptionalResponse[0] &&
+ isset($oImapResponse->OptionalResponse[1]))
+ {
+ $oResult->Uidnext = $oImapResponse->OptionalResponse[1];
+ }
+ else if ('HIGHESTMODSEQ' === $oImapResponse->OptionalResponse[0] &&
+ isset($oImapResponse->OptionalResponse[1]) &&
+ \is_numeric($oImapResponse->OptionalResponse[1]))
+ {
+ $oResult->HighestModSeq = \trim($oImapResponse->OptionalResponse[1]);
+ }
+ }
+
+ if (\count($oImapResponse->ResponseList) > 2 &&
+ \is_string($oImapResponse->ResponseList[2]) &&
+ \is_numeric($oImapResponse->ResponseList[1]))
+ {
+ switch($oImapResponse->ResponseList[2])
+ {
+ case 'EXISTS':
+ $oResult->Exists = (int) $oImapResponse->ResponseList[1];
+ break;
+ case 'RECENT':
+ $oResult->Recent = (int) $oImapResponse->ResponseList[1];
+ break;
+ }
+ }
+ }
+ }
+
+ $this->oCurrentFolderInfo = $oResult;
+ }
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param bool $bIsWritable
+ * @param bool $bReSelectSameFolders
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ protected function selectOrExamineFolder($sFolderName, $bIsWritable, $bReSelectSameFolders)
+ {
+ if (!$bReSelectSameFolders)
+ {
+ if ($this->oCurrentFolderInfo &&
+ $sFolderName === $this->oCurrentFolderInfo->FolderName &&
+ $bIsWritable === $this->oCurrentFolderInfo->IsWritable)
+ {
+ return $this;
+ }
+ }
+
+ if (!\MailSo\Base\Validator::NotEmptyString($sFolderName, true))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->SendRequest(($bIsWritable) ? 'SELECT' : 'EXAMINE',
+ array($this->EscapeString($sFolderName)));
+
+ $this->initCurrentFolderInformation(
+ $this->parseResponseWithValidation(), $sFolderName, $bIsWritable);
+
+ $this->bIsSelected = true;
+
+ return $this;
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param bool $bReSelectSameFolders = false
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderSelect($sFolderName, $bReSelectSameFolders = false)
+ {
+ return $this->selectOrExamineFolder($sFolderName, true, $bReSelectSameFolders);
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param bool $bReSelectSameFolders = false
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderExamine($sFolderName, $bReSelectSameFolders = false)
+ {
+ return $this->selectOrExamineFolder($sFolderName, $this->__FORCE_SELECT_ON_EXAMINE__, $bReSelectSameFolders);
+ }
+
+ /**
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderUnSelect()
+ {
+ if ($this->IsSelected() && $this->IsSupported('UNSELECT'))
+ {
+ $this->SendRequestWithCheck('UNSELECT');
+ $this->bIsSelected = false;
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param array $aInputFetchItems
+ * @param string $sIndexRange
+ * @param bool $bIndexIsUid
+ *
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function Fetch(array $aInputFetchItems, $sIndexRange, $bIndexIsUid)
+ {
+ $sIndexRange = (string) $sIndexRange;
+ if (!\MailSo\Base\Validator::NotEmptyString($sIndexRange, true))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $aFetchItems = \MailSo\Imap\Enumerations\FetchType::ChangeFetchItemsBefourRequest($aInputFetchItems);
+ foreach ($aFetchItems as $sName => $mItem)
+ {
+ if (0 < \strlen($sName) && '' !== $mItem)
+ {
+ if (null === $this->aFetchCallbacks)
+ {
+ $this->aFetchCallbacks = array();
+ }
+
+ $this->aFetchCallbacks[$sName] = $mItem;
+ }
+ }
+
+ $this->SendRequest((($bIndexIsUid) ? 'UID ' : '').'FETCH', array($sIndexRange, \array_keys($aFetchItems)));
+ $aResult = $this->validateResponse($this->parseResponse());
+ $this->aFetchCallbacks = null;
+
+ $aReturn = array();
+ $oImapResponse = null;
+ foreach ($aResult as $oImapResponse)
+ {
+ if (FetchResponse::IsValidFetchImapResponse($oImapResponse))
+ {
+ if (FetchResponse::IsNotEmptyFetchImapResponse($oImapResponse))
+ {
+ $aReturn[] = FetchResponse::NewInstance($oImapResponse);
+ }
+ else
+ {
+ if ($this->oLogger)
+ {
+ $this->oLogger->Write('Skipped Imap Response! ['.$oImapResponse->ToLine().']', \MailSo\Log\Enumerations\Type::NOTICE);
+ }
+ }
+ }
+ }
+
+ return $aReturn;
+ }
+
+
+ /**
+ * @return array|false
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function Quota()
+ {
+ $aReturn = false;
+ if ($this->IsSupported('QUOTA'))
+ {
+ $this->SendRequest('GETQUOTAROOT "INBOX"');
+ $aResult = $this->parseResponseWithValidation();
+
+ $aReturn = array(0, 0);
+ $oImapResponse = null;
+ foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType
+ && 'QUOTA' === $oImapResponse->StatusOrIndex
+ && \is_array($oImapResponse->ResponseList)
+ && isset($oImapResponse->ResponseList[3])
+ && \is_array($oImapResponse->ResponseList[3])
+ && 2 < \count($oImapResponse->ResponseList[3])
+ && 'STORAGE' === \strtoupper($oImapResponse->ResponseList[3][0])
+ && \is_numeric($oImapResponse->ResponseList[3][1])
+ && \is_numeric($oImapResponse->ResponseList[3][2])
+ )
+ {
+ $aReturn = array(
+ (int) $oImapResponse->ResponseList[3][1],
+ (int) $oImapResponse->ResponseList[3][2],
+ 0,
+ 0
+ );
+
+ if (5 < \count($oImapResponse->ResponseList[3])
+ && 'MESSAGE' === \strtoupper($oImapResponse->ResponseList[3][3])
+ && \is_numeric($oImapResponse->ResponseList[3][4])
+ && \is_numeric($oImapResponse->ResponseList[3][5])
+ )
+ {
+ $aReturn[2] = (int) $oImapResponse->ResponseList[3][4];
+ $aReturn[3] = (int) $oImapResponse->ResponseList[3][5];
+ }
+ }
+ }
+ }
+
+ return $aReturn;
+ }
+
+ /**
+ * @param array $aSortTypes
+ * @param string $sSearchCriterias
+ * @param bool $bReturnUid
+ *
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageSimpleSort($aSortTypes, $sSearchCriterias = 'ALL', $bReturnUid = true)
+ {
+ $sCommandPrefix = ($bReturnUid) ? 'UID ' : '';
+ $sSearchCriterias = !\MailSo\Base\Validator::NotEmptyString($sSearchCriterias, true) || '*' === $sSearchCriterias
+ ? 'ALL' : $sSearchCriterias;
+
+ if (!\is_array($aSortTypes) || 0 === \count($aSortTypes))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+ else if (!$this->IsSupported('SORT'))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $aRequest = array();
+ $aRequest[] = $aSortTypes;
+ $aRequest[] = \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? 'US-ASCII' : 'UTF-8';
+ $aRequest[] = $sSearchCriterias;
+
+ $sCmd = 'SORT';
+
+ $this->SendRequest($sCommandPrefix.$sCmd, $aRequest);
+ $aResult = $this->parseResponseWithValidation();
+
+ $aReturn = array();
+ $oImapResponse = null;
+ foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType
+ && ($sCmd === $oImapResponse->StatusOrIndex ||
+ ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex) && !empty($oImapResponse->ResponseList[2]) &&
+ $sCmd === $oImapResponse->ResponseList[2])
+ && \is_array($oImapResponse->ResponseList)
+ && 2 < \count($oImapResponse->ResponseList))
+ {
+ $iStart = 2;
+ if ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex &&
+ !empty($oImapResponse->ResponseList[2]) &&
+ $sCmd === $oImapResponse->ResponseList[2])
+ {
+ $iStart = 3;
+ }
+
+ for ($iIndex = $iStart, $iLen = \count($oImapResponse->ResponseList); $iIndex < $iLen; $iIndex++)
+ {
+ $aReturn[] = (int) $oImapResponse->ResponseList[$iIndex];
+ }
+ }
+ }
+
+ return $aReturn;
+ }
+
+ /**
+ * @param bool $bSort = false
+ * @param string $sSearchCriterias = 'ALL'
+ * @param array $aSearchOrSortReturn = null
+ * @param bool $bReturnUid = true
+ * @param string $sLimit = ''
+ * @param string $sCharset = ''
+ * @param array $aSortTypes = null
+ *
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ private function simpleESearchOrESortHelper($bSort = false, $sSearchCriterias = 'ALL', $aSearchOrSortReturn = null, $bReturnUid = true, $sLimit = '', $sCharset = '', $aSortTypes = null)
+ {
+ $sCommandPrefix = ($bReturnUid) ? 'UID ' : '';
+ $sSearchCriterias = 0 === \strlen($sSearchCriterias) || '*' === $sSearchCriterias
+ ? 'ALL' : $sSearchCriterias;
+
+ $sCmd = $bSort ? 'SORT': 'SEARCH';
+ if ($bSort && (!\is_array($aSortTypes) || 0 === \count($aSortTypes) || !$this->IsSupported('SORT')))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ if (!$this->IsSupported($bSort ? 'ESORT' : 'ESEARCH'))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ if (!\is_array($aSearchOrSortReturn) || 0 === \count($aSearchOrSortReturn))
+ {
+ $aSearchOrSortReturn = array('ALL');
+ }
+
+ $aRequest = array();
+ if ($bSort)
+ {
+ $aRequest[] = 'RETURN';
+ $aRequest[] = $aSearchOrSortReturn;
+
+ $aRequest[] = $aSortTypes;
+ $aRequest[] = \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? 'US-ASCII' : 'UTF-8';
+ }
+ else
+ {
+ if (0 < \strlen($sCharset))
+ {
+ $aRequest[] = 'CHARSET';
+ $aRequest[] = \strtoupper($sCharset);
+ }
+
+ $aRequest[] = 'RETURN';
+ $aRequest[] = $aSearchOrSortReturn;
+ }
+
+ $aRequest[] = $sSearchCriterias;
+
+ if (0 < \strlen($sLimit))
+ {
+ $aRequest[] = $sLimit;
+ }
+
+ $this->SendRequest($sCommandPrefix.$sCmd, $aRequest);
+ $sRequestTag = $this->getCurrentTag();
+
+ $aResult = array();
+ $aResponse = $this->parseResponseWithValidation();
+
+ if (\is_array($aResponse))
+ {
+ $oImapResponse = null;
+ foreach ($aResponse as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType
+ && ('ESEARCH' === $oImapResponse->StatusOrIndex || 'ESORT' === $oImapResponse->StatusOrIndex)
+ && \is_array($oImapResponse->ResponseList)
+ && isset($oImapResponse->ResponseList[2], $oImapResponse->ResponseList[2][0], $oImapResponse->ResponseList[2][1])
+ && 'TAG' === $oImapResponse->ResponseList[2][0] && $sRequestTag === $oImapResponse->ResponseList[2][1]
+ && (!$bReturnUid || ($bReturnUid && !empty($oImapResponse->ResponseList[3]) && 'UID' === $oImapResponse->ResponseList[3]))
+ )
+ {
+ $iStart = 3;
+ foreach ($oImapResponse->ResponseList as $iIndex => $mItem)
+ {
+ if ($iIndex >= $iStart)
+ {
+ switch ($mItem)
+ {
+ case 'ALL':
+ case 'MAX':
+ case 'MIN':
+ case 'COUNT':
+ if (isset($oImapResponse->ResponseList[$iIndex + 1]))
+ {
+ $aResult[$mItem] = $oImapResponse->ResponseList[$iIndex + 1];
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @param string $sSearchCriterias = 'ALL'
+ * @param array $aSearchReturn = null
+ * @param bool $bReturnUid = true
+ * @param string $sLimit = ''
+ * @param string $sCharset = ''
+ *
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageSimpleESearch($sSearchCriterias = 'ALL', $aSearchReturn = null, $bReturnUid = true, $sLimit = '', $sCharset = '')
+ {
+ return $this->simpleESearchOrESortHelper(false, $sSearchCriterias, $aSearchReturn, $bReturnUid, $sLimit, $sCharset);
+ }
+
+ /**
+ * @param array $aSortTypes
+ * @param string $sSearchCriterias = 'ALL'
+ * @param array $aSearchReturn = null
+ * @param bool $bReturnUid = true
+ * @param string $sLimit = ''
+ *
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageSimpleESort($aSortTypes, $sSearchCriterias = 'ALL', $aSearchReturn = null, $bReturnUid = true, $sLimit = '')
+ {
+ return $this->simpleESearchOrESortHelper(true, $sSearchCriterias, $aSearchReturn, $bReturnUid, $sLimit, '', $aSortTypes);
+ }
+
+ /**
+ * @param array $aResult
+ * @return \MailSo\Imap\Response
+ */
+ private function findLastResponse($aResult)
+ {
+ $oResult = null;
+ if (\is_array($aResult) && 0 < \count($aResult))
+ {
+ $oResult = $aResult[\count($aResult) - 1];
+ if (!($oResult instanceof \MailSo\Imap\Response))
+ {
+ $oResult = null;
+ }
+ }
+
+ return $oResult;
+ }
+
+ /**
+ * @param string $sSearchCriterias
+ * @param bool $bReturnUid = true
+ * @param string $sCharset = ''
+ *
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageSimpleSearch($sSearchCriterias = 'ALL', $bReturnUid = true, $sCharset = '')
+ {
+ $sCommandPrefix = ($bReturnUid) ? 'UID ' : '';
+ $sSearchCriterias = 0 === \strlen($sSearchCriterias) || '*' === $sSearchCriterias
+ ? 'ALL' : $sSearchCriterias;
+
+ $aRequest = array();
+ if (0 < \strlen($sCharset))
+ {
+ $aRequest[] = 'CHARSET';
+ $aRequest[] = \strtoupper($sCharset);
+ }
+
+ $aRequest[] = $sSearchCriterias;
+
+ $sCmd = 'SEARCH';
+
+ $sCont = $this->SendRequest($sCommandPrefix.$sCmd, $aRequest, true);
+ if ('' !== $sCont)
+ {
+ $aResult = $this->parseResponseWithValidation();
+ $oItem = $this->findLastResponse($aResult);
+
+ if ($oItem && \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oItem->ResponseType)
+ {
+ $aParts = explode("\r\n", $sCont);
+ foreach ($aParts as $sLine)
+ {
+ $this->sendRaw($sLine);
+
+ $aResult = $this->parseResponseWithValidation();
+ $oItem = $this->findLastResponse($aResult);
+ if ($oItem && \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oItem->ResponseType)
+ {
+ continue;
+ }
+ }
+ }
+ }
+ else
+ {
+ $aResult = $this->parseResponseWithValidation();
+ }
+
+ $aReturn = array();
+ $oImapResponse = null;
+ foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType
+ && ($sCmd === $oImapResponse->StatusOrIndex ||
+ ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex) && !empty($oImapResponse->ResponseList[2]) &&
+ $sCmd === $oImapResponse->ResponseList[2])
+ && \is_array($oImapResponse->ResponseList)
+ && 2 < count($oImapResponse->ResponseList))
+ {
+ $iStart = 2;
+ if ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex &&
+ !empty($oImapResponse->ResponseList[2]) &&
+ $sCmd === $oImapResponse->ResponseList[2])
+ {
+ $iStart = 3;
+ }
+
+ for ($iIndex = $iStart, $iLen = \count($oImapResponse->ResponseList); $iIndex < $iLen; $iIndex++)
+ {
+ $aReturn[] = (int) $oImapResponse->ResponseList[$iIndex];
+ }
+ }
+ }
+
+ $aReturn = \array_reverse($aReturn);
+ return $aReturn;
+ }
+
+ /**
+ * @param mixed $aValue
+ *
+ * @return mixed
+ */
+ private function validateThreadItem($aValue)
+ {
+ $mResult = false;
+ if (\is_numeric($aValue))
+ {
+ $mResult = (int) $aValue;
+ if (0 >= $mResult)
+ {
+ $mResult = false;
+ }
+ }
+ else if (\is_array($aValue))
+ {
+ if (1 === \count($aValue) && \is_numeric($aValue[0]))
+ {
+ $mResult = (int) $aValue[0];
+ if (0 >= $mResult)
+ {
+ $mResult = false;
+ }
+ }
+ else
+ {
+ $mResult = array();
+ foreach ($aValue as $aValueItem)
+ {
+ $mTemp = $this->validateThreadItem($aValueItem);
+ if (false !== $mTemp)
+ {
+ $mResult[] = $mTemp;
+ }
+ }
+ }
+ }
+
+ return $mResult;
+ }
+
+ /**
+ * @param string $sSearchCriterias = 'ALL'
+ * @param bool $bReturnUid = true
+ * @param string $sCharset = \MailSo\Base\Enumerations\Charset::UTF_8
+ *
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageSimpleThread($sSearchCriterias = 'ALL', $bReturnUid = true, $sCharset = \MailSo\Base\Enumerations\Charset::UTF_8)
+ {
+ $sCommandPrefix = ($bReturnUid) ? 'UID ' : '';
+ $sSearchCriterias = !\MailSo\Base\Validator::NotEmptyString($sSearchCriterias, true) || '*' === $sSearchCriterias
+ ? 'ALL' : $sSearchCriterias;
+
+ $sThreadType = '';
+ switch (true)
+ {
+ case $this->IsSupported('THREAD=REFS'):
+ $sThreadType = 'REFS';
+ break;
+ case $this->IsSupported('THREAD=REFERENCES'):
+ $sThreadType = 'REFERENCES';
+ break;
+ case $this->IsSupported('THREAD=ORDEREDSUBJECT'):
+ $sThreadType = 'ORDEREDSUBJECT';
+ break;
+ default:
+ $this->writeLogException(
+ new Exceptions\RuntimeException('Thread is not supported'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ break;
+ }
+
+ $aRequest = array();
+ $aRequest[] = $sThreadType;
+ $aRequest[] = \strtoupper($sCharset);
+ $aRequest[] = $sSearchCriterias;
+
+ $sCmd = 'THREAD';
+
+ $this->SendRequest($sCommandPrefix.$sCmd, $aRequest);
+ $aResult = $this->parseResponseWithValidation();
+
+ $aReturn = array();
+ $oImapResponse = null;
+
+ foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType
+ && ($sCmd === $oImapResponse->StatusOrIndex ||
+ ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex) && !empty($oImapResponse->ResponseList[2]) &&
+ $sCmd === $oImapResponse->ResponseList[2])
+ && \is_array($oImapResponse->ResponseList)
+ && 2 < \count($oImapResponse->ResponseList))
+ {
+ $iStart = 2;
+ if ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex &&
+ !empty($oImapResponse->ResponseList[2]) &&
+ $sCmd === $oImapResponse->ResponseList[2])
+ {
+ $iStart = 3;
+ }
+
+ for ($iIndex = $iStart, $iLen = \count($oImapResponse->ResponseList); $iIndex < $iLen; $iIndex++)
+ {
+ $aNewValue = $this->validateThreadItem($oImapResponse->ResponseList[$iIndex]);
+ if (false !== $aNewValue)
+ {
+ $aReturn[] = $aNewValue;
+ }
+ }
+ }
+ }
+
+ return $aReturn;
+ }
+
+ /**
+ * @param string $sToFolder
+ * @param string $sIndexRange
+ * @param bool $bIndexIsUid
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageCopy($sToFolder, $sIndexRange, $bIndexIsUid)
+ {
+ if (0 === \strlen($sIndexRange))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $sCommandPrefix = ($bIndexIsUid) ? 'UID ' : '';
+ return $this->SendRequestWithCheck($sCommandPrefix.'COPY',
+ array($sIndexRange, $this->EscapeString($sToFolder)));
+ }
+
+ /**
+ * @param string $sToFolder
+ * @param string $sIndexRange
+ * @param bool $bIndexIsUid
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageMove($sToFolder, $sIndexRange, $bIndexIsUid)
+ {
+ if (0 === \strlen($sIndexRange))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ if (!$this->IsSupported('MOVE'))
+ {
+ $this->writeLogException(
+ new Exceptions\RuntimeException('Move is not supported'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $sCommandPrefix = ($bIndexIsUid) ? 'UID ' : '';
+ return $this->SendRequestWithCheck($sCommandPrefix.'MOVE',
+ array($sIndexRange, $this->EscapeString($sToFolder)));
+ }
+
+ /**
+ * @param string $sUidRangeIfSupported = ''
+ * @param bool $bForceUidExpunge = false
+ * @param bool $bExpungeAll = false
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageExpunge($sUidRangeIfSupported = '', $bForceUidExpunge = false, $bExpungeAll = false)
+ {
+ $sUidRangeIfSupported = \trim($sUidRangeIfSupported);
+
+ $sCmd = 'EXPUNGE';
+ $aArguments = array();
+
+ if (!$bExpungeAll && $bForceUidExpunge && 0 < \strlen($sUidRangeIfSupported) && $this->IsSupported('UIDPLUS'))
+ {
+ $sCmd = 'UID '.$sCmd;
+ $aArguments = array($sUidRangeIfSupported);
+ }
+
+ return $this->SendRequestWithCheck($sCmd, $aArguments);
+ }
+
+ /**
+ * @param string $sIndexRange
+ * @param bool $bIndexIsUid
+ * @param array $aInputStoreItems
+ * @param string $sStoreAction
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageStoreFlag($sIndexRange, $bIndexIsUid, $aInputStoreItems, $sStoreAction)
+ {
+ if (!\MailSo\Base\Validator::NotEmptyString($sIndexRange, true) ||
+ !\MailSo\Base\Validator::NotEmptyString($sStoreAction, true) ||
+ 0 === \count($aInputStoreItems))
+ {
+ return false;
+ }
+
+ $sCmd = ($bIndexIsUid) ? 'UID STORE' : 'STORE';
+ return $this->SendRequestWithCheck($sCmd, array($sIndexRange, $sStoreAction, $aInputStoreItems));
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param resource $rMessageAppendStream
+ * @param int $iStreamSize
+ * @param array $aAppendFlags = null
+ * @param int $iUid = null
+ * @param int $sDateTime = 0
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageAppendStream($sFolderName, $rMessageAppendStream, $iStreamSize, $aAppendFlags = null, &$iUid = null, $sDateTime = 0)
+ {
+ $aData = array($this->EscapeString($sFolderName), $aAppendFlags);
+ if (0 < $sDateTime)
+ {
+ $aData[] = $this->EscapeString(\gmdate('d-M-Y H:i:s', $sDateTime).' +0000');
+ }
+
+ $aData[] = '{'.$iStreamSize.'}';
+
+ $this->SendRequest('APPEND', $aData);
+ $this->parseResponseWithValidation();
+
+ $this->writeLog('Write to connection stream', \MailSo\Log\Enumerations\Type::NOTE);
+
+ \MailSo\Base\Utils::MultipleStreamWriter($rMessageAppendStream, array($this->rConnect));
+
+ $this->sendRaw('');
+ $this->parseResponseWithValidation();
+
+ if (null !== $iUid)
+ {
+ $aLastResponse = $this->GetLastResponse();
+ if (\is_array($aLastResponse) && 0 < \count($aLastResponse) && $aLastResponse[\count($aLastResponse) - 1])
+ {
+ $oLast = $aLastResponse[count($aLastResponse) - 1];
+ if ($oLast && \MailSo\Imap\Enumerations\ResponseType::TAGGED === $oLast->ResponseType && \is_array($oLast->OptionalResponse))
+ {
+ if (0 < \strlen($oLast->OptionalResponse[0]) &&
+ 0 < \strlen($oLast->OptionalResponse[2]) &&
+ 'APPENDUID' === strtoupper($oLast->OptionalResponse[0]) &&
+ \is_numeric($oLast->OptionalResponse[2])
+ )
+ {
+ $iUid = (int) $oLast->OptionalResponse[2];
+ }
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Imap\FolderInformation
+ */
+ public function FolderCurrentInformation()
+ {
+ return $this->oCurrentFolderInfo;
+ }
+
+ /**
+ * @param string $sCommand
+ * @param array $aParams = array()
+ * @param bool $bBreakOnLiteral = false
+ *
+ * @return string
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ public function SendRequest($sCommand, $aParams = array(), $bBreakOnLiteral = false)
+ {
+ if (!\MailSo\Base\Validator::NotEmptyString($sCommand, true) || !\is_array($aParams))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $this->IsConnected(true);
+
+ $sTag = $this->getNewTag();
+
+ $sCommand = \trim($sCommand);
+ $sRealCommand = $sTag.' '.$sCommand.$this->prepearParamLine($aParams);
+
+ $sFakeCommand = '';
+ $aFakeParams = $this->secureRequestParams($sCommand, $aParams);
+ if (null !== $aFakeParams)
+ {
+ $sFakeCommand = $sTag.' '.$sCommand.$this->prepearParamLine($aFakeParams);
+ }
+
+ $this->aTagTimeouts[$sTag] = \microtime(true);
+
+ if ($bBreakOnLiteral && !\preg_match('/\d\+\}\r\n/', $sRealCommand))
+ {
+ $iPos = \strpos($sRealCommand, "}\r\n");
+ if (false !== $iPos)
+ {
+ $iFakePos = \strpos($sFakeCommand, "}\r\n");
+
+ $this->sendRaw(\substr($sRealCommand, 0, $iPos + 1), true,
+ false !== $iFakePos ? \substr($sFakeCommand, 0, $iFakePos + 3) : '');
+
+ return \substr($sRealCommand, $iPos + 3);
+ }
+ }
+
+ $this->sendRaw($sRealCommand, true, $sFakeCommand);
+ return '';
+ }
+
+ /**
+ * @param string $sCommand
+ * @param array $aParams
+ *
+ * @return array|null
+ */
+ private function secureRequestParams($sCommand, $aParams)
+ {
+ $aResult = null;
+ switch ($sCommand)
+ {
+ case 'LOGIN':
+ $aResult = $aParams;
+ if (\is_array($aResult) && 2 === count($aResult))
+ {
+ $aResult[1] = '"********"';
+ }
+ break;
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @param string $sCommand
+ * @param array $aParams = array()
+ * @param bool $bFindCapa = false
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function SendRequestWithCheck($sCommand, $aParams = array(), $bFindCapa = false)
+ {
+ $this->SendRequest($sCommand, $aParams);
+ $this->parseResponseWithValidation(null, $bFindCapa);
+
+ return $this;
+ }
+
+ /**
+ * @return array
+ */
+ public function GetLastResponse()
+ {
+ return $this->aLastResponse;
+ }
+
+ /**
+ * @param mixed $aResult
+ *
+ * @return array
+ *
+ * @throws \MailSo\Imap\Exceptions\ResponseNotFoundException
+ * @throws \MailSo\Imap\Exceptions\InvalidResponseException
+ * @throws \MailSo\Imap\Exceptions\NegativeResponseException
+ */
+ private function validateResponse($aResult)
+ {
+ if (!\is_array($aResult) || 0 === $iCnt = \count($aResult))
+ {
+ $this->writeLogException(
+ new Exceptions\ResponseNotFoundException(),
+ \MailSo\Log\Enumerations\Type::WARNING, true);
+ }
+
+ if ($aResult[$iCnt - 1]->ResponseType !== \MailSo\Imap\Enumerations\ResponseType::CONTINUATION)
+ {
+ if (!$aResult[$iCnt - 1]->IsStatusResponse)
+ {
+ $this->writeLogException(
+ new Exceptions\InvalidResponseException($aResult),
+ \MailSo\Log\Enumerations\Type::WARNING, true);
+ }
+
+ if (\MailSo\Imap\Enumerations\ResponseStatus::OK !== $aResult[$iCnt - 1]->StatusOrIndex)
+ {
+ $this->writeLogException(
+ new Exceptions\NegativeResponseException($aResult),
+ \MailSo\Log\Enumerations\Type::WARNING, true);
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @param string $sEndTag = null
+ * @param bool $bFindCapa = false
+ *
+ * @return array|bool
+ */
+ protected function parseResponse($sEndTag = null, $bFindCapa = false)
+ {
+ if (\is_resource($this->rConnect))
+ {
+ $oImapResponse = null;
+ $sEndTag = (null === $sEndTag) ? $this->getCurrentTag() : $sEndTag;
+
+ while (true)
+ {
+ $oImapResponse = Response::NewInstance();
+
+ $this->partialParseResponseBranch($oImapResponse);
+
+ if ($oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNKNOWN === $oImapResponse->ResponseType)
+ {
+ return false;
+ }
+
+ if ($bFindCapa)
+ {
+ $this->initCapabilityImapResponse($oImapResponse);
+ }
+
+ $this->aPartialResponses[] = $oImapResponse;
+ if ($sEndTag === $oImapResponse->Tag || \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oImapResponse->ResponseType)
+ {
+ if (isset($this->aTagTimeouts[$sEndTag]))
+ {
+ $this->writeLog((\microtime(true) - $this->aTagTimeouts[$sEndTag]).' ('.$sEndTag.')',
+ \MailSo\Log\Enumerations\Type::TIME);
+
+ unset($this->aTagTimeouts[$sEndTag]);
+ }
+
+ break;
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ unset($oImapResponse);
+ }
+ }
+
+ $this->iResponseBufParsedPos = 0;
+ $this->aLastResponse = $this->aPartialResponses;
+ $this->aPartialResponses = array();
+
+ return $this->aLastResponse;
+ }
+
+ /**
+ * @param string $sEndTag = null
+ * @param bool $bFindCapa = false
+ *
+ * @return array
+ */
+ private function parseResponseWithValidation($sEndTag = null, $bFindCapa = false)
+ {
+ return $this->validateResponse($this->parseResponse($sEndTag, $bFindCapa));
+ }
+
+ /**
+ * @param \MailSo\Imap\Response $oImapResponse
+ *
+ * @return void
+ */
+ private function initCapabilityImapResponse($oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType
+ && \is_array($oImapResponse->ResponseList))
+ {
+ $aList = null;
+ if (isset($oImapResponse->ResponseList[1]) && \is_string($oImapResponse->ResponseList[1]) &&
+ 'CAPABILITY' === \strtoupper($oImapResponse->ResponseList[1]))
+ {
+ $aList = \array_slice($oImapResponse->ResponseList, 2);
+ }
+ else if ($oImapResponse->OptionalResponse && \is_array($oImapResponse->OptionalResponse) &&
+ 1 < \count($oImapResponse->OptionalResponse) && \is_string($oImapResponse->OptionalResponse[0]) &&
+ 'CAPABILITY' === \strtoupper($oImapResponse->OptionalResponse[0]))
+ {
+ $aList = \array_slice($oImapResponse->OptionalResponse, 1);
+ }
+
+ if (\is_array($aList) && 0 < \count($aList))
+ {
+ $this->aCapabilityItems = \array_map('strtoupper', $aList);
+ }
+ }
+ }
+
+ /**
+ * @return array|string
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ private function partialParseResponseBranch(&$oImapResponse, $iStackIndex = -1,
+ $bTreatAsAtom = false, $sParentToken = '', $sOpenBracket = '')
+ {
+ $mNull = null;
+
+ $iStackIndex++;
+ $iPos = $this->iResponseBufParsedPos;
+
+ $sPreviousAtomUpperCase = null;
+ $bIsEndOfList = false;
+ $bIsClosingBracketSquare = false;
+ $iLiteralLen = 0;
+ $iBufferEndIndex = 0;
+ $iDebugCount = 0;
+
+ $rImapLiteralStream = null;
+
+ $bIsGotoDefault = false;
+ $bIsGotoLiteral = false;
+ $bIsGotoLiteralEnd = false;
+ $bIsGotoAtomBracket = false;
+ $bIsGotoNotAtomBracket = false;
+
+ $bCountOneInited = false;
+ $bCountTwoInited = false;
+
+ $sAtomBuilder = $bTreatAsAtom ? '' : null;
+ $aList = array();
+ if (null !== $oImapResponse)
+ {
+ $aList =& $oImapResponse->ResponseList;
+ }
+
+ while (!$bIsEndOfList)
+ {
+ $iDebugCount++;
+ if (100000 === $iDebugCount)
+ {
+ $this->Logger()->Write('PartialParseOver: '.$iDebugCount, \MailSo\Log\Enumerations\Type::ERROR);
+ }
+
+ if ($this->bNeedNext)
+ {
+ $iPos = 0;
+ $this->getNextBuffer();
+ $this->iResponseBufParsedPos = $iPos;
+ $this->bNeedNext = false;
+ }
+
+ $sChar = null;
+ if ($bIsGotoDefault)
+ {
+ $sChar = 'GOTO_DEFAULT';
+ $bIsGotoDefault = false;
+ }
+ else if ($bIsGotoLiteral)
+ {
+ $bIsGotoLiteral = false;
+ $bIsGotoLiteralEnd = true;
+
+ if ($this->partialResponseLiteralCallbackCallable(
+ $sParentToken, null === $sPreviousAtomUpperCase ? '' : \strtoupper($sPreviousAtomUpperCase), $this->rConnect, $iLiteralLen))
+ {
+ if (!$bTreatAsAtom)
+ {
+ $aList[] = '';
+ }
+ }
+ else
+ {
+ $sLiteral = '';
+ $iRead = $iLiteralLen;
+
+ while (0 < $iRead)
+ {
+ $sAddRead = \fread($this->rConnect, $iRead);
+ if (false === $sAddRead)
+ {
+ $sLiteral = false;
+ break;
+ }
+
+ $sLiteral .= $sAddRead;
+ $iRead -= \strlen($sAddRead);
+
+ \MailSo\Base\Utils::ResetTimeLimit();
+ }
+
+ if (false !== $sLiteral)
+ {
+ $iLiteralSize = \strlen($sLiteral);
+ \MailSo\Base\Loader::IncStatistic('NetRead', $iLiteralSize);
+ if ($iLiteralLen !== $iLiteralSize)
+ {
+ $this->writeLog('Literal stream read warning "read '.$iLiteralSize.' of '.
+ $iLiteralLen.'" bytes', \MailSo\Log\Enumerations\Type::WARNING);
+ }
+
+ if (!$bTreatAsAtom)
+ {
+ $aList[] = $sLiteral;
+
+ if (\MailSo\Config::$LogSimpleLiterals)
+ {
+ $this->writeLog('{'.\strlen($sLiteral).'} '.$sLiteral, \MailSo\Log\Enumerations\Type::INFO);
+ }
+ }
+ }
+ else
+ {
+ $this->writeLog('Can\'t read imap stream', \MailSo\Log\Enumerations\Type::NOTE);
+ }
+
+ unset($sLiteral);
+ }
+
+ continue;
+ }
+ else if ($bIsGotoLiteralEnd)
+ {
+ $rImapLiteralStream = null;
+ $sPreviousAtomUpperCase = null;
+ $this->bNeedNext = true;
+ $bIsGotoLiteralEnd = false;
+
+ continue;
+ }
+ else if ($bIsGotoAtomBracket)
+ {
+ if ($bTreatAsAtom)
+ {
+ $sAtomBlock = $this->partialParseResponseBranch($mNull, $iStackIndex, true,
+ null === $sPreviousAtomUpperCase ? '' : \strtoupper($sPreviousAtomUpperCase), $sOpenBracket);
+
+ $sAtomBuilder .= $sAtomBlock;
+ $iPos = $this->iResponseBufParsedPos;
+ $sAtomBuilder .= ($bIsClosingBracketSquare) ? ']' : ')';
+ }
+
+ $sPreviousAtomUpperCase = null;
+ $bIsGotoAtomBracket = false;
+
+ continue;
+ }
+ else if ($bIsGotoNotAtomBracket)
+ {
+ $aSubItems = $this->partialParseResponseBranch($mNull, $iStackIndex, false,
+ null === $sPreviousAtomUpperCase ? '' : \strtoupper($sPreviousAtomUpperCase), $sOpenBracket);
+
+ $aList[] = $aSubItems;
+ $iPos = $this->iResponseBufParsedPos;
+ $sPreviousAtomUpperCase = null;
+ if (null !== $oImapResponse && $oImapResponse->IsStatusResponse)
+ {
+ $oImapResponse->OptionalResponse = $aSubItems;
+
+ $bIsGotoDefault = true;
+ $bIsGotoNotAtomBracket = false;
+ continue;
+ }
+ $bIsGotoNotAtomBracket = false;
+
+ continue;
+ }
+ else
+ {
+ $iBufferEndIndex = \strlen($this->sResponseBuffer) - 3;
+ $this->bResponseBufferChanged = false;
+
+ if ($iPos > $iBufferEndIndex)
+ {
+ break;
+ }
+
+ $sChar = $this->sResponseBuffer[$iPos];
+ }
+
+ switch (true)
+ {
+ case ']' === $sChar:
+ $iPos++;
+ $sPreviousAtomUpperCase = null;
+ $bIsEndOfList = true;
+ break;
+ case ')' === $sChar:
+ $iPos++;
+ $sPreviousAtomUpperCase = null;
+ $bIsEndOfList = true;
+ break;
+ case ' ' === $sChar:
+ if ($bTreatAsAtom)
+ {
+ $sAtomBuilder .= ' ';
+ }
+ $iPos++;
+ break;
+ case '[' === $sChar:
+ $bIsClosingBracketSquare = true;
+ case '(' === $sChar:
+ if ('(' === $sChar)
+ {
+ $bIsClosingBracketSquare = false;
+ }
+
+ if ($bTreatAsAtom)
+ {
+ $sAtomBuilder .= $bIsClosingBracketSquare ? '[' : '(';
+ }
+ $iPos++;
+
+ $this->iResponseBufParsedPos = $iPos;
+ if ($bTreatAsAtom)
+ {
+ $bIsGotoAtomBracket = true;
+ $sOpenBracket = $bIsClosingBracketSquare ? '[' : '(';
+ }
+ else
+ {
+ $bIsGotoNotAtomBracket = true;
+ $sOpenBracket = $bIsClosingBracketSquare ? '[' : '(';
+ }
+ break;
+ case '{' === $sChar:
+ $bIsLiteralParsed = false;
+ $mLiteralEndPos = \strpos($this->sResponseBuffer, '}', $iPos);
+ if (false !== $mLiteralEndPos && $mLiteralEndPos > $iPos)
+ {
+ $sLiteralLenAsString = \substr($this->sResponseBuffer, $iPos + 1, $mLiteralEndPos - $iPos - 1);
+ if (\is_numeric($sLiteralLenAsString))
+ {
+ $iLiteralLen = (int) $sLiteralLenAsString;
+ $bIsLiteralParsed = true;
+ $iPos = $mLiteralEndPos + 3;
+ $bIsGotoLiteral = true;
+ break;
+ }
+ }
+ if (!$bIsLiteralParsed)
+ {
+ $iPos = $iBufferEndIndex;
+ }
+ $sPreviousAtomUpperCase = null;
+ break;
+ case '"' === $sChar:
+ $bIsQuotedParsed = false;
+ while (true)
+ {
+ $iClosingPos = $iPos + 1;
+ if ($iClosingPos > $iBufferEndIndex)
+ {
+ break;
+ }
+
+ while (true)
+ {
+ $iClosingPos = \strpos($this->sResponseBuffer, '"', $iClosingPos);
+ if (false === $iClosingPos)
+ {
+ break;
+ }
+
+ // TODO
+ $iClosingPosNext = $iClosingPos + 1;
+ if (
+ isset($this->sResponseBuffer[$iClosingPosNext]) &&
+ ' ' !== $this->sResponseBuffer[$iClosingPosNext] &&
+ "\r" !== $this->sResponseBuffer[$iClosingPosNext] &&
+ "\n" !== $this->sResponseBuffer[$iClosingPosNext] &&
+ ']' !== $this->sResponseBuffer[$iClosingPosNext] &&
+ ')' !== $this->sResponseBuffer[$iClosingPosNext]
+ )
+ {
+ $iClosingPos++;
+ continue;
+ }
+
+ $iSlashCount = 0;
+ while ('\\' === $this->sResponseBuffer[$iClosingPos - $iSlashCount - 1])
+ {
+ $iSlashCount++;
+ }
+
+ if ($iSlashCount % 2 == 1)
+ {
+ $iClosingPos++;
+ continue;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (false === $iClosingPos)
+ {
+ break;
+ }
+ else
+ {
+// $iSkipClosingPos = 0;
+ $bIsQuotedParsed = true;
+ if ($bTreatAsAtom)
+ {
+ $sAtomBuilder .= \strtr(
+ \substr($this->sResponseBuffer, $iPos, $iClosingPos - $iPos + 1),
+ array('\\\\' => '\\', '\\"' => '"')
+ );
+ }
+ else
+ {
+ $aList[] = \strtr(
+ \substr($this->sResponseBuffer, $iPos + 1, $iClosingPos - $iPos - 1),
+ array('\\\\' => '\\', '\\"' => '"')
+ );
+ }
+
+ $iPos = $iClosingPos + 1;
+ break;
+ }
+ }
+
+ if (!$bIsQuotedParsed)
+ {
+ $iPos = $iBufferEndIndex;
+ }
+
+ $sPreviousAtomUpperCase = null;
+ break;
+
+ case 'GOTO_DEFAULT' === $sChar:
+ default:
+ $iCharBlockStartPos = $iPos;
+
+ if (null !== $oImapResponse && $oImapResponse->IsStatusResponse)
+ {
+ $iPos = $iBufferEndIndex;
+
+ while ($iPos > $iCharBlockStartPos && $this->sResponseBuffer[$iCharBlockStartPos] === ' ')
+ {
+ $iCharBlockStartPos++;
+ }
+ }
+
+ $bIsAtomDone = false;
+ while (!$bIsAtomDone && ($iPos <= $iBufferEndIndex))
+ {
+ $sCharDef = $this->sResponseBuffer[$iPos];
+ switch (true)
+ {
+ case '[' === $sCharDef:
+ if (null === $sAtomBuilder)
+ {
+ $sAtomBuilder = '';
+ }
+
+ $sAtomBuilder .= \substr($this->sResponseBuffer, $iCharBlockStartPos, $iPos - $iCharBlockStartPos + 1);
+
+ $iPos++;
+ $this->iResponseBufParsedPos = $iPos;
+
+ $sListBlock = $this->partialParseResponseBranch($mNull, $iStackIndex, true,
+ null === $sPreviousAtomUpperCase ? '' : \strtoupper($sPreviousAtomUpperCase), '[');
+
+ if (null !== $sListBlock)
+ {
+ $sAtomBuilder .= $sListBlock.']';
+ }
+
+ $iPos = $this->iResponseBufParsedPos;
+ $iCharBlockStartPos = $iPos;
+ break;
+ case ' ' === $sCharDef:
+ case ')' === $sCharDef && '(' === $sOpenBracket:
+ case ']' === $sCharDef && '[' === $sOpenBracket:
+ $bIsAtomDone = true;
+ break;
+ default:
+ $iPos++;
+ break;
+ }
+ }
+
+ if ($iPos > $iCharBlockStartPos || null !== $sAtomBuilder)
+ {
+ $sLastCharBlock = \substr($this->sResponseBuffer, $iCharBlockStartPos, $iPos - $iCharBlockStartPos);
+ if (null === $sAtomBuilder)
+ {
+ $aList[] = $sLastCharBlock;
+ $sPreviousAtomUpperCase = $sLastCharBlock;
+ }
+ else
+ {
+ $sAtomBuilder .= $sLastCharBlock;
+
+ if (!$bTreatAsAtom)
+ {
+ $aList[] = $sAtomBuilder;
+ $sPreviousAtomUpperCase = $sAtomBuilder;
+ $sAtomBuilder = null;
+ }
+ }
+
+ if (null !== $oImapResponse)
+ {
+// if (1 === \count($aList))
+ if (!$bCountOneInited && 1 === \count($aList))
+// if (isset($aList[0]) && !isset($aList[1])) // fast 1 === \count($aList)
+ {
+ $bCountOneInited = true;
+
+ $oImapResponse->Tag = $aList[0];
+ if ('+' === $oImapResponse->Tag)
+ {
+ $oImapResponse->ResponseType = \MailSo\Imap\Enumerations\ResponseType::CONTINUATION;
+ }
+ else if ('*' === $oImapResponse->Tag)
+ {
+ $oImapResponse->ResponseType = \MailSo\Imap\Enumerations\ResponseType::UNTAGGED;
+ }
+ else if ($this->getCurrentTag() === $oImapResponse->Tag)
+ {
+ $oImapResponse->ResponseType = \MailSo\Imap\Enumerations\ResponseType::TAGGED;
+ }
+ else
+ {
+ $oImapResponse->ResponseType = \MailSo\Imap\Enumerations\ResponseType::UNKNOWN;
+ }
+ }
+// else if (2 === \count($aList))
+ else if (!$bCountTwoInited && 2 === \count($aList))
+// else if (isset($aList[1]) && !isset($aList[2])) // fast 2 === \count($aList)
+ {
+ $bCountTwoInited = true;
+
+ $oImapResponse->StatusOrIndex = strtoupper($aList[1]);
+
+ if ($oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::OK ||
+ $oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::NO ||
+ $oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::BAD ||
+ $oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::BYE ||
+ $oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::PREAUTH)
+ {
+ $oImapResponse->IsStatusResponse = true;
+ }
+ }
+ else if (\MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oImapResponse->ResponseType)
+ {
+ $oImapResponse->HumanReadable = $sLastCharBlock;
+ }
+ else if ($oImapResponse->IsStatusResponse)
+ {
+ $oImapResponse->HumanReadable = $sLastCharBlock;
+ }
+ }
+ }
+ }
+ }
+
+ $this->iResponseBufParsedPos = $iPos;
+ if (null !== $oImapResponse)
+ {
+ $this->bNeedNext = true;
+ $this->iResponseBufParsedPos = 0;
+ }
+
+ if (100000 < $iDebugCount)
+ {
+ $this->Logger()->Write('PartialParseOverResult: '.$iDebugCount, \MailSo\Log\Enumerations\Type::ERROR);
+ }
+
+ return $bTreatAsAtom ? $sAtomBuilder : $aList;
+ }
+
+ /**
+ * @param string $sParent
+ * @param string $sLiteralAtomUpperCase
+ * @param resource $rImapStream
+ * @param int $iLiteralLen
+ *
+ * @return bool
+ */
+ private function partialResponseLiteralCallbackCallable($sParent, $sLiteralAtomUpperCase, $rImapStream, $iLiteralLen)
+ {
+ $sLiteralAtomUpperCasePeek = '';
+ if (0 === \strpos($sLiteralAtomUpperCase, 'BODY'))
+ {
+ $sLiteralAtomUpperCasePeek = \str_replace('BODY', 'BODY.PEEK', $sLiteralAtomUpperCase);
+ }
+
+ $sFetchKey = '';
+ if (\is_array($this->aFetchCallbacks))
+ {
+ if (0 < \strlen($sLiteralAtomUpperCasePeek) && isset($this->aFetchCallbacks[$sLiteralAtomUpperCasePeek]))
+ {
+ $sFetchKey = $sLiteralAtomUpperCasePeek;
+ }
+ else if (0 < \strlen($sLiteralAtomUpperCase) && isset($this->aFetchCallbacks[$sLiteralAtomUpperCase]))
+ {
+ $sFetchKey = $sLiteralAtomUpperCase;
+ }
+ }
+
+ $bResult = false;
+ if (0 < \strlen($sFetchKey) && '' !== $this->aFetchCallbacks[$sFetchKey] &&
+ \is_callable($this->aFetchCallbacks[$sFetchKey]))
+ {
+ $rImapLiteralStream =
+ \MailSo\Base\StreamWrappers\Literal::CreateStream($rImapStream, $iLiteralLen);
+
+ $bResult = true;
+ $this->writeLog('Start Callback for '.$sParent.' / '.$sLiteralAtomUpperCase.
+ ' - try to read '.$iLiteralLen.' bytes.', \MailSo\Log\Enumerations\Type::NOTE);
+
+ $this->bRunningCallback = true;
+
+ try
+ {
+ \call_user_func($this->aFetchCallbacks[$sFetchKey],
+ $sParent, $sLiteralAtomUpperCase, $rImapLiteralStream);
+ }
+ catch (\Exception $oException)
+ {
+ $this->writeLog('Callback Exception', \MailSo\Log\Enumerations\Type::NOTICE);
+ $this->writeLogException($oException);
+ }
+
+ if (\is_resource($rImapLiteralStream))
+ {
+ $iNotReadLiteralLen = 0;
+
+ $bFeof = \feof($rImapLiteralStream);
+ $this->writeLog('End Callback for '.$sParent.' / '.$sLiteralAtomUpperCase.
+ ' - feof = '.($bFeof ? 'good' : 'BAD'), $bFeof ?
+ \MailSo\Log\Enumerations\Type::NOTE : \MailSo\Log\Enumerations\Type::WARNING);
+
+ if (!$bFeof)
+ {
+ while (!@\feof($rImapLiteralStream))
+ {
+ $sBuf = @\fread($rImapLiteralStream, 1024 * 1024);
+ if (false === $sBuf || 0 === \strlen($sBuf) || null === $sBuf)
+ {
+ break;
+ }
+
+ \MailSo\Base\Utils::ResetTimeLimit();
+ $iNotReadLiteralLen += \strlen($sBuf);
+ }
+
+ if (\is_resource($rImapLiteralStream) && !@\feof($rImapLiteralStream))
+ {
+ @\stream_get_contents($rImapLiteralStream);
+ }
+ }
+
+ if (\is_resource($rImapLiteralStream))
+ {
+ @\fclose($rImapLiteralStream);
+ }
+
+ if ($iNotReadLiteralLen > 0)
+ {
+ $this->writeLog('Not read literal size is '.$iNotReadLiteralLen.' bytes.',
+ \MailSo\Log\Enumerations\Type::WARNING);
+ }
+ }
+ else
+ {
+ $this->writeLog('Literal stream is not resource after callback.',
+ \MailSo\Log\Enumerations\Type::WARNING);
+ }
+
+ \MailSo\Base\Loader::IncStatistic('NetRead', $iLiteralLen);
+
+ $this->bRunningCallback = false;
+ }
+
+ return $bResult;
+ }
+
+ /**
+ * @param array $aParams = null
+ *
+ * @return string
+ */
+ private function prepearParamLine($aParams = array())
+ {
+ $sReturn = '';
+ if (\is_array($aParams) && 0 < \count($aParams))
+ {
+ foreach ($aParams as $mParamItem)
+ {
+ if (\is_array($mParamItem) && 0 < \count($mParamItem))
+ {
+ $sReturn .= ' ('.\trim($this->prepearParamLine($mParamItem)).')';
+ }
+ else if (\is_string($mParamItem))
+ {
+ $sReturn .= ' '.$mParamItem;
+ }
+ }
+ }
+ return $sReturn;
+ }
+
+ /**
+ * @return string
+ */
+ private function getNewTag()
+ {
+ $this->iTagCount++;
+ return $this->getCurrentTag();
+ }
+
+ /**
+ * @return string
+ */
+ private function getCurrentTag()
+ {
+ return self::TAG_PREFIX.$this->iTagCount;
+ }
+
+ /**
+ * @param string $sStringForEscape
+ *
+ * @return string
+ */
+ public function EscapeString($sStringForEscape)
+ {
+ return '"'.\str_replace(array('\\', '"'), array('\\\\', '\\"'), $sStringForEscape).'"';
+ }
+
+ /**
+ * @return string
+ */
+ protected function getLogName()
+ {
+ return 'IMAP';
+ }
+
+ /**
+ * @param \MailSo\Log\Logger $oLogger
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function SetLogger($oLogger)
+ {
+ parent::SetLogger($oLogger);
+
+ return $this;
+ }
+
+ /**
+ * @param resource $rConnect
+ * @param array $aCapabilityItems = array()
+ *
+ * @return \MailSo\Imap\ImapClient
+ */
+ public function TestSetValues($rConnect, $aCapabilityItems = array())
+ {
+ $this->rConnect = $rConnect;
+ $this->aCapabilityItems = $aCapabilityItems;
+
+ return $this;
+ }
+
+ /**
+ * @param string $sEndTag = null
+ * @param string $bFindCapa = false
+ *
+ * @return array
+ */
+ public function TestParseResponseWithValidationProxy($sEndTag = null, $bFindCapa = false)
+ {
+ return $this->parseResponseWithValidation($sEndTag, $bFindCapa);
+ }
+}
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Imap/NamespaceResult.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/NamespaceResult.php
similarity index 95%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Imap/NamespaceResult.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/NamespaceResult.php
index f53bd74ff6a64460fe5b1563b85ba1701551ba05..7d053f21e77c3e2fb110ac07d643686494c9d9f9 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Imap/NamespaceResult.php
+++ b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/NamespaceResult.php
@@ -1,132 +1,132 @@
-sPersonal = '';
- $this->sPersonalDelimiter = '';
- $this->sOtherUser = '';
- $this->sOtherUserDelimiter = '';
- $this->sShared = '';
- $this->sSharedDelimiter = '';
- }
-
- /**
- * @return \MailSo\Imap\NamespaceResult
- */
- public static function NewInstance()
- {
- return new self();
- }
-
- /**
- * @param \MailSo\Imap\Response $oImapResponse
- *
- * @return \MailSo\Imap\NamespaceResult
- */
- public function InitByImapResponse($oImapResponse)
- {
- if ($oImapResponse && $oImapResponse instanceof \MailSo\Imap\Response)
- {
- if (isset($oImapResponse->ResponseList[2][0]) &&
- \is_array($oImapResponse->ResponseList[2][0]) &&
- 2 <= \count($oImapResponse->ResponseList[2][0]))
- {
- $this->sPersonal = $oImapResponse->ResponseList[2][0][0];
- $this->sPersonalDelimiter = $oImapResponse->ResponseList[2][0][1];
-
- $this->sPersonal = 'INBOX'.$this->sPersonalDelimiter === \substr(\strtoupper($this->sPersonal), 0, 6) ?
- 'INBOX'.$this->sPersonalDelimiter.\substr($this->sPersonal, 6) : $this->sPersonal;
- }
-
- if (isset($oImapResponse->ResponseList[3][0]) &&
- \is_array($oImapResponse->ResponseList[3][0]) &&
- 2 <= \count($oImapResponse->ResponseList[3][0]))
- {
- $this->sOtherUser = $oImapResponse->ResponseList[3][0][0];
- $this->sOtherUserDelimiter = $oImapResponse->ResponseList[3][0][1];
-
- $this->sOtherUser = 'INBOX'.$this->sOtherUserDelimiter === \substr(\strtoupper($this->sOtherUser), 0, 6) ?
- 'INBOX'.$this->sOtherUserDelimiter.\substr($this->sOtherUser, 6) : $this->sOtherUser;
- }
-
- if (isset($oImapResponse->ResponseList[4][0]) &&
- \is_array($oImapResponse->ResponseList[4][0]) &&
- 2 <= \count($oImapResponse->ResponseList[4][0]))
- {
- $this->sShared = $oImapResponse->ResponseList[4][0][0];
- $this->sSharedDelimiter = $oImapResponse->ResponseList[4][0][1];
-
- $this->sShared = 'INBOX'.$this->sSharedDelimiter === \substr(\strtoupper($this->sShared), 0, 6) ?
- 'INBOX'.$this->sSharedDelimiter.\substr($this->sShared, 6) : $this->sShared;
- }
- }
-
- return $this;
- }
-
- /**
- * @return string
- */
- public function GetPersonalNamespace()
- {
- return $this->sPersonal;
- }
-
- /**
- * @return string
- */
- public function GetPersonalNamespaceDelimiter()
- {
- return $this->sPersonalDelimiter;
- }
-}
+sPersonal = '';
+ $this->sPersonalDelimiter = '';
+ $this->sOtherUser = '';
+ $this->sOtherUserDelimiter = '';
+ $this->sShared = '';
+ $this->sSharedDelimiter = '';
+ }
+
+ /**
+ * @return \MailSo\Imap\NamespaceResult
+ */
+ public static function NewInstance()
+ {
+ return new self();
+ }
+
+ /**
+ * @param \MailSo\Imap\Response $oImapResponse
+ *
+ * @return \MailSo\Imap\NamespaceResult
+ */
+ public function InitByImapResponse($oImapResponse)
+ {
+ if ($oImapResponse && $oImapResponse instanceof \MailSo\Imap\Response)
+ {
+ if (isset($oImapResponse->ResponseList[2][0]) &&
+ \is_array($oImapResponse->ResponseList[2][0]) &&
+ 2 <= \count($oImapResponse->ResponseList[2][0]))
+ {
+ $this->sPersonal = $oImapResponse->ResponseList[2][0][0];
+ $this->sPersonalDelimiter = $oImapResponse->ResponseList[2][0][1];
+
+ $this->sPersonal = 'INBOX'.$this->sPersonalDelimiter === \substr(\strtoupper($this->sPersonal), 0, 6) ?
+ 'INBOX'.$this->sPersonalDelimiter.\substr($this->sPersonal, 6) : $this->sPersonal;
+ }
+
+ if (isset($oImapResponse->ResponseList[3][0]) &&
+ \is_array($oImapResponse->ResponseList[3][0]) &&
+ 2 <= \count($oImapResponse->ResponseList[3][0]))
+ {
+ $this->sOtherUser = $oImapResponse->ResponseList[3][0][0];
+ $this->sOtherUserDelimiter = $oImapResponse->ResponseList[3][0][1];
+
+ $this->sOtherUser = 'INBOX'.$this->sOtherUserDelimiter === \substr(\strtoupper($this->sOtherUser), 0, 6) ?
+ 'INBOX'.$this->sOtherUserDelimiter.\substr($this->sOtherUser, 6) : $this->sOtherUser;
+ }
+
+ if (isset($oImapResponse->ResponseList[4][0]) &&
+ \is_array($oImapResponse->ResponseList[4][0]) &&
+ 2 <= \count($oImapResponse->ResponseList[4][0]))
+ {
+ $this->sShared = $oImapResponse->ResponseList[4][0][0];
+ $this->sSharedDelimiter = $oImapResponse->ResponseList[4][0][1];
+
+ $this->sShared = 'INBOX'.$this->sSharedDelimiter === \substr(\strtoupper($this->sShared), 0, 6) ?
+ 'INBOX'.$this->sSharedDelimiter.\substr($this->sShared, 6) : $this->sShared;
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetPersonalNamespace()
+ {
+ return $this->sPersonal;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetPersonalNamespaceDelimiter()
+ {
+ return $this->sPersonalDelimiter;
+ }
+}
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Imap/Response.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/Response.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Imap/Response.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Imap/Response.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/LICENSE b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/LICENSE
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/LICENSE
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/LICENSE
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Log/Driver.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Driver.php
similarity index 95%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Log/Driver.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Driver.php
index 457b78c47c04c7647910a91f3c4ade49d577f95c..fd313fc2821ada387e555993f5cae1cf0480058a 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Log/Driver.php
+++ b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Driver.php
@@ -1,408 +1,408 @@
-sDatePattern = 'H:i:s';
- $this->sName = 'INFO';
- $this->sNewLine = "\r\n";
- $this->bTimePrefix = true;
- $this->bTypedPrefix = true;
- $this->bGuidPrefix = true;
-
- $this->sTimeOffset = '0';
-
- $this->iWriteOnTimeoutOnly = 0;
- $this->bWriteOnErrorOnly = false;
- $this->bWriteOnPhpErrorOnly = false;
- $this->bFlushCache = false;
- $this->aCache = array();
-
- $this->aPrefixes = array(
- \MailSo\Log\Enumerations\Type::INFO => '[DATA]',
- \MailSo\Log\Enumerations\Type::SECURE => '[SECURE]',
- \MailSo\Log\Enumerations\Type::NOTE => '[NOTE]',
- \MailSo\Log\Enumerations\Type::TIME => '[TIME]',
- \MailSo\Log\Enumerations\Type::TIME_DELTA => '[TIME]',
- \MailSo\Log\Enumerations\Type::MEMORY => '[MEMORY]',
- \MailSo\Log\Enumerations\Type::NOTICE => '[NOTICE]',
- \MailSo\Log\Enumerations\Type::WARNING => '[WARNING]',
- \MailSo\Log\Enumerations\Type::ERROR => '[ERROR]',
-
- \MailSo\Log\Enumerations\Type::NOTICE_PHP => '[NOTICE]',
- \MailSo\Log\Enumerations\Type::WARNING_PHP => '[WARNING]',
- \MailSo\Log\Enumerations\Type::ERROR_PHP => '[ERROR]',
- );
- }
-
- /**
- * @param string $sTimeOffset
- *
- * @return \MailSo\Log\Driver
- */
- public function SetTimeOffset($sTimeOffset)
- {
- $this->sTimeOffset = (string) $sTimeOffset;
- return $this;
- }
-
- /**
- * @return \MailSo\Log\Driver
- */
- public function DisableGuidPrefix()
- {
- $this->bGuidPrefix = false;
- return $this;
- }
-
- /**
- * @return \MailSo\Log\Driver
- */
- public function DisableTimePrefix()
- {
- $this->bTimePrefix = false;
- return $this;
- }
-
- /**
- * @param bool $bValue
- *
- * @return \MailSo\Log\Driver
- */
- public function WriteOnErrorOnly($bValue)
- {
- $this->bWriteOnErrorOnly = !!$bValue;
- return $this;
- }
-
- /**
- * @param bool $bValue
- *
- * @return \MailSo\Log\Driver
- */
- public function WriteOnPhpErrorOnly($bValue)
- {
- $this->bWriteOnPhpErrorOnly = !!$bValue;
- return $this;
- }
-
- /**
- * @param int $iTimeout
- *
- * @return \MailSo\Log\Driver
- */
- public function WriteOnTimeoutOnly($iTimeout)
- {
- $this->iWriteOnTimeoutOnly = (int) $iTimeout;
- if (0 > $this->iWriteOnTimeoutOnly)
- {
- $this->iWriteOnTimeoutOnly = 0;
- }
-
- return $this;
- }
-
- /**
- * @return \MailSo\Log\Driver
- */
- public function DisableTypedPrefix()
- {
- $this->bTypedPrefix = false;
- return $this;
- }
-
- /**
- * @param string|array $mDesc
- * @return bool
- */
- abstract protected function writeImplementation($mDesc);
-
- /**
- * @return bool
- */
- protected function writeEmptyLineImplementation()
- {
- return $this->writeImplementation('');
- }
-
- /**
- * @param string $sTimePrefix
- * @param string $sDesc
- * @param int $iType = \MailSo\Log\Enumerations\Type::INFO
- * @param array $sName = ''
- *
- * @return string
- */
- protected function loggerLineImplementation($sTimePrefix, $sDesc,
- $iType = \MailSo\Log\Enumerations\Type::INFO, $sName = '')
- {
- return \ltrim(
- ($this->bTimePrefix ? '['.$sTimePrefix.']' : '').
- ($this->bGuidPrefix ? '['.\MailSo\Log\Logger::Guid().']' : '').
- ($this->bTypedPrefix ? ' '.$this->getTypedPrefix($iType, $sName) : '')
- ).$sDesc;
- }
-
- /**
- * @return bool
- */
- protected function clearImplementation()
- {
- return true;
- }
-
- /**
- * @return string
- */
- protected function getTimeWithMicroSec()
- {
- $aMicroTimeItems = \explode(' ', \microtime());
- return \MailSo\Log\Logger::DateHelper($this->sDatePattern, $this->sTimeOffset, $aMicroTimeItems[1]).'.'.
- \str_pad((int) ($aMicroTimeItems[0] * 1000), 3, '0', STR_PAD_LEFT);
- }
-
- /**
- * @param int $iType
- * @param string $sName = ''
- *
- * @return string
- */
- protected function getTypedPrefix($iType, $sName = '')
- {
- $sName = 0 < \strlen($sName) ? $sName : $this->sName;
- return isset($this->aPrefixes[$iType]) ? $sName.$this->aPrefixes[$iType].': ' : '';
- }
-
- /**
- * @param string|array $mDesc
- * @param bool $bDiplayCrLf = false
- *
- * @return string
- */
- protected function localWriteImplementation($mDesc, $bDiplayCrLf = false)
- {
- if ($bDiplayCrLf)
- {
- if (\is_array($mDesc))
- {
- foreach ($mDesc as &$sLine)
- {
- $sLine = \strtr($sLine, array("\r" => '\r', "\n" => '\n'.$this->sNewLine));
- $sLine = \rtrim($sLine);
- }
- }
- else
- {
- $mDesc = \strtr($mDesc, array("\r" => '\r', "\n" => '\n'.$this->sNewLine));
- $mDesc = \rtrim($mDesc);
- }
- }
-
- return $this->writeImplementation($mDesc);
- }
-
- /**
- * @final
- * @param string $sDesc
- * @param int $iType = \MailSo\Log\Enumerations\Type::INFO
- * @param string $sName = ''
- * @param bool $bDiplayCrLf = false
- *
- * @return bool
- */
- final public function Write($sDesc, $iType = \MailSo\Log\Enumerations\Type::INFO, $sName = '', $bDiplayCrLf = false)
- {
- $bResult = true;
- if (!$this->bFlushCache && ($this->bWriteOnErrorOnly || $this->bWriteOnPhpErrorOnly || 0 < $this->iWriteOnTimeoutOnly))
- {
- $bErrorPhp = false;
-
- $bError = $this->bWriteOnErrorOnly && \in_array($iType, array(
- \MailSo\Log\Enumerations\Type::NOTICE,
- \MailSo\Log\Enumerations\Type::NOTICE_PHP,
- \MailSo\Log\Enumerations\Type::WARNING,
- \MailSo\Log\Enumerations\Type::WARNING_PHP,
- \MailSo\Log\Enumerations\Type::ERROR,
- \MailSo\Log\Enumerations\Type::ERROR_PHP
- ));
-
- if (!$bError)
- {
- $bErrorPhp = $this->bWriteOnPhpErrorOnly && \in_array($iType, array(
- \MailSo\Log\Enumerations\Type::NOTICE_PHP,
- \MailSo\Log\Enumerations\Type::WARNING_PHP,
- \MailSo\Log\Enumerations\Type::ERROR_PHP
- ));
- }
-
- if ($bError || $bErrorPhp)
- {
- $sFlush = '--- FlushLogCache: '.($bError ? 'WriteOnErrorOnly' : 'WriteOnPhpErrorOnly');
- if (isset($this->aCache[0]) && empty($this->aCache[0]))
- {
- $this->aCache[0] = $sFlush;
- \array_unshift($this->aCache, '');
- }
- else
- {
- \array_unshift($this->aCache, $sFlush);
- }
-
- $this->aCache[] = '--- FlushLogCache: Trigger';
- $this->aCache[] = $this->loggerLineImplementation($this->getTimeWithMicroSec(), $sDesc, $iType, $sName);
-
- $this->bFlushCache = true;
- $bResult = $this->localWriteImplementation($this->aCache, $bDiplayCrLf);
- $this->aCache = array();
- }
- else if (0 < $this->iWriteOnTimeoutOnly && \time() - APP_START_TIME > $this->iWriteOnTimeoutOnly)
- {
- $sFlush = '--- FlushLogCache: WriteOnTimeoutOnly ['.(\time() - APP_START_TIME).'sec]';
- if (isset($this->aCache[0]) && empty($this->aCache[0]))
- {
- $this->aCache[0] = $sFlush;
- \array_unshift($this->aCache, '');
- }
- else
- {
- \array_unshift($this->aCache, $sFlush);
- }
-
- $this->aCache[] = '--- FlushLogCache: Trigger';
- $this->aCache[] = $this->loggerLineImplementation($this->getTimeWithMicroSec(), $sDesc, $iType, $sName);
-
- $this->bFlushCache = true;
- $bResult = $this->localWriteImplementation($this->aCache, $bDiplayCrLf);
- $this->aCache = array();
- }
- else
- {
- $this->aCache[] = $this->loggerLineImplementation($this->getTimeWithMicroSec(), $sDesc, $iType, $sName);
- }
- }
- else
- {
- $bResult = $this->localWriteImplementation(
- $this->loggerLineImplementation($this->getTimeWithMicroSec(), $sDesc, $iType, $sName), $bDiplayCrLf);
- }
-
- return $bResult;
- }
-
- /**
- * @return string
- */
- public function GetNewLine()
- {
- return $this->sNewLine;
- }
-
- /**
- * @final
- * @return bool
- */
- final public function Clear()
- {
- return $this->clearImplementation();
- }
-
- /**
- * @final
- * @return void
- */
- final public function WriteEmptyLine()
- {
- if (!$this->bFlushCache && ($this->bWriteOnErrorOnly || $this->bWriteOnPhpErrorOnly || 0 < $this->iWriteOnTimeoutOnly))
- {
- $this->aCache[] = '';
- }
- else
- {
- $this->writeEmptyLineImplementation();
- }
- }
-}
+sDatePattern = 'H:i:s';
+ $this->sName = 'INFO';
+ $this->sNewLine = "\r\n";
+ $this->bTimePrefix = true;
+ $this->bTypedPrefix = true;
+ $this->bGuidPrefix = true;
+
+ $this->sTimeOffset = '0';
+
+ $this->iWriteOnTimeoutOnly = 0;
+ $this->bWriteOnErrorOnly = false;
+ $this->bWriteOnPhpErrorOnly = false;
+ $this->bFlushCache = false;
+ $this->aCache = array();
+
+ $this->aPrefixes = array(
+ \MailSo\Log\Enumerations\Type::INFO => '[DATA]',
+ \MailSo\Log\Enumerations\Type::SECURE => '[SECURE]',
+ \MailSo\Log\Enumerations\Type::NOTE => '[NOTE]',
+ \MailSo\Log\Enumerations\Type::TIME => '[TIME]',
+ \MailSo\Log\Enumerations\Type::TIME_DELTA => '[TIME]',
+ \MailSo\Log\Enumerations\Type::MEMORY => '[MEMORY]',
+ \MailSo\Log\Enumerations\Type::NOTICE => '[NOTICE]',
+ \MailSo\Log\Enumerations\Type::WARNING => '[WARNING]',
+ \MailSo\Log\Enumerations\Type::ERROR => '[ERROR]',
+
+ \MailSo\Log\Enumerations\Type::NOTICE_PHP => '[NOTICE]',
+ \MailSo\Log\Enumerations\Type::WARNING_PHP => '[WARNING]',
+ \MailSo\Log\Enumerations\Type::ERROR_PHP => '[ERROR]',
+ );
+ }
+
+ /**
+ * @param string $sTimeOffset
+ *
+ * @return \MailSo\Log\Driver
+ */
+ public function SetTimeOffset($sTimeOffset)
+ {
+ $this->sTimeOffset = (string) $sTimeOffset;
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Log\Driver
+ */
+ public function DisableGuidPrefix()
+ {
+ $this->bGuidPrefix = false;
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Log\Driver
+ */
+ public function DisableTimePrefix()
+ {
+ $this->bTimePrefix = false;
+ return $this;
+ }
+
+ /**
+ * @param bool $bValue
+ *
+ * @return \MailSo\Log\Driver
+ */
+ public function WriteOnErrorOnly($bValue)
+ {
+ $this->bWriteOnErrorOnly = !!$bValue;
+ return $this;
+ }
+
+ /**
+ * @param bool $bValue
+ *
+ * @return \MailSo\Log\Driver
+ */
+ public function WriteOnPhpErrorOnly($bValue)
+ {
+ $this->bWriteOnPhpErrorOnly = !!$bValue;
+ return $this;
+ }
+
+ /**
+ * @param int $iTimeout
+ *
+ * @return \MailSo\Log\Driver
+ */
+ public function WriteOnTimeoutOnly($iTimeout)
+ {
+ $this->iWriteOnTimeoutOnly = (int) $iTimeout;
+ if (0 > $this->iWriteOnTimeoutOnly)
+ {
+ $this->iWriteOnTimeoutOnly = 0;
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Log\Driver
+ */
+ public function DisableTypedPrefix()
+ {
+ $this->bTypedPrefix = false;
+ return $this;
+ }
+
+ /**
+ * @param string|array $mDesc
+ * @return bool
+ */
+ abstract protected function writeImplementation($mDesc);
+
+ /**
+ * @return bool
+ */
+ protected function writeEmptyLineImplementation()
+ {
+ return $this->writeImplementation('');
+ }
+
+ /**
+ * @param string $sTimePrefix
+ * @param string $sDesc
+ * @param int $iType = \MailSo\Log\Enumerations\Type::INFO
+ * @param array $sName = ''
+ *
+ * @return string
+ */
+ protected function loggerLineImplementation($sTimePrefix, $sDesc,
+ $iType = \MailSo\Log\Enumerations\Type::INFO, $sName = '')
+ {
+ return \ltrim(
+ ($this->bTimePrefix ? '['.$sTimePrefix.']' : '').
+ ($this->bGuidPrefix ? '['.\MailSo\Log\Logger::Guid().']' : '').
+ ($this->bTypedPrefix ? ' '.$this->getTypedPrefix($iType, $sName) : '')
+ ).$sDesc;
+ }
+
+ /**
+ * @return bool
+ */
+ protected function clearImplementation()
+ {
+ return true;
+ }
+
+ /**
+ * @return string
+ */
+ protected function getTimeWithMicroSec()
+ {
+ $aMicroTimeItems = \explode(' ', \microtime());
+ return \MailSo\Log\Logger::DateHelper($this->sDatePattern, $this->sTimeOffset, $aMicroTimeItems[1]).'.'.
+ \str_pad((int) ($aMicroTimeItems[0] * 1000), 3, '0', STR_PAD_LEFT);
+ }
+
+ /**
+ * @param int $iType
+ * @param string $sName = ''
+ *
+ * @return string
+ */
+ protected function getTypedPrefix($iType, $sName = '')
+ {
+ $sName = 0 < \strlen($sName) ? $sName : $this->sName;
+ return isset($this->aPrefixes[$iType]) ? $sName.$this->aPrefixes[$iType].': ' : '';
+ }
+
+ /**
+ * @param string|array $mDesc
+ * @param bool $bDiplayCrLf = false
+ *
+ * @return string
+ */
+ protected function localWriteImplementation($mDesc, $bDiplayCrLf = false)
+ {
+ if ($bDiplayCrLf)
+ {
+ if (\is_array($mDesc))
+ {
+ foreach ($mDesc as &$sLine)
+ {
+ $sLine = \strtr($sLine, array("\r" => '\r', "\n" => '\n'.$this->sNewLine));
+ $sLine = \rtrim($sLine);
+ }
+ }
+ else
+ {
+ $mDesc = \strtr($mDesc, array("\r" => '\r', "\n" => '\n'.$this->sNewLine));
+ $mDesc = \rtrim($mDesc);
+ }
+ }
+
+ return $this->writeImplementation($mDesc);
+ }
+
+ /**
+ * @final
+ * @param string $sDesc
+ * @param int $iType = \MailSo\Log\Enumerations\Type::INFO
+ * @param string $sName = ''
+ * @param bool $bDiplayCrLf = false
+ *
+ * @return bool
+ */
+ final public function Write($sDesc, $iType = \MailSo\Log\Enumerations\Type::INFO, $sName = '', $bDiplayCrLf = false)
+ {
+ $bResult = true;
+ if (!$this->bFlushCache && ($this->bWriteOnErrorOnly || $this->bWriteOnPhpErrorOnly || 0 < $this->iWriteOnTimeoutOnly))
+ {
+ $bErrorPhp = false;
+
+ $bError = $this->bWriteOnErrorOnly && \in_array($iType, array(
+ \MailSo\Log\Enumerations\Type::NOTICE,
+ \MailSo\Log\Enumerations\Type::NOTICE_PHP,
+ \MailSo\Log\Enumerations\Type::WARNING,
+ \MailSo\Log\Enumerations\Type::WARNING_PHP,
+ \MailSo\Log\Enumerations\Type::ERROR,
+ \MailSo\Log\Enumerations\Type::ERROR_PHP
+ ));
+
+ if (!$bError)
+ {
+ $bErrorPhp = $this->bWriteOnPhpErrorOnly && \in_array($iType, array(
+ \MailSo\Log\Enumerations\Type::NOTICE_PHP,
+ \MailSo\Log\Enumerations\Type::WARNING_PHP,
+ \MailSo\Log\Enumerations\Type::ERROR_PHP
+ ));
+ }
+
+ if ($bError || $bErrorPhp)
+ {
+ $sFlush = '--- FlushLogCache: '.($bError ? 'WriteOnErrorOnly' : 'WriteOnPhpErrorOnly');
+ if (isset($this->aCache[0]) && empty($this->aCache[0]))
+ {
+ $this->aCache[0] = $sFlush;
+ \array_unshift($this->aCache, '');
+ }
+ else
+ {
+ \array_unshift($this->aCache, $sFlush);
+ }
+
+ $this->aCache[] = '--- FlushLogCache: Trigger';
+ $this->aCache[] = $this->loggerLineImplementation($this->getTimeWithMicroSec(), $sDesc, $iType, $sName);
+
+ $this->bFlushCache = true;
+ $bResult = $this->localWriteImplementation($this->aCache, $bDiplayCrLf);
+ $this->aCache = array();
+ }
+ else if (0 < $this->iWriteOnTimeoutOnly && \time() - APP_START_TIME > $this->iWriteOnTimeoutOnly)
+ {
+ $sFlush = '--- FlushLogCache: WriteOnTimeoutOnly ['.(\time() - APP_START_TIME).'sec]';
+ if (isset($this->aCache[0]) && empty($this->aCache[0]))
+ {
+ $this->aCache[0] = $sFlush;
+ \array_unshift($this->aCache, '');
+ }
+ else
+ {
+ \array_unshift($this->aCache, $sFlush);
+ }
+
+ $this->aCache[] = '--- FlushLogCache: Trigger';
+ $this->aCache[] = $this->loggerLineImplementation($this->getTimeWithMicroSec(), $sDesc, $iType, $sName);
+
+ $this->bFlushCache = true;
+ $bResult = $this->localWriteImplementation($this->aCache, $bDiplayCrLf);
+ $this->aCache = array();
+ }
+ else
+ {
+ $this->aCache[] = $this->loggerLineImplementation($this->getTimeWithMicroSec(), $sDesc, $iType, $sName);
+ }
+ }
+ else
+ {
+ $bResult = $this->localWriteImplementation(
+ $this->loggerLineImplementation($this->getTimeWithMicroSec(), $sDesc, $iType, $sName), $bDiplayCrLf);
+ }
+
+ return $bResult;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetNewLine()
+ {
+ return $this->sNewLine;
+ }
+
+ /**
+ * @final
+ * @return bool
+ */
+ final public function Clear()
+ {
+ return $this->clearImplementation();
+ }
+
+ /**
+ * @final
+ * @return void
+ */
+ final public function WriteEmptyLine()
+ {
+ if (!$this->bFlushCache && ($this->bWriteOnErrorOnly || $this->bWriteOnPhpErrorOnly || 0 < $this->iWriteOnTimeoutOnly))
+ {
+ $this->aCache[] = '';
+ }
+ else
+ {
+ $this->writeEmptyLineImplementation();
+ }
+ }
+}
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Log/Drivers/Callback.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Drivers/Callback.php
similarity index 94%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Log/Drivers/Callback.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Drivers/Callback.php
index 021d7e82b0409ed5f19643338f5172e047aa5556..46e8789334536f719f3206dc82324644512531c2 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Log/Drivers/Callback.php
+++ b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Drivers/Callback.php
@@ -1,83 +1,83 @@
-fWriteCallback = \is_callable($fWriteCallback) ? $fWriteCallback : null;
- $this->fClearCallback = \is_callable($fClearCallback) ? $fClearCallback : null;
- }
-
- /**
- * @param mixed $fWriteCallback
- * @param mixed $fClearCallback = null
- *
- * @return \MailSo\Log\Drivers\Callback
- */
- public static function NewInstance($fWriteCallback, $fClearCallback = null)
- {
- return new self($fWriteCallback, $fClearCallback);
- }
-
- /**
- * @param string|array $mDesc
- *
- * @return bool
- */
- protected function writeImplementation($mDesc)
- {
- if ($this->fWriteCallback)
- {
- \call_user_func_array($this->fWriteCallback, array($mDesc));
- }
-
- return true;
- }
-
- /**
- * @return bool
- */
- protected function clearImplementation()
- {
- if ($this->fClearCallback)
- {
- \call_user_func($this->fClearCallback);
- }
-
- return true;
- }
-}
+fWriteCallback = \is_callable($fWriteCallback) ? $fWriteCallback : null;
+ $this->fClearCallback = \is_callable($fClearCallback) ? $fClearCallback : null;
+ }
+
+ /**
+ * @param mixed $fWriteCallback
+ * @param mixed $fClearCallback = null
+ *
+ * @return \MailSo\Log\Drivers\Callback
+ */
+ public static function NewInstance($fWriteCallback, $fClearCallback = null)
+ {
+ return new self($fWriteCallback, $fClearCallback);
+ }
+
+ /**
+ * @param string|array $mDesc
+ *
+ * @return bool
+ */
+ protected function writeImplementation($mDesc)
+ {
+ if ($this->fWriteCallback)
+ {
+ \call_user_func_array($this->fWriteCallback, array($mDesc));
+ }
+
+ return true;
+ }
+
+ /**
+ * @return bool
+ */
+ protected function clearImplementation()
+ {
+ if ($this->fClearCallback)
+ {
+ \call_user_func($this->fClearCallback);
+ }
+
+ return true;
+ }
+}
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Log/Drivers/File.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Drivers/File.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Log/Drivers/File.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Drivers/File.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Log/Drivers/Inline.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Drivers/Inline.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Log/Drivers/Inline.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Drivers/Inline.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Log/Drivers/Syslog.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Drivers/Syslog.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Log/Drivers/Syslog.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Drivers/Syslog.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Log/Enumerations/Type.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Enumerations/Type.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Log/Enumerations/Type.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Enumerations/Type.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Log/Logger.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Logger.php
similarity index 95%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Log/Logger.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Logger.php
index cb5dea68cdf06480cf115dce7be2a6080de7ee67..82cbf5418961c0de4f64a06dd318e43425df631c 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Log/Logger.php
+++ b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Log/Logger.php
@@ -1,431 +1,431 @@
-bUsed = false;
- $this->aForbiddenTypes = array();
- $this->aSecretWords = array();
- $this->bShowSecter = false;
- $this->bHideErrorNotices = false;
-
- if ($bRegPhpErrorHandler)
- {
- \set_error_handler(array(&$this, '__phpErrorHandler'));
- }
-
- \register_shutdown_function(array(&$this, '__loggerShutDown'));
- }
-
- /**
- * @param bool $bRegPhpErrorHandler = false
- *
- * @return \MailSo\Log\Logger
- */
- public static function NewInstance($bRegPhpErrorHandler = false)
- {
- return new self($bRegPhpErrorHandler);
- }
-
- /**
- * @staticvar \MailSo\Log\Logger $oInstance;
- *
- * @return \MailSo\Log\Logger
- */
- public static function SingletonInstance()
- {
- static $oInstance = null;
- if (null === $oInstance)
- {
- $oInstance = self::NewInstance();
- }
-
- return $oInstance;
- }
-
- /**
- * @param string $sFormat
- * @param string $sTimeOffset = '0'
- * @param int $iTimestamp = 0
- *
- * @return string
- */
- public static function DateHelper($sFormat, $sTimeOffset = '0', $iTimestamp = null)
- {
- $iTimestamp = null === $iTimestamp ? \time() : (int) $iTimestamp;
- return \gmdate($sFormat, $iTimestamp + \MailSo\Base\DateTimeHelper::TimeToSec((string) $sTimeOffset));
- }
-
- /**
- * @return bool
- */
- public static function IsSystemEnabled()
- {
- return !!(\MailSo\Config::$SystemLogger instanceof \MailSo\Log\Logger);
- }
-
- /**
- * @param mixed $mData
- * @param int $iType = \MailSo\Log\Enumerations\Type::INFO
- */
- public static function SystemLog($mData, $iType = \MailSo\Log\Enumerations\Type::INFO)
- {
- if (\MailSo\Config::$SystemLogger instanceof \MailSo\Log\Logger)
- {
- \MailSo\Config::$SystemLogger->WriteMixed($mData, $iType);
- }
- }
-
- /**
- * @staticvar string $sCache;
- *
- * @return string
- */
- public static function Guid()
- {
- static $sCache = null;
- if (null === $sCache)
- {
- $sCache = \substr(\MailSo\Base\Utils::Md5Rand(), -8);
- }
-
- return $sCache;
- }
-
- /**
- * @return bool
- */
- public function Ping()
- {
- return true;
- }
-
- /**
- * @return bool
- */
- public function IsEnabled()
- {
- return 0 < $this->Count();
- }
-
- /**
- * @param string $sWord
- *
- * @return bool
- */
- public function AddSecret($sWord)
- {
- if (\is_string($sWord) && 0 < \strlen(\trim($sWord)))
- {
- $this->aSecretWords[] = $sWord;
- $this->aSecretWords = \array_unique($this->aSecretWords);
- }
- }
-
- /**
- * @param bool $bShow
- *
- * @return \MailSo\Log\Logger
- */
- public function SetShowSecter($bShow)
- {
- $this->bShowSecter = !!$bShow;
- return $this;
- }
-
- /**
- * @param bool $bValue
- *
- * @return \MailSo\Log\Logger
- */
- public function HideErrorNotices($bValue)
- {
- $this->bHideErrorNotices = !!$bValue;
- return $this;
- }
-
- /**
- * @return bool
- */
- public function IsShowSecter()
- {
- return $this->bShowSecter;
- }
-
- /**
- * @param int $iType
- *
- * @return \MailSo\Log\Logger
- */
- public function AddForbiddenType($iType)
- {
- $this->aForbiddenTypes[$iType] = true;
-
- return $this;
- }
-
- /**
- * @param int $iType
- *
- * @return \MailSo\Log\Logger
- */
- public function RemoveForbiddenType($iType)
- {
- $this->aForbiddenTypes[$iType] = false;
- return $this;
- }
-
- /**
- * @param int $iErrNo
- * @param string $sErrStr
- * @param string $sErrFile
- * @param int $iErrLine
- *
- * @return bool
- */
- public function __phpErrorHandler($iErrNo, $sErrStr, $sErrFile, $iErrLine)
- {
- $iType = \MailSo\Log\Enumerations\Type::NOTICE_PHP;
- switch ($iErrNo)
- {
- case E_USER_ERROR:
- $iType = \MailSo\Log\Enumerations\Type::ERROR_PHP;
- break;
- case E_USER_WARNING:
- $iType = \MailSo\Log\Enumerations\Type::WARNING_PHP;
- break;
- }
-
- $this->Write($sErrFile.' [line:'.$iErrLine.', code:'.$iErrNo.']', $iType, 'PHP');
- $this->Write('Error: '.$sErrStr, $iType, 'PHP');
-
- return !!(\MailSo\Log\Enumerations\Type::NOTICE === $iType && $this->bHideErrorNotices);
- }
-
- /**
- * @return void
- */
- public function __loggerShutDown()
- {
- if ($this->bUsed)
- {
- $aStatistic = \MailSo\Base\Loader::Statistic();
- if (\is_array($aStatistic))
- {
- if (isset($aStatistic['php']['memory_get_peak_usage']))
- {
- $this->Write('Memory peak usage: '.$aStatistic['php']['memory_get_peak_usage'],
- \MailSo\Log\Enumerations\Type::MEMORY);
- }
-
- if (isset($aStatistic['time']))
- {
- $this->Write('Time delta: '.$aStatistic['time'], \MailSo\Log\Enumerations\Type::TIME_DELTA);
- }
- }
- }
- }
-
- /**
- * @return bool
- */
- public function WriteEmptyLine()
- {
- $iResult = 1;
-
- $aLoggers =& $this->GetAsArray();
- foreach ($aLoggers as /* @var $oLogger \MailSo\Log\Driver */ &$oLogger)
- {
- $iResult &= $oLogger->WriteEmptyLine();
- }
-
- return (bool) $iResult;
- }
-
- /**
- * @param string $sDesc
- * @param int $iType = \MailSo\Log\Enumerations\Type::INFO
- * @param string $sName = ''
- * @param bool $bSearchSecretWords = true
- * @param bool $bDiplayCrLf = false
- *
- * @return bool
- */
- public function Write($sDesc, $iType = \MailSo\Log\Enumerations\Type::INFO,
- $sName = '', $bSearchSecretWords = true, $bDiplayCrLf = false)
- {
- if (isset($this->aForbiddenTypes[$iType]) && true === $this->aForbiddenTypes[$iType])
- {
- return true;
- }
-
- $this->bUsed = true;
-
- $oLogger = null;
- $aLoggers = array();
- $iResult = 1;
-
- if ($bSearchSecretWords && !$this->bShowSecter && 0 < \count($this->aSecretWords))
- {
- $sDesc = \str_replace($this->aSecretWords, '*******', $sDesc);
- }
-
- $aLoggers =& $this->GetAsArray();
- foreach ($aLoggers as /* @var $oLogger \MailSo\Log\Driver */ $oLogger)
- {
- $iResult &= $oLogger->Write($sDesc, $iType, $sName, $bDiplayCrLf);
- }
-
- return (bool) $iResult;
- }
-
- /**
- * @param mixed $oValue
- * @param int $iType = \MailSo\Log\Enumerations\Type::INFO
- * @param string $sName = ''
- * @param bool $bSearchSecretWords = false
- * @param bool $bDiplayCrLf = false
- *
- * @return bool
- */
- public function WriteDump($oValue, $iType = \MailSo\Log\Enumerations\Type::INFO, $sName = '',
- $bSearchSecretWords = false, $bDiplayCrLf = false)
- {
- return $this->Write(\print_r($oValue, true), $iType, $sName, $bSearchSecretWords, $bDiplayCrLf);
- }
-
- /**
- * @param \Exception $oException
- * @param int $iType = \MailSo\Log\Enumerations\Type::NOTICE
- * @param string $sName = ''
- * @param bool $bSearchSecretWords = true
- * @param bool $bDiplayCrLf = false
- *
- * @return bool
- */
- public function WriteException($oException, $iType = \MailSo\Log\Enumerations\Type::NOTICE, $sName = '',
- $bSearchSecretWords = true, $bDiplayCrLf = false)
- {
- if ($oException instanceof \Exception)
- {
- if (isset($oException->__LOGINNED__))
- {
- return true;
- }
-
- $oException->__LOGINNED__ = true;
-
- return $this->Write((string) $oException, $iType, $sName, $bSearchSecretWords, $bDiplayCrLf);
- }
-
- return false;
- }
-
- /**
- * @param \Exception $oException
- * @param int $iType = \MailSo\Log\Enumerations\Type::NOTICE
- * @param string $sName = ''
- * @param bool $bSearchSecretWords = true
- * @param bool $bDiplayCrLf = false
- *
- * @return bool
- */
- public function WriteExceptionShort($oException, $iType = \MailSo\Log\Enumerations\Type::NOTICE, $sName = '',
- $bSearchSecretWords = true, $bDiplayCrLf = false)
- {
- if ($oException instanceof \Exception)
- {
- if (isset($oException->__LOGINNED__))
- {
- return true;
- }
-
- $oException->__LOGINNED__ = true;
-
- return $this->Write($oException->getMessage(), $iType, $sName, $bSearchSecretWords, $bDiplayCrLf);
- }
-
- return false;
- }
-
- /**
- * @param mixed $mData
- * @param int $iType = \MailSo\Log\Enumerations\Type::NOTICE
- * @param string $sName = ''
- * @param bool $bSearchSecretWords = true
- * @param bool $bDiplayCrLf = false
- *
- * @return bool
- */
- public function WriteMixed($mData, $iType = null, $sName = '',
- $bSearchSecretWords = true, $bDiplayCrLf = false)
- {
- $iType = null === $iType ? \MailSo\Log\Enumerations\Type::INFO : $iType;
- if (\is_array($mData) || \is_object($mData))
- {
- if ($mData instanceof \Exception)
- {
- $iType = null === $iType ? \MailSo\Log\Enumerations\Type::NOTICE : $iType;
- return $this->WriteException($mData, $iType, $sName, $bSearchSecretWords, $bDiplayCrLf);
- }
- else
- {
- return $this->WriteDump($mData, $iType, $sName, $bSearchSecretWords, $bDiplayCrLf);
- }
- }
- else
- {
- return $this->Write($mData, $iType, $sName, $bSearchSecretWords, $bDiplayCrLf);
- }
-
- return false;
- }
-}
+bUsed = false;
+ $this->aForbiddenTypes = array();
+ $this->aSecretWords = array();
+ $this->bShowSecter = false;
+ $this->bHideErrorNotices = false;
+
+ if ($bRegPhpErrorHandler)
+ {
+ \set_error_handler(array(&$this, '__phpErrorHandler'));
+ }
+
+ \register_shutdown_function(array(&$this, '__loggerShutDown'));
+ }
+
+ /**
+ * @param bool $bRegPhpErrorHandler = false
+ *
+ * @return \MailSo\Log\Logger
+ */
+ public static function NewInstance($bRegPhpErrorHandler = false)
+ {
+ return new self($bRegPhpErrorHandler);
+ }
+
+ /**
+ * @staticvar \MailSo\Log\Logger $oInstance;
+ *
+ * @return \MailSo\Log\Logger
+ */
+ public static function SingletonInstance()
+ {
+ static $oInstance = null;
+ if (null === $oInstance)
+ {
+ $oInstance = self::NewInstance();
+ }
+
+ return $oInstance;
+ }
+
+ /**
+ * @param string $sFormat
+ * @param string $sTimeOffset = '0'
+ * @param int $iTimestamp = 0
+ *
+ * @return string
+ */
+ public static function DateHelper($sFormat, $sTimeOffset = '0', $iTimestamp = null)
+ {
+ $iTimestamp = null === $iTimestamp ? \time() : (int) $iTimestamp;
+ return \gmdate($sFormat, $iTimestamp + \MailSo\Base\DateTimeHelper::TimeToSec((string) $sTimeOffset));
+ }
+
+ /**
+ * @return bool
+ */
+ public static function IsSystemEnabled()
+ {
+ return !!(\MailSo\Config::$SystemLogger instanceof \MailSo\Log\Logger);
+ }
+
+ /**
+ * @param mixed $mData
+ * @param int $iType = \MailSo\Log\Enumerations\Type::INFO
+ */
+ public static function SystemLog($mData, $iType = \MailSo\Log\Enumerations\Type::INFO)
+ {
+ if (\MailSo\Config::$SystemLogger instanceof \MailSo\Log\Logger)
+ {
+ \MailSo\Config::$SystemLogger->WriteMixed($mData, $iType);
+ }
+ }
+
+ /**
+ * @staticvar string $sCache;
+ *
+ * @return string
+ */
+ public static function Guid()
+ {
+ static $sCache = null;
+ if (null === $sCache)
+ {
+ $sCache = \substr(\MailSo\Base\Utils::Md5Rand(), -8);
+ }
+
+ return $sCache;
+ }
+
+ /**
+ * @return bool
+ */
+ public function Ping()
+ {
+ return true;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsEnabled()
+ {
+ return 0 < $this->Count();
+ }
+
+ /**
+ * @param string $sWord
+ *
+ * @return bool
+ */
+ public function AddSecret($sWord)
+ {
+ if (\is_string($sWord) && 0 < \strlen(\trim($sWord)))
+ {
+ $this->aSecretWords[] = $sWord;
+ $this->aSecretWords = \array_unique($this->aSecretWords);
+ }
+ }
+
+ /**
+ * @param bool $bShow
+ *
+ * @return \MailSo\Log\Logger
+ */
+ public function SetShowSecter($bShow)
+ {
+ $this->bShowSecter = !!$bShow;
+ return $this;
+ }
+
+ /**
+ * @param bool $bValue
+ *
+ * @return \MailSo\Log\Logger
+ */
+ public function HideErrorNotices($bValue)
+ {
+ $this->bHideErrorNotices = !!$bValue;
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsShowSecter()
+ {
+ return $this->bShowSecter;
+ }
+
+ /**
+ * @param int $iType
+ *
+ * @return \MailSo\Log\Logger
+ */
+ public function AddForbiddenType($iType)
+ {
+ $this->aForbiddenTypes[$iType] = true;
+
+ return $this;
+ }
+
+ /**
+ * @param int $iType
+ *
+ * @return \MailSo\Log\Logger
+ */
+ public function RemoveForbiddenType($iType)
+ {
+ $this->aForbiddenTypes[$iType] = false;
+ return $this;
+ }
+
+ /**
+ * @param int $iErrNo
+ * @param string $sErrStr
+ * @param string $sErrFile
+ * @param int $iErrLine
+ *
+ * @return bool
+ */
+ public function __phpErrorHandler($iErrNo, $sErrStr, $sErrFile, $iErrLine)
+ {
+ $iType = \MailSo\Log\Enumerations\Type::NOTICE_PHP;
+ switch ($iErrNo)
+ {
+ case E_USER_ERROR:
+ $iType = \MailSo\Log\Enumerations\Type::ERROR_PHP;
+ break;
+ case E_USER_WARNING:
+ $iType = \MailSo\Log\Enumerations\Type::WARNING_PHP;
+ break;
+ }
+
+ $this->Write($sErrFile.' [line:'.$iErrLine.', code:'.$iErrNo.']', $iType, 'PHP');
+ $this->Write('Error: '.$sErrStr, $iType, 'PHP');
+
+ return !!(\MailSo\Log\Enumerations\Type::NOTICE === $iType && $this->bHideErrorNotices);
+ }
+
+ /**
+ * @return void
+ */
+ public function __loggerShutDown()
+ {
+ if ($this->bUsed)
+ {
+ $aStatistic = \MailSo\Base\Loader::Statistic();
+ if (\is_array($aStatistic))
+ {
+ if (isset($aStatistic['php']['memory_get_peak_usage']))
+ {
+ $this->Write('Memory peak usage: '.$aStatistic['php']['memory_get_peak_usage'],
+ \MailSo\Log\Enumerations\Type::MEMORY);
+ }
+
+ if (isset($aStatistic['time']))
+ {
+ $this->Write('Time delta: '.$aStatistic['time'], \MailSo\Log\Enumerations\Type::TIME_DELTA);
+ }
+ }
+ }
+ }
+
+ /**
+ * @return bool
+ */
+ public function WriteEmptyLine()
+ {
+ $iResult = 1;
+
+ $aLoggers =& $this->GetAsArray();
+ foreach ($aLoggers as /* @var $oLogger \MailSo\Log\Driver */ &$oLogger)
+ {
+ $iResult &= $oLogger->WriteEmptyLine();
+ }
+
+ return (bool) $iResult;
+ }
+
+ /**
+ * @param string $sDesc
+ * @param int $iType = \MailSo\Log\Enumerations\Type::INFO
+ * @param string $sName = ''
+ * @param bool $bSearchSecretWords = true
+ * @param bool $bDiplayCrLf = false
+ *
+ * @return bool
+ */
+ public function Write($sDesc, $iType = \MailSo\Log\Enumerations\Type::INFO,
+ $sName = '', $bSearchSecretWords = true, $bDiplayCrLf = false)
+ {
+ if (isset($this->aForbiddenTypes[$iType]) && true === $this->aForbiddenTypes[$iType])
+ {
+ return true;
+ }
+
+ $this->bUsed = true;
+
+ $oLogger = null;
+ $aLoggers = array();
+ $iResult = 1;
+
+ if ($bSearchSecretWords && !$this->bShowSecter && 0 < \count($this->aSecretWords))
+ {
+ $sDesc = \str_replace($this->aSecretWords, '*******', $sDesc);
+ }
+
+ $aLoggers =& $this->GetAsArray();
+ foreach ($aLoggers as /* @var $oLogger \MailSo\Log\Driver */ $oLogger)
+ {
+ $iResult &= $oLogger->Write($sDesc, $iType, $sName, $bDiplayCrLf);
+ }
+
+ return (bool) $iResult;
+ }
+
+ /**
+ * @param mixed $oValue
+ * @param int $iType = \MailSo\Log\Enumerations\Type::INFO
+ * @param string $sName = ''
+ * @param bool $bSearchSecretWords = false
+ * @param bool $bDiplayCrLf = false
+ *
+ * @return bool
+ */
+ public function WriteDump($oValue, $iType = \MailSo\Log\Enumerations\Type::INFO, $sName = '',
+ $bSearchSecretWords = false, $bDiplayCrLf = false)
+ {
+ return $this->Write(\print_r($oValue, true), $iType, $sName, $bSearchSecretWords, $bDiplayCrLf);
+ }
+
+ /**
+ * @param \Exception $oException
+ * @param int $iType = \MailSo\Log\Enumerations\Type::NOTICE
+ * @param string $sName = ''
+ * @param bool $bSearchSecretWords = true
+ * @param bool $bDiplayCrLf = false
+ *
+ * @return bool
+ */
+ public function WriteException($oException, $iType = \MailSo\Log\Enumerations\Type::NOTICE, $sName = '',
+ $bSearchSecretWords = true, $bDiplayCrLf = false)
+ {
+ if ($oException instanceof \Exception)
+ {
+ if (isset($oException->__LOGINNED__))
+ {
+ return true;
+ }
+
+ $oException->__LOGINNED__ = true;
+
+ return $this->Write((string) $oException, $iType, $sName, $bSearchSecretWords, $bDiplayCrLf);
+ }
+
+ return false;
+ }
+
+ /**
+ * @param \Exception $oException
+ * @param int $iType = \MailSo\Log\Enumerations\Type::NOTICE
+ * @param string $sName = ''
+ * @param bool $bSearchSecretWords = true
+ * @param bool $bDiplayCrLf = false
+ *
+ * @return bool
+ */
+ public function WriteExceptionShort($oException, $iType = \MailSo\Log\Enumerations\Type::NOTICE, $sName = '',
+ $bSearchSecretWords = true, $bDiplayCrLf = false)
+ {
+ if ($oException instanceof \Exception)
+ {
+ if (isset($oException->__LOGINNED__))
+ {
+ return true;
+ }
+
+ $oException->__LOGINNED__ = true;
+
+ return $this->Write($oException->getMessage(), $iType, $sName, $bSearchSecretWords, $bDiplayCrLf);
+ }
+
+ return false;
+ }
+
+ /**
+ * @param mixed $mData
+ * @param int $iType = \MailSo\Log\Enumerations\Type::NOTICE
+ * @param string $sName = ''
+ * @param bool $bSearchSecretWords = true
+ * @param bool $bDiplayCrLf = false
+ *
+ * @return bool
+ */
+ public function WriteMixed($mData, $iType = null, $sName = '',
+ $bSearchSecretWords = true, $bDiplayCrLf = false)
+ {
+ $iType = null === $iType ? \MailSo\Log\Enumerations\Type::INFO : $iType;
+ if (\is_array($mData) || \is_object($mData))
+ {
+ if ($mData instanceof \Exception)
+ {
+ $iType = null === $iType ? \MailSo\Log\Enumerations\Type::NOTICE : $iType;
+ return $this->WriteException($mData, $iType, $sName, $bSearchSecretWords, $bDiplayCrLf);
+ }
+ else
+ {
+ return $this->WriteDump($mData, $iType, $sName, $bSearchSecretWords, $bDiplayCrLf);
+ }
+ }
+ else
+ {
+ return $this->Write($mData, $iType, $sName, $bSearchSecretWords, $bDiplayCrLf);
+ }
+
+ return false;
+ }
+}
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mail/Attachment.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Attachment.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mail/Attachment.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Attachment.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mail/AttachmentCollection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/AttachmentCollection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mail/AttachmentCollection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/AttachmentCollection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mail/Exceptions/Exception.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Exceptions/Exception.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mail/Exceptions/Exception.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Exceptions/Exception.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mail/Exceptions/NonEmptyFolder.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Exceptions/NonEmptyFolder.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mail/Exceptions/NonEmptyFolder.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Exceptions/NonEmptyFolder.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mail/Exceptions/RuntimeException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Exceptions/RuntimeException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mail/Exceptions/RuntimeException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Exceptions/RuntimeException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mail/Folder.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Folder.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mail/Folder.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Folder.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mail/FolderCollection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/FolderCollection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mail/FolderCollection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/FolderCollection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mail/MailClient.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/MailClient.php
similarity index 96%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mail/MailClient.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/MailClient.php
index 1e95e251f7a1e14e6fbd23c05ddc0f05ed6f1522..ff0500faf5ad0c911f50f28e8c199177bc9015d3 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mail/MailClient.php
+++ b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/MailClient.php
@@ -1,2677 +1,2677 @@
-oLogger = null;
-
- $this->oImapClient = \MailSo\Imap\ImapClient::NewInstance();
- $this->oImapClient->SetTimeOuts(10, \MailSo\Config::$ImapTimeout);
- }
-
- /**
- * @return \MailSo\Mail\MailClient
- */
- public static function NewInstance()
- {
- return new self();
- }
-
- /**
- * @return \MailSo\Imap\ImapClient
- */
- public function ImapClient()
- {
- return $this->oImapClient;
- }
-
- /**
- * @param string $sServerName
- * @param int $iPort = 143
- * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT
- * @param bool $bVerifySsl = false
- *
- * @return \MailSo\Mail\MailClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function Connect($sServerName, $iPort = 143,
- $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, $bVerifySsl = false)
- {
- $this->oImapClient->Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl);
- return $this;
- }
-
- /**
- * @param string $sLogin
- * @param string $sPassword
- * @param string $sProxyAuthUser = ''
- * @param bool $bUseAuthPlainIfSupported = true
- * @param bool $bUseAuthCramMd5IfSupported = true
- *
- * @return \MailSo\Mail\MailClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\LoginException
- */
- public function Login($sLogin, $sPassword, $sProxyAuthUser = '',
- $bUseAuthPlainIfSupported = true, $bUseAuthCramMd5IfSupported = true)
- {
- $this->oImapClient->Login($sLogin, $sPassword, $sProxyAuthUser, $bUseAuthPlainIfSupported, $bUseAuthCramMd5IfSupported);
- return $this;
- }
-
- /**
- * @param string $sXOAuth2Token
- *
- * @return \MailSo\Mail\MailClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\LoginException
- */
- public function LoginWithXOauth2($sXOAuth2Token)
- {
- $this->oImapClient->LoginWithXOauth2($sXOAuth2Token);
- return $this;
- }
-
- /**
- * @return \MailSo\Mail\MailClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- */
- public function Logout()
- {
- $this->oImapClient->Logout();
- return $this;
- }
-
- /**
- * @return \MailSo\Mail\MailClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- */
- public function Disconnect()
- {
- $this->oImapClient->Disconnect();
- return $this;
- }
-
- /**
- * @return \MailSo\Mail\MailClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- */
- public function LogoutAndDisconnect()
- {
- return $this->Logout()->Disconnect();
- }
-
- /**
- * @return bool
- */
- public function IsConnected()
- {
- return $this->oImapClient->IsConnected();
- }
-
- /**
- * @return bool
- */
- public function IsLoggined()
- {
- return $this->oImapClient->IsLoggined();
- }
-
- /**
- * @return string
- */
- private function getEnvelopeOrHeadersRequestStringForSimpleList()
- {
- return \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array(
- \MailSo\Mime\Enumerations\Header::RETURN_PATH,
- \MailSo\Mime\Enumerations\Header::RECEIVED,
- \MailSo\Mime\Enumerations\Header::MIME_VERSION,
- \MailSo\Mime\Enumerations\Header::FROM_,
- \MailSo\Mime\Enumerations\Header::TO_,
- \MailSo\Mime\Enumerations\Header::CC,
- \MailSo\Mime\Enumerations\Header::SENDER,
- \MailSo\Mime\Enumerations\Header::REPLY_TO,
- \MailSo\Mime\Enumerations\Header::DATE,
- \MailSo\Mime\Enumerations\Header::SUBJECT,
- \MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
- \MailSo\Mime\Enumerations\Header::LIST_UNSUBSCRIBE,
- ), true);
- }
-
- /**
- * @return string
- */
- private function getEnvelopeOrHeadersRequestString()
- {
- if (\MailSo\Config::$MessageAllHeaders)
- {
- return \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK;
- }
-
- return \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array(
- \MailSo\Mime\Enumerations\Header::RETURN_PATH,
- \MailSo\Mime\Enumerations\Header::RECEIVED,
- \MailSo\Mime\Enumerations\Header::MIME_VERSION,
- \MailSo\Mime\Enumerations\Header::MESSAGE_ID,
- \MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
- \MailSo\Mime\Enumerations\Header::FROM_,
- \MailSo\Mime\Enumerations\Header::TO_,
- \MailSo\Mime\Enumerations\Header::CC,
- \MailSo\Mime\Enumerations\Header::BCC,
- \MailSo\Mime\Enumerations\Header::SENDER,
- \MailSo\Mime\Enumerations\Header::REPLY_TO,
- \MailSo\Mime\Enumerations\Header::DELIVERED_TO,
- \MailSo\Mime\Enumerations\Header::IN_REPLY_TO,
- \MailSo\Mime\Enumerations\Header::REFERENCES,
- \MailSo\Mime\Enumerations\Header::DATE,
- \MailSo\Mime\Enumerations\Header::SUBJECT,
- \MailSo\Mime\Enumerations\Header::SENSITIVITY,
- \MailSo\Mime\Enumerations\Header::X_MSMAIL_PRIORITY,
- \MailSo\Mime\Enumerations\Header::IMPORTANCE,
- \MailSo\Mime\Enumerations\Header::X_PRIORITY,
- \MailSo\Mime\Enumerations\Header::X_DRAFT_INFO,
- \MailSo\Mime\Enumerations\Header::RETURN_RECEIPT_TO,
- \MailSo\Mime\Enumerations\Header::DISPOSITION_NOTIFICATION_TO,
- \MailSo\Mime\Enumerations\Header::X_CONFIRM_READING_TO,
- \MailSo\Mime\Enumerations\Header::AUTHENTICATION_RESULTS,
- \MailSo\Mime\Enumerations\Header::X_DKIM_AUTHENTICATION_RESULTS,
- \MailSo\Mime\Enumerations\Header::LIST_UNSUBSCRIBE,
- ), true);
-//
-// return \MailSo\Imap\Enumerations\FetchType::ENVELOPE;
- }
-
- /**
- * @param string $sFolderName
- * @param string $sMessageFlag
- * @param bool $bSetAction = true
- * @param bool $sSkipUnsupportedFlag = false
- * @param array $aCustomUids = null
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- * @throws \MailSo\Mail\Exceptions\Exception
- */
- public function MessageSetFlagToAll($sFolderName, $sMessageFlag, $bSetAction = true, $sSkipUnsupportedFlag = false, $aCustomUids = null)
- {
- $this->oImapClient->FolderSelect($sFolderName);
-
- $oFolderInfo = $this->oImapClient->FolderCurrentInformation();
- if (!$oFolderInfo || !$oFolderInfo->IsFlagSupported($sMessageFlag))
- {
- if (!$sSkipUnsupportedFlag)
- {
- throw new \MailSo\Mail\Exceptions\RuntimeException('Message flag "'.$sMessageFlag.'" is not supported.');
- }
- }
-
- if ($oFolderInfo && 0 < $oFolderInfo->Exists)
- {
- $sStoreAction = $bSetAction
- ? \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT
- : \MailSo\Imap\Enumerations\StoreAction::REMOVE_FLAGS_SILENT
- ;
-
- if (is_array($aCustomUids))
- {
- if (0 < count($aCustomUids))
- {
- $this->oImapClient->MessageStoreFlag(implode(',', $aCustomUids), true, array($sMessageFlag), $sStoreAction);
- }
- }
- else
- {
- $this->oImapClient->MessageStoreFlag('1:*', false, array($sMessageFlag), $sStoreAction);
- }
- }
- }
-
- /**
- * @param string $sFolderName
- * @param array $aIndexRange
- * @param bool $bIndexIsUid
- * @param string $sMessageFlag
- * @param bool $bSetAction = true
- * @param bool $sSkipUnsupportedFlag = false
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- * @throws \MailSo\Mail\Exceptions\Exception
- */
- public function MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid, $sMessageFlag, $bSetAction = true, $sSkipUnsupportedFlag = false)
- {
- $this->oImapClient->FolderSelect($sFolderName);
-
- $oFolderInfo = $this->oImapClient->FolderCurrentInformation();
- if (!$oFolderInfo || !$oFolderInfo->IsFlagSupported($sMessageFlag))
- {
- if (!$sSkipUnsupportedFlag)
- {
- throw new \MailSo\Mail\Exceptions\RuntimeException('Message flag "'.$sMessageFlag.'" is not supported.');
- }
- }
- else
- {
- $sStoreAction = $bSetAction
- ? \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT
- : \MailSo\Imap\Enumerations\StoreAction::REMOVE_FLAGS_SILENT
- ;
-
- $this->oImapClient->MessageStoreFlag(\MailSo\Base\Utils::PrepearFetchSequence($aIndexRange),
- $bIndexIsUid, array($sMessageFlag), $sStoreAction);
- }
- }
-
- /**
- * @param string $sFolderName
- * @param array $aIndexRange
- * @param bool $bIndexIsUid
- * @param bool $bSetAction = true
- * @param bool $sSkipUnsupportedFlag = false
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function MessageSetFlagged($sFolderName, $aIndexRange, $bIndexIsUid, $bSetAction = true, $sSkipUnsupportedFlag = false)
- {
- $this->MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid,
- \MailSo\Imap\Enumerations\MessageFlag::FLAGGED, $bSetAction, $sSkipUnsupportedFlag);
- }
-
- /**
- * @param string $sFolderName
- * @param bool $bSetAction = true
- * @param array $aCustomUids = null
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function MessageSetSeenToAll($sFolderName, $bSetAction = true, $aCustomUids = null)
- {
- $this->MessageSetFlagToAll($sFolderName, \MailSo\Imap\Enumerations\MessageFlag::SEEN, $bSetAction, true, $aCustomUids);
- }
-
- /**
- * @param string $sFolderName
- * @param array $aIndexRange
- * @param bool $bIndexIsUid
- * @param bool $bSetAction = true
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function MessageSetSeen($sFolderName, $aIndexRange, $bIndexIsUid, $bSetAction = true)
- {
- $this->MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid,
- \MailSo\Imap\Enumerations\MessageFlag::SEEN, $bSetAction, true);
- }
-
- /**
- * @param string $sFolderName
- * @param int $iIndex
- * @param bool $bIndexIsUid = true
- * @param \MailSo\Cache\CacheClient $oCacher = null
- * @param int $iBodyTextLimit = null
- *
- * @return \MailSo\Mail\Message|false
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function Message($sFolderName, $iIndex, $bIndexIsUid = true, $oCacher = null, $iBodyTextLimit = null)
- {
- if (!\MailSo\Base\Validator::RangeInt($iIndex, 1))
- {
- throw new \MailSo\Base\Exceptions\InvalidArgumentException();
- }
-
- $this->oImapClient->FolderSelect($sFolderName);
-
- $oBodyStructure = null;
- $oMessage = false;
-
- $aBodyPeekMimeIndexes = array();
- $aSignatureMimeIndexes = array();
-
- $aFetchResponse = $this->oImapClient->Fetch(array(\MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE), $iIndex, $bIndexIsUid);
- if (0 < \count($aFetchResponse) && isset($aFetchResponse[0]))
- {
- $oBodyStructure = $aFetchResponse[0]->GetFetchBodyStructure();
- if ($oBodyStructure)
- {
- $aTextParts = $oBodyStructure->SearchHtmlOrPlainParts();
- if (is_array($aTextParts) && 0 < \count($aTextParts))
- {
- foreach ($aTextParts as $oPart)
- {
- $aBodyPeekMimeIndexes[] = array($oPart->PartID(), $oPart->Size());
- }
- }
-
- $aSignatureParts = $oBodyStructure->SearchByContentType('application/pgp-signature');
- if (is_array($aSignatureParts) && 0 < \count($aSignatureParts))
- {
- foreach ($aSignatureParts as $oPart)
- {
- $aSignatureMimeIndexes[] = $oPart->PartID();
- }
- }
- }
- }
-
- $aFetchItems = array(
- \MailSo\Imap\Enumerations\FetchType::INDEX,
- \MailSo\Imap\Enumerations\FetchType::UID,
- \MailSo\Imap\Enumerations\FetchType::RFC822_SIZE,
- \MailSo\Imap\Enumerations\FetchType::INTERNALDATE,
- \MailSo\Imap\Enumerations\FetchType::FLAGS,
- $this->getEnvelopeOrHeadersRequestString()
- );
-
- if (0 < \count($aBodyPeekMimeIndexes))
- {
- foreach ($aBodyPeekMimeIndexes as $aTextMimeData)
- {
- $sLine = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$aTextMimeData[0].']';
- if (\is_numeric($iBodyTextLimit) && 0 < $iBodyTextLimit && $iBodyTextLimit < $aTextMimeData[1])
- {
- $sLine .= '<0.'.((int) $iBodyTextLimit).'>';
- }
-
- $aFetchItems[] = $sLine;
- }
- }
-
- if (0 < \count($aSignatureMimeIndexes))
- {
- foreach ($aSignatureMimeIndexes as $sTextMimeIndex)
- {
- $aFetchItems[] = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sTextMimeIndex.']';
- }
- }
-
- if (!$oBodyStructure)
- {
- $aFetchItems[] = \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE;
- }
-
- $aFetchResponse = $this->oImapClient->Fetch($aFetchItems, $iIndex, $bIndexIsUid);
- if (0 < \count($aFetchResponse))
- {
- $oMessage = \MailSo\Mail\Message::NewFetchResponseInstance(
- $sFolderName, $aFetchResponse[0], $oBodyStructure);
- }
-
- return $oMessage;
- }
-
- /**
- * @param mixed $mCallback
- * @param string $sFolderName
- * @param int $iIndex
- * @param bool $bIndexIsUid = true,
- * @param string $sMimeIndex = ''
- *
- * @return bool
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function MessageMimeStream($mCallback, $sFolderName, $iIndex, $bIndexIsUid = true, $sMimeIndex = '')
- {
- if (!is_callable($mCallback))
- {
- throw new \MailSo\Base\Exceptions\InvalidArgumentException();
- }
-
- $this->oImapClient->FolderSelect($sFolderName);
-
- $sFileName = '';
- $sContentType = '';
- $sMailEncodingName = '';
-
- $sMimeIndex = trim($sMimeIndex);
- $aFetchResponse = $this->oImapClient->Fetch(array(
- 0 === \strlen($sMimeIndex)
- ? \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK
- : \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sMimeIndex.'.MIME]'
- ), $iIndex, $bIndexIsUid);
-
- if (0 < \count($aFetchResponse))
- {
- $sMime = $aFetchResponse[0]->GetFetchValue(
- 0 === \strlen($sMimeIndex)
- ? \MailSo\Imap\Enumerations\FetchType::BODY_HEADER
- : \MailSo\Imap\Enumerations\FetchType::BODY.'['.$sMimeIndex.'.MIME]'
- );
-
- if (0 < \strlen($sMime))
- {
- $oHeaders = \MailSo\Mime\HeaderCollection::NewInstance()->Parse($sMime);
-
- if (0 < \strlen($sMimeIndex))
- {
- $sFileName = $oHeaders->ParameterValue(
- \MailSo\Mime\Enumerations\Header::CONTENT_DISPOSITION,
- \MailSo\Mime\Enumerations\Parameter::FILENAME);
-
- if (0 === \strlen($sFileName))
- {
- $sFileName = $oHeaders->ParameterValue(
- \MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
- \MailSo\Mime\Enumerations\Parameter::NAME);
- }
-
- $sMailEncodingName = $oHeaders->ValueByName(
- \MailSo\Mime\Enumerations\Header::CONTENT_TRANSFER_ENCODING);
-
- $sContentType = $oHeaders->ValueByName(
- \MailSo\Mime\Enumerations\Header::CONTENT_TYPE);
- }
- else
- {
- $sSubject = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::SUBJECT);
-
- $sFileName = 0 === \strlen($sSubject) ? (string) $iIndex : $sSubject;
- $sFileName .= '.eml';
-
- $sContentType = 'message/rfc822';
- }
- }
- }
-
- $aFetchResponse = $this->oImapClient->Fetch(array(
- array(\MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sMimeIndex.']',
- function ($sParent, $sLiteralAtomUpperCase, $rImapLiteralStream) use ($mCallback, $sMimeIndex, $sMailEncodingName, $sContentType, $sFileName)
- {
- if (0 < \strlen($sLiteralAtomUpperCase))
- {
- if (is_resource($rImapLiteralStream) && 'FETCH' === $sParent)
- {
- $rMessageMimeIndexStream = (0 === \strlen($sMailEncodingName))
- ? $rImapLiteralStream
- : \MailSo\Base\StreamWrappers\Binary::CreateStream($rImapLiteralStream,
- \MailSo\Base\StreamWrappers\Binary::GetInlineDecodeOrEncodeFunctionName(
- $sMailEncodingName, true));
-
- \call_user_func($mCallback, $rMessageMimeIndexStream, $sContentType, $sFileName, $sMimeIndex);
- }
- }
- }
- )), $iIndex, $bIndexIsUid);
-
- return ($aFetchResponse && 1 === \count($aFetchResponse));
- }
-
- /**
- * @param string $sFolder
- * @param array $aIndexRange
- * @param bool $bIndexIsUid
- * @param bool $bUseExpunge = true
- * @param bool $bExpungeAll = false
- *
- * @return \MailSo\Mail\MailClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function MessageDelete($sFolder, $aIndexRange, $bIndexIsUid, $bUseExpunge = true, $bExpungeAll = false)
- {
- if (0 === \strlen($sFolder) || !\is_array($aIndexRange) || 0 === \count($aIndexRange))
- {
- throw new \MailSo\Base\Exceptions\InvalidArgumentException();
- }
-
- $this->oImapClient->FolderSelect($sFolder);
-
- $sIndexRange = \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange);
-
- $this->oImapClient->MessageStoreFlag($sIndexRange, $bIndexIsUid,
- array(\MailSo\Imap\Enumerations\MessageFlag::DELETED),
- \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT
- );
-
- if ($bUseExpunge)
- {
- $this->oImapClient->MessageExpunge($bIndexIsUid ? $sIndexRange : '', $bIndexIsUid, $bExpungeAll);
- }
-
- return $this;
- }
-
- /**
- * @param string $sFromFolder
- * @param string $sToFolder
- * @param array $aIndexRange
- * @param bool $bIndexIsUid
- * @param bool $bUseMoveSupported = false
- * @param bool $bExpungeAll = false
- *
- * @return \MailSo\Mail\MailClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function MessageMove($sFromFolder, $sToFolder, $aIndexRange, $bIndexIsUid, $bUseMoveSupported = false, $bExpungeAll = false)
- {
- if (0 === \strlen($sFromFolder) || 0 === \strlen($sToFolder) ||
- !\is_array($aIndexRange) || 0 === \count($aIndexRange))
- {
- throw new \MailSo\Base\Exceptions\InvalidArgumentException();
- }
-
- $this->oImapClient->FolderSelect($sFromFolder);
-
- if ($bUseMoveSupported && $this->oImapClient->IsSupported('MOVE'))
- {
- $this->oImapClient->MessageMove($sToFolder,
- \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), $bIndexIsUid);
- }
- else
- {
- $this->oImapClient->MessageCopy($sToFolder,
- \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), $bIndexIsUid);
-
- $this->MessageDelete($sFromFolder, $aIndexRange, $bIndexIsUid, true, $bExpungeAll);
- }
-
- return $this;
- }
-
- /**
- * @param string $sFromFolder
- * @param string $sToFolder
- * @param array $aIndexRange
- * @param bool $bIndexIsUid
- *
- * @return \MailSo\Mail\MailClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function MessageCopy($sFromFolder, $sToFolder, $aIndexRange, $bIndexIsUid)
- {
- if (0 === \strlen($sFromFolder) || 0 === \strlen($sToFolder) ||
- !\is_array($aIndexRange) || 0 === \count($aIndexRange))
- {
- throw new \MailSo\Base\Exceptions\InvalidArgumentException();
- }
-
- $this->oImapClient->FolderSelect($sFromFolder);
- $this->oImapClient->MessageCopy($sToFolder,
- \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), $bIndexIsUid);
-
- return $this;
- }
-
- /**
- * @return \MailSo\Mail\MailClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function FolderUnSelect()
- {
- if ($this->oImapClient->IsSelected())
- {
- $this->oImapClient->FolderUnSelect();
- }
-
- return $this;
- }
-
- /**
- * @param resource $rMessageStream
- * @param int $iMessageStreamSize
- * @param string $sFolderToSave
- * @param array $aAppendFlags = null
- * @param int $iUid = null
- *
- * @return \MailSo\Mail\MailClient
- */
- public function MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderToSave, $aAppendFlags = null, &$iUid = null)
- {
- if (!\is_resource($rMessageStream) || 0 === \strlen($sFolderToSave))
- {
- throw new \MailSo\Base\Exceptions\InvalidArgumentException();
- }
-
- $this->oImapClient->MessageAppendStream(
- $sFolderToSave, $rMessageStream, $iMessageStreamSize, $aAppendFlags, $iUid);
-
- return $this;
- }
-
- /**
- * @param string $sMessageFileName
- * @param string $sFolderToSave
- * @param array $aAppendFlags = null
- * @param int &$iUid = null
- *
- * @return \MailSo\Mail\MailClient
- */
- public function MessageAppendFile($sMessageFileName, $sFolderToSave, $aAppendFlags = null, &$iUid = null)
- {
- if (!@\is_file($sMessageFileName) || !@\is_readable($sMessageFileName))
- {
- throw new \MailSo\Base\Exceptions\InvalidArgumentException();
- }
-
- $iMessageStreamSize = \filesize($sMessageFileName);
- $rMessageStream = \fopen($sMessageFileName, 'rb');
-
- $this->MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderToSave, $aAppendFlags, $iUid);
-
- if (\is_resource($rMessageStream))
- {
- @fclose($rMessageStream);
- }
-
- return $this;
- }
-
- /**
- * @param string $sFolderName
- * @param int $iCount
- * @param int $iUnseenCount
- * @param string $sUidNext
- * @param string $sHighestModSeq
- *
- * @return void
- */
- protected function initFolderValues($sFolderName, &$iCount, &$iUnseenCount,
- &$sUidNext, &$sHighestModSeq = '')
- {
- $aTypes = array(
- \MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES,
- \MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN,
- \MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT
- );
-
- if ($this->oImapClient->IsSupported('CONDSTORE'))
- {
- $aTypes[] = \MailSo\Imap\Enumerations\FolderResponseStatus::HIGHESTMODSEQ;
- }
-
- $aFolderStatus = $this->oImapClient->FolderStatus($sFolderName, $aTypes);
-
- $iCount = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES])
- ? (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES] : 0;
-
- $iUnseenCount = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN])
- ? (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN] : 0;
-
- $sUidNext = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT])
- ? (string) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT] : '0';
-
- $sHighestModSeq = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::HIGHESTMODSEQ])
- ? (string) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::HIGHESTMODSEQ] : '';
-
- if ($this->IsGmail() &&
- ('INBOX' === $sFolderName || '[gmail]' === \strtolower(\substr($sFolderName, 0, 7))))
- {
- $oFolder = $this->oImapClient->FolderCurrentInformation();
- if ($oFolder && null !== $oFolder->Exists && $oFolder->FolderName === $sFolderName)
- {
- $iSubCount = (int) $oFolder->Exists;
- if (0 < $iSubCount && $iSubCount < $iCount)
- {
- $iCount = $iSubCount;
- }
- }
- }
- }
-
- /**
- * @return string
- */
- public function GenerateImapClientHash()
- {
- return \md5('ImapClientHash/'.
- $this->oImapClient->GetLogginedUser().'@'.
- $this->oImapClient->GetConnectedHost().':'.
- $this->oImapClient->GetConnectedPort()
- );
- }
-
- /**
- * @param string $sFolder
- * @param int $iCount
- * @param int $iUnseenCount
- * @param string $sUidNext
- * @param string $sHighestModSeq = ''
- *
- * @return string
- */
- public function GenerateFolderHash($sFolder, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq = '')
- {
- $iUnseenCount = 0; // unneccessery
- return \md5('FolderHash/'.$sFolder.'-'.$iCount.'-'.$iUnseenCount.'-'.$sUidNext.'-'.
- $sHighestModSeq.'-'.$this->GenerateImapClientHash().'-'.
- \MailSo\Config::$MessageListPermanentFilter
- );
- }
-
- /**
- * @param string $sFolderName
- * @param string $sPrevUidNext
- * @param string $sCurrentUidNext
- *
- * @return array
- */
- private function getFolderNextMessageInformation($sFolderName, $sPrevUidNext, $sCurrentUidNext)
- {
- $aNewMessages = array();
-
- if (0 < \strlen($sPrevUidNext) && (string) $sPrevUidNext !== (string) $sCurrentUidNext)
- {
- $this->oImapClient->FolderSelect($sFolderName);
-
- $aFetchResponse = $this->oImapClient->Fetch(array(
- \MailSo\Imap\Enumerations\FetchType::INDEX,
- \MailSo\Imap\Enumerations\FetchType::UID,
- \MailSo\Imap\Enumerations\FetchType::FLAGS,
- \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array(
- \MailSo\Mime\Enumerations\Header::FROM_,
- \MailSo\Mime\Enumerations\Header::SUBJECT,
- \MailSo\Mime\Enumerations\Header::CONTENT_TYPE
- ))
- ), $sPrevUidNext.':*', true);
-
- if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse))
- {
- foreach ($aFetchResponse as /* @var $oFetchResponse \MailSo\Imap\FetchResponse */ $oFetchResponse)
- {
- $aFlags = \array_map('strtolower', $oFetchResponse->GetFetchValue(
- \MailSo\Imap\Enumerations\FetchType::FLAGS));
-
- if (!\in_array(\strtolower(\MailSo\Imap\Enumerations\MessageFlag::SEEN), $aFlags))
- {
- $sUid = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID);
- $sHeaders = $oFetchResponse->GetHeaderFieldsValue();
-
- $oHeaders = \MailSo\Mime\HeaderCollection::NewInstance()->Parse($sHeaders);
-
- $sContentTypeCharset = $oHeaders->ParameterValue(
- \MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
- \MailSo\Mime\Enumerations\Parameter::CHARSET
- );
-
- $sCharset = '';
- if (0 < \strlen($sContentTypeCharset))
- {
- $sCharset = $sContentTypeCharset;
- }
-
- if (0 < \strlen($sCharset))
- {
- $oHeaders->SetParentCharset($sCharset);
- }
-
- $aNewMessages[] = array(
- 'Folder' => $sFolderName,
- 'Uid' => $sUid,
- 'Subject' => $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::SUBJECT, 0 === \strlen($sCharset)),
- 'From' => $oHeaders->GetAsEmailCollection(\MailSo\Mime\Enumerations\Header::FROM_, 0 === \strlen($sCharset))
- );
- }
- }
- }
- }
-
- return $aNewMessages;
- }
-
- /**
- * @param string $sFolderName
- * @param string $sPrevUidNext = ''
- * @param array $aUids = ''
- *
- * @return string
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function FolderInformation($sFolderName, $sPrevUidNext = '', $aUids = array())
- {
- $aFlags = array();
-
- $bSelect = false;
- if ($this->IsGmail() &&
- ('INBOX' === $sFolderName || '[gmail]' === \strtolower(\substr($sFolderName, 0, 7))))
- {
- $this->oImapClient->FolderSelect($sFolderName);
- $bSelect = true;
- }
-
- if (\is_array($aUids) && 0 < \count($aUids))
- {
- if (!$bSelect)
- {
- $this->oImapClient->FolderSelect($sFolderName);
- }
-
- $aFetchResponse = $this->oImapClient->Fetch(array(
- \MailSo\Imap\Enumerations\FetchType::INDEX,
- \MailSo\Imap\Enumerations\FetchType::UID,
- \MailSo\Imap\Enumerations\FetchType::FLAGS
- ), \MailSo\Base\Utils::PrepearFetchSequence($aUids), true);
-
- if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse))
- {
- foreach ($aFetchResponse as $oFetchResponse)
- {
- $sUid = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID);
- $aFlags[(\is_numeric($sUid) ? (int) $sUid : 0)] =
- $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::FLAGS);
- }
- }
- }
-
- $iCount = 0;
- $iUnseenCount = 0;
- $sUidNext = '0';
- $sHighestModSeq = '';
-
- $this->initFolderValues($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq);
-
- $aResult = array(
- 'Folder' => $sFolderName,
- 'Hash' => $this->GenerateFolderHash($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq),
- 'MessageCount' => $iCount,
- 'MessageUnseenCount' => $iUnseenCount,
- 'UidNext' => $sUidNext,
- 'Flags' => $aFlags,
- 'HighestModSeq' => $sHighestModSeq,
- 'NewMessages' => 'INBOX' === $sFolderName && \MailSo\Config::$CheckNewMessages ?
- $this->getFolderNextMessageInformation($sFolderName, $sPrevUidNext, $sUidNext) : array()
- );
-
- return $aResult;
- }
-
- /**
- * @param string $sFolderName
- *
- * @return string
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function FolderHash($sFolderName)
- {
- $iCount = 0;
- $iUnseenCount = 0;
- $sUidNext = '0';
- $sHighestModSeq = '';
-
- $this->initFolderValues($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq);
-
- return $this->GenerateFolderHash($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq);
- }
-
- /**
- * @return int
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function InboxUnreadCount()
- {
- $aFolderStatus = $this->oImapClient->FolderStatus('INBOX', array(
- \MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN
- ));
-
- $iResult = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN]) ?
- (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN] : 0;
-
- return 0 < $iResult ? $iResult : 0;
- }
-
- /**
- * @return bool
- */
- public function IsGmail()
- {
- return 'ssl://imap.gmail.com' === \strtolower($this->oImapClient->GetConnectedHost());
- }
-
- /**
- * @param string $sSearch
- * @param bool $bDetectGmail = true
- *
- * @return string
- */
- private function escapeSearchString($sSearch, $bDetectGmail = true)
- {
- return !\MailSo\Base\Utils::IsAscii($sSearch)
- ? '{'.\strlen($sSearch).'}'."\r\n".$sSearch : $this->oImapClient->EscapeString($sSearch);
-// return ($bDetectGmail && !\MailSo\Base\Utils::IsAscii($sSearch) && $this->IsGmail())
-// ? '{'.\strlen($sSearch).'+}'."\r\n".$sSearch : $this->oImapClient->EscapeString($sSearch);
- }
-
- /**
- * @param string $sDate
- * @param int $iTimeZoneOffset
- *
- * @return int
- */
- private function parseSearchDate($sDate, $iTimeZoneOffset)
- {
- $iResult = 0;
- if (0 < \strlen($sDate))
- {
- $oDateTime = \DateTime::createFromFormat('Y.m.d', $sDate, \MailSo\Base\DateTimeHelper::GetUtcTimeZoneObject());
- return $oDateTime ? $oDateTime->getTimestamp() - $iTimeZoneOffset : 0;
- }
-
- return $iResult;
- }
-
- /**
- * @param string $sSize
- *
- * @return int
- */
- private function parseFriendlySize($sSize)
- {
- $sSize = preg_replace('/[^0-9bBkKmM]/', '', $sSize);
-
- $iResult = 0;
- $aMatch = array();
-
- if (\preg_match('/([\d]+)(B|KB|M|MB|G|GB)$/i', $sSize, $aMatch) && isset($aMatch[1], $aMatch[2]))
- {
- $iResult = (int) $aMatch[1];
- switch (\strtoupper($aMatch[2]))
- {
- case 'K':
- case 'KB':
- $iResult *= 1024;
- case 'M':
- case 'MB':
- $iResult *= 1024;
- case 'G':
- case 'GB':
- $iResult *= 1024;
- }
- }
- else
- {
- $iResult = (int) $sSize;
- }
-
- return $iResult;
- }
-
- /**
- * @param string $sSearch
- *
- * @return array
- */
- private function parseSearchString($sSearch)
- {
- $aResult = array(
- 'OTHER' => ''
- );
-
- $aCache = array();
-
- $sReg = 'e?mail|from|to|subject|has|is|date|text|body|size|larger|bigger|smaller|maxsize|minsize';
-
- $sSearch = \MailSo\Base\Utils::StripSpaces($sSearch);
- $sSearch = \trim(\preg_replace('/('.$sReg.'): /i', '\\1:', $sSearch));
-
- $mMatch = array();
- \preg_match_all('/".*?(? $sName)
- {
- if (isset($mMatch[2][$iIndex]) && 0 < \strlen($mMatch[2][$iIndex]))
- {
- $sName = \strtoupper($sName);
- $sValue = $mMatch[2][$iIndex];
- switch ($sName)
- {
- case 'TEXT':
- case 'BODY':
- case 'EMAIL':
- case 'MAIL':
- case 'FROM':
- case 'TO':
- case 'SUBJECT':
- case 'IS':
- case 'HAS':
- case 'SIZE':
- case 'SMALLER':
- case 'LARGER':
- case 'BIGGER':
- case 'MAXSIZE':
- case 'MINSIZE':
- case 'DATE':
- if ('MAIL' === $sName)
- {
- $sName = 'EMAIL';
- }
- if ('BODY' === $sName)
- {
- $sName = 'TEXT';
- }
- if ('SIZE' === $sName || 'BIGGER' === $sName || 'MINSIZE' === $sName)
- {
- $sName = 'LARGER';
- }
- if ('MAXSIZE' === $sName)
- {
- $sName = 'SMALLER';
- }
- $aResult[$sName] = $sValue;
- break;
- }
- }
- }
- }
-
- $aResult['OTHER'] = $sSearch;
- foreach ($aResult as $sName => $sValue)
- {
- if (isset($aCache[$sValue]))
- {
- $aResult[$sName] = \trim($aCache[$sValue], '"\' ');
- }
- }
-
- return $aResult;
- }
-
- /**
- * @param string $sSearch
- * @param string $sFilter
- * @param int $iTimeZoneOffset = 0
- * @param bool $bUseCache = true
- *
- * @return string
- */
- private function getImapSearchCriterias($sSearch, $sFilter, $iTimeZoneOffset = 0, &$bUseCache = true)
- {
- $bUseCache = true;
- $iTimeFilter = 0;
- $aCriteriasResult = array();
-
- if (0 < \MailSo\Config::$MessageListDateFilter)
- {
- $iD = \time() - 3600 * 24 * 30 * \MailSo\Config::$MessageListDateFilter;
- $iTimeFilter = \gmmktime(1, 1, 1, \gmdate('n', $iD), 1, \gmdate('Y', $iD));
- }
-
- if (0 < \strlen(\trim($sSearch)))
- {
- $sGmailRawSearch = '';
- $sResultBodyTextSearch = '';
-
- $aLines = $this->parseSearchString($sSearch);
- $bIsGmail = $this->oImapClient->IsSupported('X-GM-EXT-1');
-
- if (1 === \count($aLines) && isset($aLines['OTHER']))
- {
- $sValue = $this->escapeSearchString($aLines['OTHER']);
-
- if (\MailSo\Config::$MessageListFastSimpleSearch)
- {
- $aCriteriasResult[] = 'OR OR OR';
- $aCriteriasResult[] = 'FROM';
- $aCriteriasResult[] = $sValue;
- $aCriteriasResult[] = 'TO';
- $aCriteriasResult[] = $sValue;
- $aCriteriasResult[] = 'CC';
- $aCriteriasResult[] = $sValue;
- $aCriteriasResult[] = 'SUBJECT';
- $aCriteriasResult[] = $sValue;
- }
- else
- {
- $aCriteriasResult[] = 'TEXT';
- $aCriteriasResult[] = $sValue;
- }
- }
- else
- {
- if (isset($aLines['EMAIL']))
- {
- $sValue = $this->escapeSearchString($aLines['EMAIL']);
-
- $aCriteriasResult[] = 'OR OR';
- $aCriteriasResult[] = 'FROM';
- $aCriteriasResult[] = $sValue;
- $aCriteriasResult[] = 'TO';
- $aCriteriasResult[] = $sValue;
- $aCriteriasResult[] = 'CC';
- $aCriteriasResult[] = $sValue;
-
- unset($aLines['EMAIL']);
- }
-
- if (isset($aLines['TO']))
- {
- $sValue = $this->escapeSearchString($aLines['TO']);
-
- $aCriteriasResult[] = 'OR';
- $aCriteriasResult[] = 'TO';
- $aCriteriasResult[] = $sValue;
- $aCriteriasResult[] = 'CC';
- $aCriteriasResult[] = $sValue;
-
- unset($aLines['TO']);
- }
-
- $sMainText = '';
- foreach ($aLines as $sName => $sRawValue)
- {
- if ('' === \trim($sRawValue))
- {
- continue;
- }
-
- $sValue = $this->escapeSearchString($sRawValue);
- switch ($sName)
- {
- case 'FROM':
- $aCriteriasResult[] = 'FROM';
- $aCriteriasResult[] = $sValue;
- break;
- case 'SUBJECT':
- $aCriteriasResult[] = 'SUBJECT';
- $aCriteriasResult[] = $sValue;
- break;
- case 'OTHER':
- case 'TEXT':
- $sMainText .= ' '.$sRawValue;
- break;
- case 'HAS':
- $aValue = \explode(',', \strtolower($sRawValue));
- $aValue = \array_map('trim', $aValue);
-
- $aCompareArray = array('file', 'files', 'attach', 'attachs', 'attachment', 'attachments');
- if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue)))
- {
- if ($bIsGmail)
- {
- $sGmailRawSearch .= ' has:attachment';
- }
- else
- {
- // Simple, is not detailed search (Sometimes doesn't work)
- $aCriteriasResult[] = 'OR OR OR';
- $aCriteriasResult[] = 'HEADER Content-Type application/';
- $aCriteriasResult[] = 'HEADER Content-Type multipart/m';
- $aCriteriasResult[] = 'HEADER Content-Type multipart/signed';
- $aCriteriasResult[] = 'HEADER Content-Type multipart/report';
- }
- }
-
- case 'IS':
- $aValue = \explode(',', \strtolower($sRawValue));
- $aValue = \array_map('trim', $aValue);
-
- $aCompareArray = array('flag', 'flagged', 'star', 'starred', 'pinned');
- $aCompareArray2 = array('unflag', 'unflagged', 'unstar', 'unstarred', 'unpinned');
- if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue)))
- {
- $aCriteriasResult[] = 'FLAGGED';
- $bUseCache = false;
- }
- else if (\count($aCompareArray2) > \count(\array_diff($aCompareArray2, $aValue)))
- {
- $aCriteriasResult[] = 'UNFLAGGED';
- $bUseCache = false;
- }
-
- $aCompareArray = array('unread', 'unseen');
- $aCompareArray2 = array('read', 'seen');
- if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue)))
- {
- $aCriteriasResult[] = 'UNSEEN';
- $bUseCache = false;
- }
- else if (\count($aCompareArray2) > \count(\array_diff($aCompareArray2, $aValue)))
- {
- $aCriteriasResult[] = 'SEEN';
- $bUseCache = false;
- }
- break;
-
- case 'LARGER':
- $aCriteriasResult[] = 'LARGER';
- $aCriteriasResult[] = $this->parseFriendlySize($sRawValue);
- break;
- case 'SMALLER':
- $aCriteriasResult[] = 'SMALLER';
- $aCriteriasResult[] = $this->parseFriendlySize($sRawValue);
- break;
- case 'DATE':
- $iDateStampFrom = $iDateStampTo = 0;
-
- $sDate = $sRawValue;
- $aDate = \explode('/', $sDate);
-
- if (\is_array($aDate) && 2 === \count($aDate))
- {
- if (0 < \strlen($aDate[0]))
- {
- $iDateStampFrom = $this->parseSearchDate($aDate[0], $iTimeZoneOffset);
- }
-
- if (0 < \strlen($aDate[1]))
- {
- $iDateStampTo = $this->parseSearchDate($aDate[1], $iTimeZoneOffset);
- $iDateStampTo += 60 * 60 * 24;
- }
- }
- else
- {
- if (0 < \strlen($sDate))
- {
- $iDateStampFrom = $this->parseSearchDate($sDate, $iTimeZoneOffset);
- $iDateStampTo = $iDateStampFrom + 60 * 60 * 24;
- }
- }
-
- if (0 < $iDateStampFrom)
- {
- $aCriteriasResult[] = 'SINCE';
- $aCriteriasResult[] = \gmdate('j-M-Y', $iTimeFilter > $iDateStampFrom ?
- $iTimeFilter : $iDateStampFrom);
-
- $iTimeFilter = 0;
- }
-
- if (0 < $iDateStampTo)
- {
- $aCriteriasResult[] = 'BEFORE';
- $aCriteriasResult[] = \gmdate('j-M-Y', $iDateStampTo);
- }
- break;
- }
- }
-
- if ('' !== \trim($sMainText))
- {
- $sMainText = \trim(\MailSo\Base\Utils::StripSpaces($sMainText), '"');
- if ($bIsGmail)
- {
- $sGmailRawSearch .= ' '.$sMainText;
- }
- else
- {
- $sResultBodyTextSearch .= ' '.$sMainText;
- }
- }
- }
-
- $sGmailRawSearch = \trim($sGmailRawSearch);
- if ($bIsGmail && 0 < \strlen($sGmailRawSearch))
- {
- $aCriteriasResult[] = 'X-GM-RAW';
- $aCriteriasResult[] = $this->escapeSearchString($sGmailRawSearch, false);
- }
-
- $sResultBodyTextSearch = \trim($sResultBodyTextSearch);
- if (0 < \strlen($sResultBodyTextSearch))
- {
- $aCriteriasResult[] = 'BODY';
- $aCriteriasResult[] = $this->escapeSearchString($sResultBodyTextSearch);
- }
- }
-
- $sCriteriasResult = \trim(\implode(' ', $aCriteriasResult));
-
- if (0 < $iTimeFilter)
- {
- $sCriteriasResult .= ' SINCE '.\gmdate('j-M-Y', $iTimeFilter);
- }
-
- $sCriteriasResult = \trim($sCriteriasResult);
- if (\MailSo\Config::$MessageListUndeletedOnly)
- {
- $sCriteriasResult = \trim($sCriteriasResult.' UNDELETED');
- }
-
- $sFilter = \trim($sFilter);
- if ('' !== $sFilter)
- {
- $sCriteriasResult .= ' '.$sFilter;
- }
-
- $sCriteriasResult = \trim($sCriteriasResult);
- if ('' !== \MailSo\Config::$MessageListPermanentFilter)
- {
- $sCriteriasResult = \trim($sCriteriasResult.' '.\MailSo\Config::$MessageListPermanentFilter);
- }
-
- $sCriteriasResult = \trim($sCriteriasResult);
- if ('' === $sCriteriasResult)
- {
- $sCriteriasResult = 'ALL';
- }
-
- return $sCriteriasResult;
- }
-
- /**
- * @param array $aThreads
- * @return array
- */
- private function threadArrayMap($aThreads)
- {
- $aNew = array();
- foreach ($aThreads as $mItem)
- {
- if (!\is_array($mItem))
- {
- $aNew[] = $mItem;
- }
- else
- {
- $mMap = $this->threadArrayMap($mItem);
- if (\is_array($mMap) && 0 < \count($mMap))
- {
- $aNew = \array_merge($aNew, $mMap);
- }
- }
- }
-
- return $aNew;
- }
-
- /**
- * @param array $aThreads
- *
- * @return array
- */
- private function compileThreadArray($aThreads)
- {
- $aResult = array();
- foreach ($aThreads as $mItem)
- {
- if (\is_array($mItem))
- {
- $aMap = $this->threadArrayMap($mItem);
- if (\is_array($aMap))
- {
- if (1 < \count($aMap))
- {
- $aResult[] = $aMap;
- }
- else if (0 < \count($aMap))
- {
- $aResult[] = $aMap[0];
- }
- }
- }
- else
- {
- $aResult[] = $mItem;
- }
- }
-
- return $aResult;
- }
-
- /**
- * @param string $sFolderName
- * @param string $sFolderHash
- * @param array $aIndexOrUids
- * @param \MailSo\Cache\CacheClient $oCacher
- * @param bool $bCacheOnly = false
- *
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function MessageListThreadsMap($sFolderName, $sFolderHash, $aIndexOrUids, $oCacher, $bCacheOnly = false)
- {
- $iThreadLimit = \MailSo\Config::$LargeThreadLimit;
-
- $sSearchHash = '';
- if (0 < \MailSo\Config::$MessageListDateFilter)
- {
- $iD = \time() - 3600 * 24 * 30 * \MailSo\Config::$MessageListDateFilter;
- $iTimeFilter = \gmmktime(1, 1, 1, \gmdate('n', $iD), 1, \gmdate('Y', $iD));
-
- $sSearchHash .= ' SINCE '.\gmdate('j-M-Y', $iTimeFilter);
- }
-
- if ('' === \trim($sSearchHash))
- {
- $sSearchHash = 'ALL';
- }
-
- if ($oCacher && $oCacher->IsInited())
- {
- $sSerializedHashKey =
- 'ThreadsMapSorted/'.$sSearchHash.'/'.
- 'Limit='.$iThreadLimit.'/'.$sFolderName.'/'.$sFolderHash;
-
- if ($this->oLogger)
- {
- $this->oLogger->Write($sSerializedHashKey);
- }
-
- $sSerializedUids = $oCacher->Get($sSerializedHashKey);
- if (!empty($sSerializedUids))
- {
- $aSerializedUids = @\json_decode($sSerializedUids, true);
- if (isset($aSerializedUids['ThreadsUids']) && \is_array($aSerializedUids['ThreadsUids']))
- {
- if ($this->oLogger)
- {
- $this->oLogger->Write('Get Serialized Thread UIDS from cache ("'.$sFolderName.'" / '.$sSearchHash.') [count:'.\count($aSerializedUids['ThreadsUids']).']');
- }
-
- return $aSerializedUids['ThreadsUids'];
- }
- }
- }
-
- if ($bCacheOnly)
- {
- return null;
- }
-
- $this->oImapClient->FolderExamine($sFolderName);
-
- $aThreadUids = array();
- try
- {
- $aThreadUids = $this->oImapClient->MessageSimpleThread($sSearchHash);
- }
- catch (\MailSo\Imap\Exceptions\RuntimeException $oException)
- {
- unset($oException);
- $aThreadUids = array();
- }
-
- $aResult = array();
- $aCompiledThreads = $this->compileThreadArray($aThreadUids);
-
- foreach ($aCompiledThreads as $mData)
- {
- if (\is_array($mData))
- {
- foreach ($mData as $mSubData)
- {
- $aResult[(int) $mSubData] =
- \array_diff($mData, array((int) $mSubData));
- }
- }
- else if (\is_int($mData) || \is_string($mData))
- {
- $aResult[(int) $mData] = (int) $mData;
- }
- }
-
- $aParentsMap = array();
- foreach ($aIndexOrUids as $iUid)
- {
- if (isset($aResult[$iUid]) && \is_array($aResult[$iUid]))
- {
- foreach ($aResult[$iUid] as $iTempUid)
- {
- $aParentsMap[$iTempUid] = $iUid;
- if (isset($aResult[$iTempUid]))
- {
- unset($aResult[$iTempUid]);
- }
- }
- }
- }
-
- $aSortedThreads = array();
- foreach ($aIndexOrUids as $iUid)
- {
- if (isset($aResult[$iUid]))
- {
- $aSortedThreads[$iUid] = $iUid;
- }
- }
-
- foreach ($aIndexOrUids as $iUid)
- {
- if (!isset($aSortedThreads[$iUid]) &&
- isset($aParentsMap[$iUid]) &&
- isset($aSortedThreads[$aParentsMap[$iUid]]))
- {
- if (!\is_array($aSortedThreads[$aParentsMap[$iUid]]))
- {
- $aSortedThreads[$aParentsMap[$iUid]] = array();
- }
-
- $aSortedThreads[$aParentsMap[$iUid]][] = $iUid;
- }
- }
-
- $aResult = $aSortedThreads;
- unset($aParentsMap, $aSortedThreads);
-
- $aTemp = array();
- foreach ($aResult as $iUid => $mValue)
- {
- if (0 < $iThreadLimit && \is_array($mValue) && $iThreadLimit < \count($mValue))
- {
- $aParts = \array_chunk($mValue, $iThreadLimit);
- if (0 < count($aParts))
- {
- foreach ($aParts as $iIndex => $aItem)
- {
- if (0 === $iIndex)
- {
- $aResult[$iUid] = $aItem;
- }
- else if (0 < $iIndex && \is_array($aItem))
- {
- $mFirst = \array_shift($aItem);
- if (!empty($mFirst))
- {
- $aTemp[$mFirst] = 0 < \count($aItem) ? $aItem : $mFirst;
- }
- }
- }
- }
- }
- }
-
- foreach ($aTemp as $iUid => $mValue)
- {
- $aResult[$iUid] = $mValue;
- }
-
- unset($aTemp);
-
- $aLastResult = array();
- foreach ($aIndexOrUids as $iUid)
- {
- if (isset($aResult[$iUid]))
- {
- $aLastResult[$iUid] = $aResult[$iUid];
- }
- }
-
- $aResult = $aLastResult;
- unset($aLastResult);
-
- if ($oCacher && $oCacher->IsInited() && !empty($sSerializedHashKey))
- {
- $oCacher->Set($sSerializedHashKey, @\json_encode(array(
- 'ThreadsUids' => $aResult
- )));
-
- if ($this->oLogger)
- {
- $this->oLogger->Write('Save Serialized Thread UIDS to cache ("'.$sFolderName.'" / '.$sSearchHash.') [count:'.\count($aResult).']');
- }
- }
-
- return $aResult;
- }
-
- /**
- * @param \MailSo\Mail\MessageCollection &$oMessageCollection
- * @param array $aRequestIndexOrUids
- * @param bool $bIndexAsUid
- * @param bool $bSimple = false
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function MessageListByRequestIndexOrUids(&$oMessageCollection, $aRequestIndexOrUids, $bIndexAsUid, $bSimple = false)
- {
- if (\is_array($aRequestIndexOrUids) && 0 < \count($aRequestIndexOrUids))
- {
- $aFetchResponse = $this->oImapClient->Fetch(array(
- \MailSo\Imap\Enumerations\FetchType::INDEX,
- \MailSo\Imap\Enumerations\FetchType::UID,
- \MailSo\Imap\Enumerations\FetchType::RFC822_SIZE,
- \MailSo\Imap\Enumerations\FetchType::INTERNALDATE,
- \MailSo\Imap\Enumerations\FetchType::FLAGS,
- \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE,
- $bSimple ?
- $this->getEnvelopeOrHeadersRequestStringForSimpleList() :
- $this->getEnvelopeOrHeadersRequestString()
- ), \MailSo\Base\Utils::PrepearFetchSequence($aRequestIndexOrUids), $bIndexAsUid);
-
- if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse))
- {
- $aFetchIndexArray = array();
- $oFetchResponseItem = null;
- foreach ($aFetchResponse as /* @var $oFetchResponseItem \MailSo\Imap\FetchResponse */ &$oFetchResponseItem)
- {
- $aFetchIndexArray[($bIndexAsUid)
- ? $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID)
- : $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::INDEX)] =& $oFetchResponseItem;
-
- unset($oFetchResponseItem);
- }
-
- foreach ($aRequestIndexOrUids as $iFUid)
- {
- if (isset($aFetchIndexArray[$iFUid]))
- {
- $oMessageCollection->Add(
- Message::NewFetchResponseInstance(
- $oMessageCollection->FolderName, $aFetchIndexArray[$iFUid]));
- }
- }
- }
- }
- }
-
- /**
- * @return bool
- *
- * @throws \MailSo\Net\Exceptions\Exception
- */
- public function IsThreadsSupported()
- {
- return $this->oImapClient->IsSupported('THREAD=REFS') ||
- $this->oImapClient->IsSupported('THREAD=REFERENCES') ||
- $this->oImapClient->IsSupported('THREAD=ORDEREDSUBJECT');
- }
-
- /**
- * @param string $sFolderName
- * @param array $aUids
- *
- * @return \MailSo\Mail\MessageCollection
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function MessageListSimple($sFolderName, $aUids)
- {
- if (0 === \strlen($sFolderName) || !\MailSo\Base\Validator::NotEmptyArray($aUids))
- {
- throw new \MailSo\Base\Exceptions\InvalidArgumentException();
- }
-
- $this->oImapClient->FolderExamine($sFolderName);
-
- $oMessageCollection = \MailSo\Mail\MessageCollection::NewInstance();
- $oMessageCollection->FolderName = $sFolderName;
-
- $this->MessageListByRequestIndexOrUids($oMessageCollection, $aUids, true, true);
-
- return $oMessageCollection->GetAsArray();
- }
-
- /**
- * @param \MailSo\Cache\CacheClient|null $oCacher
- * @param string $sSearch
- * @param string $sFilter
- * @param string $sFolderName
- * @param string $sFolderHash
- * @param bool $bUseSortIfSupported = false
- *
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function GetUids($oCacher, $sSearch, $sFilter, $sFolderName, $sFolderHash, $bUseSortIfSupported = false)
- {
- $aResultUids = false;
- $bUidsFromCacher = false;
- $bUseCacheAfterSearch = true;
-
- $sSerializedHash = '';
- $sSerializedLog = '';
-
- $bUseSortIfSupported = $bUseSortIfSupported ? !!$this->oImapClient->IsSupported('SORT') : false;
-
- if (0 < \strlen($sSearch))
- {
- $bUseSortIfSupported = false;
- }
-
- $sSearchCriterias = $this->getImapSearchCriterias($sSearch, $sFilter, 0, $bUseCacheAfterSearch);
- if ($bUseCacheAfterSearch && $oCacher && $oCacher->IsInited())
- {
- $sSerializedHash = 'GetUids/'.
- ($bUseSortIfSupported ? 'S': 'N').'/'.
- $this->GenerateImapClientHash().'/'.
- $sFolderName.'/'.$sSearchCriterias;
-
- $sSerializedLog = '"'.$sFolderName.'" / '.$sSearchCriterias.'';
-
- $sSerialized = $oCacher->Get($sSerializedHash);
- if (!empty($sSerialized))
- {
- $aSerialized = @\json_decode($sSerialized, true);
- if (\is_array($aSerialized) && isset($aSerialized['FolderHash'], $aSerialized['Uids']) &&
- $sFolderHash === $aSerialized['FolderHash'] &&
- \is_array($aSerialized['Uids'])
- )
- {
- if ($this->oLogger)
- {
- $this->oLogger->Write('Get Serialized UIDS from cache ('.$sSerializedLog.') [count:'.\count($aSerialized['Uids']).']');
- }
-
- $aResultUids = $aSerialized['Uids'];
- $bUidsFromCacher = true;
- }
- }
- }
-
- if (!\is_array($aResultUids))
- {
- $aResultUids = $bUseSortIfSupported ?
- $this->oImapClient->MessageSimpleSort(array('REVERSE ARRIVAL'), $sSearchCriterias, true) :
- $this->oImapClient->MessageSimpleSearch($sSearchCriterias, true, \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? '' : 'UTF-8')
- ;
-
- if (!$bUidsFromCacher && $bUseCacheAfterSearch && \is_array($aResultUids) && $oCacher && $oCacher->IsInited() && 0 < \strlen($sSerializedHash))
- {
- $oCacher->Set($sSerializedHash, @\json_encode(array(
- 'FolderHash' => $sFolderHash,
- 'Uids' => $aResultUids
- )));
-
- if ($this->oLogger)
- {
- $this->oLogger->Write('Save Serialized UIDS to cache ('.$sSerializedLog.') [count:'.\count($aResultUids).']');
- }
- }
- }
-
- return \is_array($aResultUids) ? $aResultUids : array();
- }
-
- /**
- * @param string $sFolderName
- * @param int $iOffset = 0
- * @param int $iLimit = 10
- * @param string $sSearch = ''
- * @param string $sPrevUidNext = ''
- * @param \MailSo\Cache\CacheClient|null $oCacher = null
- * @param bool $bUseSortIfSupported = false
- * @param bool $bUseThreadSortIfSupported = false
- * @param bool $bUseESearchOrESortRequest = false
- * @param string $sThreadUid = ''
- * @param string $sFilter = ''
- *
- * @return \MailSo\Mail\MessageCollection
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Imap\Exceptions\Exception
- */
- public function MessageList($sFolderName, $iOffset = 0, $iLimit = 10, $sSearch = '', $sPrevUidNext = '', $oCacher = null,
- $bUseSortIfSupported = false, $bUseThreadSortIfSupported = false, $sThreadUid = '', $sFilter = '')
- {
- $sFilter = \trim($sFilter);
- $sSearch = \trim($sSearch);
- if (!\MailSo\Base\Validator::RangeInt($iOffset, 0) ||
- !\MailSo\Base\Validator::RangeInt($iLimit, 0, 999))
- {
- throw new \MailSo\Base\Exceptions\InvalidArgumentException();
- }
-
- $bUseFilter = '' !== $sFilter;
-
- $this->oImapClient->FolderSelect($sFolderName);
-
- $oMessageCollection = MessageCollection::NewInstance();
- $oMessageCollection->FolderName = $sFolderName;
- $oMessageCollection->Offset = $iOffset;
- $oMessageCollection->Limit = $iLimit;
- $oMessageCollection->Search = $sSearch;
- $oMessageCollection->ThreadUid = $sThreadUid;
- $oMessageCollection->Filtered = '' !== \MailSo\Config::$MessageListPermanentFilter;
-
- $aUids = array();
- $mAllSortedUids = null;
- $mAllThreads = null;
-
- $iThreadUid = empty($sThreadUid) ? 0 : (int) $sThreadUid;
-
- $iMessageRealCount = 0;
- $iMessageUnseenCount = 0;
- $sUidNext = '0';
- $sHighestModSeq = '';
-
- $bUseSortIfSupported = $bUseSortIfSupported ? $this->oImapClient->IsSupported('SORT') : false;
-
- $bUseThreadSortIfSupported = $bUseThreadSortIfSupported ?
- ($this->oImapClient->IsSupported('THREAD=REFS') || $this->oImapClient->IsSupported('THREAD=REFERENCES') || $this->oImapClient->IsSupported('THREAD=ORDEREDSUBJECT')) : false;
-
- if (!empty($sThreadUid) && !$bUseThreadSortIfSupported)
- {
- throw new \MailSo\Base\Exceptions\InvalidArgumentException();
- }
-
- if (!$oCacher || !($oCacher instanceof \MailSo\Cache\CacheClient))
- {
- $oCacher = null;
- }
-
- $this->initFolderValues($sFolderName, $iMessageRealCount, $iMessageUnseenCount, $sUidNext, $sHighestModSeq);
-
- if ($bUseFilter)
- {
- $iMessageUnseenCount = 0;
- }
-
- $oMessageCollection->FolderHash = $this->GenerateFolderHash(
- $sFolderName, $iMessageRealCount, $iMessageUnseenCount, $sUidNext, $sHighestModSeq);
-
- $oMessageCollection->UidNext = $sUidNext;
-
- if (empty($sThreadUid) && 0 < \strlen($sPrevUidNext) && 'INBOX' === $sFolderName)
- {
- $oMessageCollection->NewMessages = $this->getFolderNextMessageInformation(
- $sFolderName, $sPrevUidNext, $sUidNext);
- }
-
- $bSearch = false;
- $bMessageListOptimization = 0 < \MailSo\Config::$MessageListCountLimitTrigger &&
- \MailSo\Config::$MessageListCountLimitTrigger < $iMessageRealCount;
-
- if ($bMessageListOptimization)
- {
- $bUseSortIfSupported = false;
- $bUseThreadSortIfSupported = false;
- }
-
- if (0 < $iMessageRealCount && !$bMessageListOptimization)
- {
- $mAllSortedUids = $this->GetUids($oCacher, '', $sFilter,
- $oMessageCollection->FolderName, $oMessageCollection->FolderHash, $bUseSortIfSupported);
-
- $mAllThreads = $bUseThreadSortIfSupported ? $this->MessageListThreadsMap(
- $oMessageCollection->FolderName, $oMessageCollection->FolderHash, $mAllSortedUids, $oCacher) : null;
-
- if ($bUseThreadSortIfSupported && 0 < $iThreadUid && \is_array($mAllThreads))
- {
- $aUids = array();
- $iResultRootUid = 0;
-
- if (isset($mAllThreads[$iThreadUid]))
- {
- $iResultRootUid = $iThreadUid;
- if (\is_array($mAllThreads[$iThreadUid]))
- {
- $aUids = $mAllThreads[$iThreadUid];
- }
- }
- else
- {
- foreach ($mAllThreads as $iRootUid => $mSubUids)
- {
- if (\is_array($mSubUids) && \in_array($iThreadUid, $mSubUids))
- {
- $iResultRootUid = $iRootUid;
- $aUids = $mSubUids;
- continue;
- }
- }
- }
-
- if (0 < $iResultRootUid && \in_array($iResultRootUid, $mAllSortedUids))
- {
- \array_unshift($aUids, $iResultRootUid);
- }
- }
- else if ($bUseThreadSortIfSupported && \is_array($mAllThreads))
- {
- $aUids = \array_keys($mAllThreads);
- }
- else
- {
- $bUseThreadSortIfSupported = false;
- $aUids = $mAllSortedUids;
- }
-
- if (0 < \strlen($sSearch) && \is_array($aUids))
- {
- $aSearchedUids = $this->GetUids($oCacher, $sSearch, $sFilter,
- $oMessageCollection->FolderName, $oMessageCollection->FolderHash);
-
- if (\is_array($aSearchedUids) && 0 < \count($aSearchedUids))
- {
- $aFlippedSearchedUids = \array_flip($aSearchedUids);
-
- $bSearch = true;
- $aNewUids = array();
-
- foreach ($aUids as $iUid)
- {
- if (isset($aFlippedSearchedUids[$iUid]))
- {
- $aNewUids[] = $iUid;
- }
- else if ($bUseThreadSortIfSupported && 0 === $iThreadUid && isset($mAllThreads[$iUid]) && \is_array($mAllThreads[$iUid]))
- {
- foreach ($mAllThreads[$iUid] as $iSubUid)
- {
- if (isset($aFlippedSearchedUids[$iSubUid]))
- {
- $aNewUids[] = $iUid;
- continue;
- }
- }
- }
- }
-
- $aUids = \array_unique($aNewUids);
- unset($aNewUids);
- }
- else
- {
- $aUids = array();
- }
- }
-
- if (\is_array($aUids))
- {
- $oMessageCollection->MessageCount = $iMessageRealCount;
- $oMessageCollection->MessageUnseenCount = $iMessageUnseenCount;
- $oMessageCollection->MessageResultCount = \count($aUids);
-
- if (0 < \count($aUids))
- {
- $aRequestUids = \array_slice($aUids, $iOffset, $iLimit);
- $this->MessageListByRequestIndexOrUids($oMessageCollection, $aRequestUids, true);
- }
- }
- }
- else if (0 < $iMessageRealCount)
- {
- if ($this->oLogger)
- {
- $this->oLogger->Write('List optimization (count: '.$iMessageRealCount.
- ', limit:'.\MailSo\Config::$MessageListCountLimitTrigger.')');
- }
-
- $oMessageCollection->MessageCount = $iMessageRealCount;
- $oMessageCollection->MessageUnseenCount = $iMessageUnseenCount;
-
- if (0 < \strlen($sSearch) || $bUseFilter)
- {
- $aUids = $this->GetUids($oCacher, $sSearch, $sFilter,
- $oMessageCollection->FolderName, $oMessageCollection->FolderHash);
-
- if (0 < \count($aUids))
- {
- $oMessageCollection->MessageResultCount = \count($aUids);
-
- $aRequestUids = \array_slice($aUids, $iOffset, $iLimit);
- $this->MessageListByRequestIndexOrUids($oMessageCollection, $aRequestUids, true);
- }
- else
- {
- $oMessageCollection->MessageResultCount = 0;
- }
- }
- else
- {
- $oMessageCollection->MessageResultCount = $iMessageRealCount;
-
- if (1 < $iMessageRealCount)
- {
- $aRequestIndexes = \array_slice(array_reverse(range(1, $iMessageRealCount)), $iOffset, $iLimit);
- }
- else
- {
- $aRequestIndexes = \array_slice(array(1), $iOffset, $iLimit);
- }
-
- $this->MessageListByRequestIndexOrUids($oMessageCollection, $aRequestIndexes, false);
- }
- }
-
- if ($bUseThreadSortIfSupported && 0 === $iThreadUid && \is_array($mAllThreads) && 0 < \count($mAllThreads))
- {
- $oMessageCollection->ForeachList(function (/* @var $oMessage \MailSo\Mail\Message */ $oMessage) use ($mAllThreads) {
-
- $iUid = $oMessage->Uid();
- if (isset($mAllThreads[$iUid]) && \is_array($mAllThreads[$iUid]) && 0 < \count($mAllThreads[$iUid]))
- {
- $aSubThreads = $mAllThreads[$iUid];
- \array_unshift($aSubThreads, $iUid);
-
- $oMessage->SetThreads(\array_map('trim', $aSubThreads));
- unset($aSubThreads);
- }
- });
- }
-
- return $oMessageCollection;
- }
-
- /**
- * @return array|false
- */
- public function Quota()
- {
- return $this->oImapClient->Quota();
- }
-
- /**
- * @param string $sFolderName
- * @param string $sMessageId
- *
- * @return int|null
- */
- public function FindMessageUidByMessageId($sFolderName, $sMessageId)
- {
- if (0 === \strlen($sMessageId))
- {
- throw new \MailSo\Base\Exceptions\InvalidArgumentException();
- }
-
- $this->oImapClient->FolderExamine($sFolderName);
-
- $aUids = $this->oImapClient->MessageSimpleSearch(
- 'HEADER Message-ID '.$sMessageId, true);
-
- return \is_array($aUids) && 1 === \count($aUids) && \is_numeric($aUids[0]) ? (int) $aUids[0] : null;
- }
-
- /**
- * @param array $aMailFoldersHelper
- * @param int $iOptimizationLimit = 0
- *
- * @return array
- */
- public function folderListOptimization($aMailFoldersHelper, $iOptimizationLimit = 0)
- {
- // optimization
- if (10 < $iOptimizationLimit && \is_array($aMailFoldersHelper) && $iOptimizationLimit < \count($aMailFoldersHelper))
- {
- if ($this->oLogger)
- {
- $this->oLogger->Write('Start optimization (limit:'.$iOptimizationLimit.') for '.\count($aMailFoldersHelper).' folders');
- }
-
- $iForeachLimit = 1;
-
- $aFilteredNames = array(
- 'inbox',
- 'sent', 'send', 'outbox', 'sentmail', 'sendmail',
- 'drafts', 'draft',
- 'junk', 'spam', 'spambucket',
- 'trash', 'bin', 'deleted',
- 'archives', 'archive', 'allmail', 'all',
- 'starred', 'flagged', 'important',
- 'contacts', 'chats'
- );
-
- $aNewMailFoldersHelper = array();
-
- $iCountLimit = $iForeachLimit;
-
- foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder)
- {
- // mandatory folders
- if ($oFolder && \in_array(\str_replace(' ', '', \strtolower($oFolder->NameRaw())), $aFilteredNames))
- {
- $aNewMailFoldersHelper[] = $oFolder;
- $aMailFoldersHelper[$iIndex] = null;
- }
- }
-
- foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder)
- {
- // subscribed folders
- if ($oFolder && $oFolder->IsSubscribed())
- {
- $aNewMailFoldersHelper[] = $oFolder;
-
- $aMailFoldersHelper[$iIndex] = null;
- $iCountLimit--;
- }
-
- if (0 > $iCountLimit)
- {
- if ($iOptimizationLimit < \count($aNewMailFoldersHelper))
- {
- break;
- }
- else
- {
- $iCountLimit = $iForeachLimit;
- }
- }
- }
-
- $iCountLimit = $iForeachLimit;
- if ($iOptimizationLimit >= \count($aNewMailFoldersHelper))
- {
- // name filter
- foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder)
- {
- if ($oFolder && !\preg_match('/[{}\[\]]/', $oFolder->NameRaw()))
- {
- $aNewMailFoldersHelper[] = $oFolder;
-
- $aMailFoldersHelper[$iIndex] = null;
- $iCountLimit--;
- }
-
- if (0 > $iCountLimit)
- {
- if ($iOptimizationLimit < \count($aNewMailFoldersHelper))
- {
- break;
- }
- else
- {
- $iCountLimit = $iForeachLimit;
- }
- }
- }
- }
-
- $iCountLimit = $iForeachLimit;
- if ($iOptimizationLimit >= \count($aNewMailFoldersHelper))
- {
- // other
- foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder)
- {
- if ($oFolder)
- {
- $aNewMailFoldersHelper[] = $oFolder;
-
- $aMailFoldersHelper[$iIndex] = null;
- $iCountLimit--;
- }
-
- if (0 > $iCountLimit)
- {
- if ($iOptimizationLimit < \count($aNewMailFoldersHelper))
- {
- break;
- }
- else
- {
- $iCountLimit = $iForeachLimit;
- }
- }
- }
- }
-
- $aMailFoldersHelper = $aNewMailFoldersHelper;
-
- if ($this->oLogger)
- {
- $this->oLogger->Write('Result optimization: '.\count($aMailFoldersHelper).' folders');
- }
- }
-
- return $aMailFoldersHelper;
- }
-
- /**
- * @param string $sParent = ''
- * @param string $sListPattern = '*'
- * @param bool $bUseListSubscribeStatus = false
- * @param int $iOptimizationLimit = 0
- *
- * @return \MailSo\Mail\FolderCollection|false
- */
- public function Folders($sParent = '', $sListPattern = '*', $bUseListSubscribeStatus = true, $iOptimizationLimit = 0)
- {
- $oFolderCollection = false;
-
- $aSubscribedFolders = null;
- if ($bUseListSubscribeStatus)
- {
- try
- {
- $aSubscribedFolders = $this->oImapClient->FolderSubscribeList($sParent, $sListPattern);
- }
- catch (\Exception $oException)
- {
- unset($oException);
- }
- }
-
- $aImapSubscribedFoldersHelper = null;
- if (\is_array($aSubscribedFolders))
- {
- $aImapSubscribedFoldersHelper = array();
- foreach ($aSubscribedFolders as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder)
- {
- $aImapSubscribedFoldersHelper[] = $oImapFolder->FullNameRaw();
- }
- }
-
- $aFolders = $this->oImapClient->FolderList($sParent, $sListPattern);
-
- $bOptimized = false;
- $aMailFoldersHelper = null;
-
- if (\is_array($aFolders))
- {
- $aMailFoldersHelper = array();
-
- foreach ($aFolders as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder)
- {
- $aMailFoldersHelper[] = Folder::NewInstance($oImapFolder,
- (null === $aImapSubscribedFoldersHelper || \in_array($oImapFolder->FullNameRaw(), $aImapSubscribedFoldersHelper)) ||
- $oImapFolder->IsInbox()
- );
- }
-
- $iCount = \count($aMailFoldersHelper);
- $aMailFoldersHelper = $this->folderListOptimization($aMailFoldersHelper, $iOptimizationLimit);
-
- $bOptimized = $iCount !== \count($aMailFoldersHelper);
- }
-
- if (\is_array($aMailFoldersHelper))
- {
- $oFolderCollection = FolderCollection::NewInstance();
- $oFolderCollection->InitByUnsortedMailFolderArray($aMailFoldersHelper);
-
- $oFolderCollection->Optimized = $bOptimized;
- }
-
- if ($oFolderCollection)
- {
- $oFolderCollection->SortByCallback(function ($oFolderA, $oFolderB) {
- $sA = \strtoupper($oFolderA->FullNameRaw());
- $sB = \strtoupper($oFolderB->FullNameRaw());
- switch (true)
- {
- case 'INBOX' === $sA:
- return -1;
- case 'INBOX' === $sB:
- return 1;
- case '[GMAIL]' === $sA:
- return -1;
- case '[GMAIL]' === $sB:
- return 1;
- }
-
- return \strnatcasecmp($oFolderA->FullName(), $oFolderB->FullName());
- });
-
- $oNamespace = $this->oImapClient->GetNamespace();
- if ($oNamespace)
- {
- $oFolderCollection->SetNamespace($oNamespace->GetPersonalNamespace());
- }
-
- $oFolderCollection->IsThreadsSupported = $this->IsThreadsSupported();
- }
-
- return $oFolderCollection;
- }
-
- /**
- * @param string $sFolderNameInUtf8
- * @param string $sFolderParentFullNameRaw = ''
- * @param bool $bSubscribeOnCreation = true
- * @param string $sDelimiter = ''
- *
- * @return \MailSo\Mail\MailClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- */
- public function FolderCreate($sFolderNameInUtf8, $sFolderParentFullNameRaw = '', $bSubscribeOnCreation = true, $sDelimiter = '')
- {
- if (!\MailSo\Base\Validator::NotEmptyString($sFolderNameInUtf8, true) ||
- !\is_string($sFolderParentFullNameRaw))
- {
- throw new \MailSo\Base\Exceptions\InvalidArgumentException();
- }
-
- $sFolderNameInUtf8 = \trim($sFolderNameInUtf8);
-
- if (0 === \strlen($sDelimiter) || 0 < \strlen(\trim($sFolderParentFullNameRaw)))
- {
- $aFolders = $this->oImapClient->FolderList('', 0 === \strlen(\trim($sFolderParentFullNameRaw)) ? 'INBOX' : $sFolderParentFullNameRaw);
- if (!\is_array($aFolders) || !isset($aFolders[0]))
- {
- // TODO
- throw new \MailSo\Mail\Exceptions\RuntimeException(
- 0 === \strlen(trim($sFolderParentFullNameRaw))
- ? 'Cannot get folder delimiter'
- : 'Cannot create folder in non-existen parent folder');
- }
-
- $sDelimiter = $aFolders[0]->Delimiter();
- if (0 < \strlen($sDelimiter) && 0 < \strlen(\trim($sFolderParentFullNameRaw)))
- {
- $sFolderParentFullNameRaw .= $sDelimiter;
- }
- }
-
- $sFullNameRawToCreate = \MailSo\Base\Utils::ConvertEncoding($sFolderNameInUtf8,
- \MailSo\Base\Enumerations\Charset::UTF_8,
- \MailSo\Base\Enumerations\Charset::UTF_7_IMAP);
-
- if (0 < \strlen($sDelimiter) && false !== \strpos($sFullNameRawToCreate, $sDelimiter))
- {
- // TODO
- throw new \MailSo\Mail\Exceptions\RuntimeException(
- 'New folder name contains delimiter');
- }
-
- $sFullNameRawToCreate = $sFolderParentFullNameRaw.$sFullNameRawToCreate;
-
- $this->oImapClient->FolderCreate($sFullNameRawToCreate);
-
- if ($bSubscribeOnCreation)
- {
- $this->oImapClient->FolderSubscribe($sFullNameRawToCreate);
- }
-
- return $this;
- }
-
- /**
- * @param string $sPrevFolderFullNameRaw
- * @param string $sNextFolderFullNameInUtf
- * @param bool $bSubscribeOnMove = true
- *
- * @return \MailSo\Mail\MailClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- */
- public function FolderMove($sPrevFolderFullNameRaw, $sNextFolderFullNameInUtf, $bSubscribeOnMove = true)
- {
- return $this->folderModify($sPrevFolderFullNameRaw, $sNextFolderFullNameInUtf, false, $bSubscribeOnMove);
- }
-
- /**
- * @param string $sPrevFolderFullNameRaw
- * @param string $sNewTopFolderNameInUtf
- * @param bool $bSubscribeOnRename = true
- *
- * @return \MailSo\Mail\MailClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- */
- public function FolderRename($sPrevFolderFullNameRaw, $sNewTopFolderNameInUtf, $bSubscribeOnRename = true)
- {
- return $this->folderModify($sPrevFolderFullNameRaw, $sNewTopFolderNameInUtf, true, $bSubscribeOnRename);
- }
-
- /**
- * @param string $sPrevFolderFullNameRaw
- * @param string $sNextFolderNameInUtf
- * @param bool $bRenameOrMove
- * @param bool $bSubscribeOnModify
- *
- * @return \MailSo\Mail\MailClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- */
- public function folderModify($sPrevFolderFullNameRaw, $sNextFolderNameInUtf, $bRenameOrMove, $bSubscribeOnModify)
- {
- if (0 === \strlen($sPrevFolderFullNameRaw) || 0 === \strlen($sNextFolderNameInUtf))
- {
- throw new \MailSo\Base\Exceptions\InvalidArgumentException();
- }
-
- $aFolders = $this->oImapClient->FolderList('', $sPrevFolderFullNameRaw);
- if (!\is_array($aFolders) || !isset($aFolders[0]))
- {
- // TODO
- throw new \MailSo\Mail\Exceptions\RuntimeException('Cannot rename non-existen folder');
- }
-
- $sDelimiter = $aFolders[0]->Delimiter();
- $iLast = \strrpos($sPrevFolderFullNameRaw, $sDelimiter);
-
- $mSubscribeFolders = null;
- if ($bSubscribeOnModify)
- {
- $mSubscribeFolders = $this->oImapClient->FolderSubscribeList($sPrevFolderFullNameRaw, '*');
- if (\is_array($mSubscribeFolders) && 0 < count($mSubscribeFolders))
- {
- foreach ($mSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder)
- {
- $this->oImapClient->FolderUnSubscribe($oFolder->FullNameRaw());
- }
- }
- }
-
- $sNewFolderFullNameRaw = \MailSo\Base\Utils::ConvertEncoding($sNextFolderNameInUtf,
- \MailSo\Base\Enumerations\Charset::UTF_8,
- \MailSo\Base\Enumerations\Charset::UTF_7_IMAP);
-
- if($bRenameOrMove)
- {
- if (0 < \strlen($sDelimiter) && false !== \strpos($sNewFolderFullNameRaw, $sDelimiter))
- {
- // TODO
- throw new \MailSo\Mail\Exceptions\RuntimeException('New folder name contains delimiter');
- }
-
- $sFolderParentFullNameRaw = false === $iLast ? '' : \substr($sPrevFolderFullNameRaw, 0, $iLast + 1);
- $sNewFolderFullNameRaw = $sFolderParentFullNameRaw.$sNewFolderFullNameRaw;
- }
-
- $this->oImapClient->FolderRename($sPrevFolderFullNameRaw, $sNewFolderFullNameRaw);
-
- if (\is_array($mSubscribeFolders) && 0 < count($mSubscribeFolders))
- {
- foreach ($mSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder)
- {
- $sFolderFullNameRawForResubscrine = $oFolder->FullNameRaw();
- if (0 === \strpos($sFolderFullNameRawForResubscrine, $sPrevFolderFullNameRaw))
- {
- $sNewFolderFullNameRawForResubscrine = $sNewFolderFullNameRaw.
- \substr($sFolderFullNameRawForResubscrine, \strlen($sPrevFolderFullNameRaw));
-
- $this->oImapClient->FolderSubscribe($sNewFolderFullNameRawForResubscrine);
- }
- }
- }
-
- return $this;
- }
-
- /**
- * @param string $sFolderFullNameRaw
- * @param bool $bUnsubscribeOnDeletion = true
- *
- * @return \MailSo\Mail\MailClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Mail\Exceptions\RuntimeException
- */
- public function FolderDelete($sFolderFullNameRaw, $bUnsubscribeOnDeletion = true)
- {
- if (0 === \strlen($sFolderFullNameRaw) || 'INBOX' === $sFolderFullNameRaw)
- {
- throw new \MailSo\Base\Exceptions\InvalidArgumentException();
- }
-
- $this->oImapClient->FolderExamine($sFolderFullNameRaw);
-
- $aIndexOrUids = $this->oImapClient->MessageSimpleSearch('ALL');
- if (0 < \count($aIndexOrUids))
- {
- throw new \MailSo\Mail\Exceptions\NonEmptyFolder();
- }
-
- $this->oImapClient->FolderExamine('INBOX');
-
- if ($bUnsubscribeOnDeletion)
- {
- $this->oImapClient->FolderUnSubscribe($sFolderFullNameRaw);
- }
-
- $this->oImapClient->FolderDelete($sFolderFullNameRaw);
-
- return $this;
- }
-
- /**
- * @param string $sFolderFullNameRaw
- *
- * @return \MailSo\Mail\MailClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- */
- public function FolderClear($sFolderFullNameRaw)
- {
- $this->oImapClient->FolderSelect($sFolderFullNameRaw);
-
- $oFolderInformation = $this->oImapClient->FolderCurrentInformation();
- if ($oFolderInformation && $oFolderInformation->Exists && 0 < $oFolderInformation->Exists) // STATUS?
- {
- $this->oImapClient->MessageStoreFlag('1:*', false,
- array(\MailSo\Imap\Enumerations\MessageFlag::DELETED),
- \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT
- );
-
- $this->oImapClient->MessageExpunge();
- }
-
- return $this;
- }
-
- /**
- * @param string $sFolderFullNameRaw
- * @param bool $bSubscribe
- *
- * @return \MailSo\Mail\MailClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- */
- public function FolderSubscribe($sFolderFullNameRaw, $bSubscribe)
- {
- if (0 === \strlen($sFolderFullNameRaw))
- {
- throw new \MailSo\Base\Exceptions\InvalidArgumentException();
- }
-
- $this->oImapClient->{($bSubscribe) ? 'FolderSubscribe' : 'FolderUnSubscribe'}($sFolderFullNameRaw);
-
- return $this;
- }
-
- /**
- * @param \MailSo\Log\Logger $oLogger
- *
- * @return \MailSo\Mail\MailClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- */
- public function SetLogger($oLogger)
- {
- if (!($oLogger instanceof \MailSo\Log\Logger))
- {
- throw new \MailSo\Base\Exceptions\InvalidArgumentException();
- }
-
- $this->oLogger = $oLogger;
- $this->oImapClient->SetLogger($this->oLogger);
-
- return $this;
- }
-}
+oLogger = null;
+
+ $this->oImapClient = \MailSo\Imap\ImapClient::NewInstance();
+ $this->oImapClient->SetTimeOuts(10, \MailSo\Config::$ImapTimeout);
+ }
+
+ /**
+ * @return \MailSo\Mail\MailClient
+ */
+ public static function NewInstance()
+ {
+ return new self();
+ }
+
+ /**
+ * @return \MailSo\Imap\ImapClient
+ */
+ public function ImapClient()
+ {
+ return $this->oImapClient;
+ }
+
+ /**
+ * @param string $sServerName
+ * @param int $iPort = 143
+ * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT
+ * @param bool $bVerifySsl = false
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function Connect($sServerName, $iPort = 143,
+ $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, $bVerifySsl = false)
+ {
+ $this->oImapClient->Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl);
+ return $this;
+ }
+
+ /**
+ * @param string $sLogin
+ * @param string $sPassword
+ * @param string $sProxyAuthUser = ''
+ * @param bool $bUseAuthPlainIfSupported = true
+ * @param bool $bUseAuthCramMd5IfSupported = true
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\LoginException
+ */
+ public function Login($sLogin, $sPassword, $sProxyAuthUser = '',
+ $bUseAuthPlainIfSupported = true, $bUseAuthCramMd5IfSupported = true)
+ {
+ $this->oImapClient->Login($sLogin, $sPassword, $sProxyAuthUser, $bUseAuthPlainIfSupported, $bUseAuthCramMd5IfSupported);
+ return $this;
+ }
+
+ /**
+ * @param string $sXOAuth2Token
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\LoginException
+ */
+ public function LoginWithXOauth2($sXOAuth2Token)
+ {
+ $this->oImapClient->LoginWithXOauth2($sXOAuth2Token);
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ public function Logout()
+ {
+ $this->oImapClient->Logout();
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ public function Disconnect()
+ {
+ $this->oImapClient->Disconnect();
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ public function LogoutAndDisconnect()
+ {
+ return $this->Logout()->Disconnect();
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsConnected()
+ {
+ return $this->oImapClient->IsConnected();
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsLoggined()
+ {
+ return $this->oImapClient->IsLoggined();
+ }
+
+ /**
+ * @return string
+ */
+ private function getEnvelopeOrHeadersRequestStringForSimpleList()
+ {
+ return \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array(
+ \MailSo\Mime\Enumerations\Header::RETURN_PATH,
+ \MailSo\Mime\Enumerations\Header::RECEIVED,
+ \MailSo\Mime\Enumerations\Header::MIME_VERSION,
+ \MailSo\Mime\Enumerations\Header::FROM_,
+ \MailSo\Mime\Enumerations\Header::TO_,
+ \MailSo\Mime\Enumerations\Header::CC,
+ \MailSo\Mime\Enumerations\Header::SENDER,
+ \MailSo\Mime\Enumerations\Header::REPLY_TO,
+ \MailSo\Mime\Enumerations\Header::DATE,
+ \MailSo\Mime\Enumerations\Header::SUBJECT,
+ \MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
+ \MailSo\Mime\Enumerations\Header::LIST_UNSUBSCRIBE,
+ ), true);
+ }
+
+ /**
+ * @return string
+ */
+ private function getEnvelopeOrHeadersRequestString()
+ {
+ if (\MailSo\Config::$MessageAllHeaders)
+ {
+ return \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK;
+ }
+
+ return \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array(
+ \MailSo\Mime\Enumerations\Header::RETURN_PATH,
+ \MailSo\Mime\Enumerations\Header::RECEIVED,
+ \MailSo\Mime\Enumerations\Header::MIME_VERSION,
+ \MailSo\Mime\Enumerations\Header::MESSAGE_ID,
+ \MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
+ \MailSo\Mime\Enumerations\Header::FROM_,
+ \MailSo\Mime\Enumerations\Header::TO_,
+ \MailSo\Mime\Enumerations\Header::CC,
+ \MailSo\Mime\Enumerations\Header::BCC,
+ \MailSo\Mime\Enumerations\Header::SENDER,
+ \MailSo\Mime\Enumerations\Header::REPLY_TO,
+ \MailSo\Mime\Enumerations\Header::DELIVERED_TO,
+ \MailSo\Mime\Enumerations\Header::IN_REPLY_TO,
+ \MailSo\Mime\Enumerations\Header::REFERENCES,
+ \MailSo\Mime\Enumerations\Header::DATE,
+ \MailSo\Mime\Enumerations\Header::SUBJECT,
+ \MailSo\Mime\Enumerations\Header::SENSITIVITY,
+ \MailSo\Mime\Enumerations\Header::X_MSMAIL_PRIORITY,
+ \MailSo\Mime\Enumerations\Header::IMPORTANCE,
+ \MailSo\Mime\Enumerations\Header::X_PRIORITY,
+ \MailSo\Mime\Enumerations\Header::X_DRAFT_INFO,
+ \MailSo\Mime\Enumerations\Header::RETURN_RECEIPT_TO,
+ \MailSo\Mime\Enumerations\Header::DISPOSITION_NOTIFICATION_TO,
+ \MailSo\Mime\Enumerations\Header::X_CONFIRM_READING_TO,
+ \MailSo\Mime\Enumerations\Header::AUTHENTICATION_RESULTS,
+ \MailSo\Mime\Enumerations\Header::X_DKIM_AUTHENTICATION_RESULTS,
+ \MailSo\Mime\Enumerations\Header::LIST_UNSUBSCRIBE,
+ ), true);
+//
+// return \MailSo\Imap\Enumerations\FetchType::ENVELOPE;
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param string $sMessageFlag
+ * @param bool $bSetAction = true
+ * @param bool $sSkipUnsupportedFlag = false
+ * @param array $aCustomUids = null
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ * @throws \MailSo\Mail\Exceptions\Exception
+ */
+ public function MessageSetFlagToAll($sFolderName, $sMessageFlag, $bSetAction = true, $sSkipUnsupportedFlag = false, $aCustomUids = null)
+ {
+ $this->oImapClient->FolderSelect($sFolderName);
+
+ $oFolderInfo = $this->oImapClient->FolderCurrentInformation();
+ if (!$oFolderInfo || !$oFolderInfo->IsFlagSupported($sMessageFlag))
+ {
+ if (!$sSkipUnsupportedFlag)
+ {
+ throw new \MailSo\Mail\Exceptions\RuntimeException('Message flag "'.$sMessageFlag.'" is not supported.');
+ }
+ }
+
+ if ($oFolderInfo && 0 < $oFolderInfo->Exists)
+ {
+ $sStoreAction = $bSetAction
+ ? \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT
+ : \MailSo\Imap\Enumerations\StoreAction::REMOVE_FLAGS_SILENT
+ ;
+
+ if (is_array($aCustomUids))
+ {
+ if (0 < count($aCustomUids))
+ {
+ $this->oImapClient->MessageStoreFlag(implode(',', $aCustomUids), true, array($sMessageFlag), $sStoreAction);
+ }
+ }
+ else
+ {
+ $this->oImapClient->MessageStoreFlag('1:*', false, array($sMessageFlag), $sStoreAction);
+ }
+ }
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param array $aIndexRange
+ * @param bool $bIndexIsUid
+ * @param string $sMessageFlag
+ * @param bool $bSetAction = true
+ * @param bool $sSkipUnsupportedFlag = false
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ * @throws \MailSo\Mail\Exceptions\Exception
+ */
+ public function MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid, $sMessageFlag, $bSetAction = true, $sSkipUnsupportedFlag = false)
+ {
+ $this->oImapClient->FolderSelect($sFolderName);
+
+ $oFolderInfo = $this->oImapClient->FolderCurrentInformation();
+ if (!$oFolderInfo || !$oFolderInfo->IsFlagSupported($sMessageFlag))
+ {
+ if (!$sSkipUnsupportedFlag)
+ {
+ throw new \MailSo\Mail\Exceptions\RuntimeException('Message flag "'.$sMessageFlag.'" is not supported.');
+ }
+ }
+ else
+ {
+ $sStoreAction = $bSetAction
+ ? \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT
+ : \MailSo\Imap\Enumerations\StoreAction::REMOVE_FLAGS_SILENT
+ ;
+
+ $this->oImapClient->MessageStoreFlag(\MailSo\Base\Utils::PrepearFetchSequence($aIndexRange),
+ $bIndexIsUid, array($sMessageFlag), $sStoreAction);
+ }
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param array $aIndexRange
+ * @param bool $bIndexIsUid
+ * @param bool $bSetAction = true
+ * @param bool $sSkipUnsupportedFlag = false
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageSetFlagged($sFolderName, $aIndexRange, $bIndexIsUid, $bSetAction = true, $sSkipUnsupportedFlag = false)
+ {
+ $this->MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid,
+ \MailSo\Imap\Enumerations\MessageFlag::FLAGGED, $bSetAction, $sSkipUnsupportedFlag);
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param bool $bSetAction = true
+ * @param array $aCustomUids = null
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageSetSeenToAll($sFolderName, $bSetAction = true, $aCustomUids = null)
+ {
+ $this->MessageSetFlagToAll($sFolderName, \MailSo\Imap\Enumerations\MessageFlag::SEEN, $bSetAction, true, $aCustomUids);
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param array $aIndexRange
+ * @param bool $bIndexIsUid
+ * @param bool $bSetAction = true
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageSetSeen($sFolderName, $aIndexRange, $bIndexIsUid, $bSetAction = true)
+ {
+ $this->MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid,
+ \MailSo\Imap\Enumerations\MessageFlag::SEEN, $bSetAction, true);
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param int $iIndex
+ * @param bool $bIndexIsUid = true
+ * @param \MailSo\Cache\CacheClient $oCacher = null
+ * @param int $iBodyTextLimit = null
+ *
+ * @return \MailSo\Mail\Message|false
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function Message($sFolderName, $iIndex, $bIndexIsUid = true, $oCacher = null, $iBodyTextLimit = null)
+ {
+ if (!\MailSo\Base\Validator::RangeInt($iIndex, 1))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oImapClient->FolderSelect($sFolderName);
+
+ $oBodyStructure = null;
+ $oMessage = false;
+
+ $aBodyPeekMimeIndexes = array();
+ $aSignatureMimeIndexes = array();
+
+ $aFetchResponse = $this->oImapClient->Fetch(array(\MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE), $iIndex, $bIndexIsUid);
+ if (0 < \count($aFetchResponse) && isset($aFetchResponse[0]))
+ {
+ $oBodyStructure = $aFetchResponse[0]->GetFetchBodyStructure();
+ if ($oBodyStructure)
+ {
+ $aTextParts = $oBodyStructure->SearchHtmlOrPlainParts();
+ if (is_array($aTextParts) && 0 < \count($aTextParts))
+ {
+ foreach ($aTextParts as $oPart)
+ {
+ $aBodyPeekMimeIndexes[] = array($oPart->PartID(), $oPart->Size());
+ }
+ }
+
+ $aSignatureParts = $oBodyStructure->SearchByContentType('application/pgp-signature');
+ if (is_array($aSignatureParts) && 0 < \count($aSignatureParts))
+ {
+ foreach ($aSignatureParts as $oPart)
+ {
+ $aSignatureMimeIndexes[] = $oPart->PartID();
+ }
+ }
+ }
+ }
+
+ $aFetchItems = array(
+ \MailSo\Imap\Enumerations\FetchType::INDEX,
+ \MailSo\Imap\Enumerations\FetchType::UID,
+ \MailSo\Imap\Enumerations\FetchType::RFC822_SIZE,
+ \MailSo\Imap\Enumerations\FetchType::INTERNALDATE,
+ \MailSo\Imap\Enumerations\FetchType::FLAGS,
+ $this->getEnvelopeOrHeadersRequestString()
+ );
+
+ if (0 < \count($aBodyPeekMimeIndexes))
+ {
+ foreach ($aBodyPeekMimeIndexes as $aTextMimeData)
+ {
+ $sLine = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$aTextMimeData[0].']';
+ if (\is_numeric($iBodyTextLimit) && 0 < $iBodyTextLimit && $iBodyTextLimit < $aTextMimeData[1])
+ {
+ $sLine .= '<0.'.((int) $iBodyTextLimit).'>';
+ }
+
+ $aFetchItems[] = $sLine;
+ }
+ }
+
+ if (0 < \count($aSignatureMimeIndexes))
+ {
+ foreach ($aSignatureMimeIndexes as $sTextMimeIndex)
+ {
+ $aFetchItems[] = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sTextMimeIndex.']';
+ }
+ }
+
+ if (!$oBodyStructure)
+ {
+ $aFetchItems[] = \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE;
+ }
+
+ $aFetchResponse = $this->oImapClient->Fetch($aFetchItems, $iIndex, $bIndexIsUid);
+ if (0 < \count($aFetchResponse))
+ {
+ $oMessage = \MailSo\Mail\Message::NewFetchResponseInstance(
+ $sFolderName, $aFetchResponse[0], $oBodyStructure);
+ }
+
+ return $oMessage;
+ }
+
+ /**
+ * @param mixed $mCallback
+ * @param string $sFolderName
+ * @param int $iIndex
+ * @param bool $bIndexIsUid = true,
+ * @param string $sMimeIndex = ''
+ *
+ * @return bool
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageMimeStream($mCallback, $sFolderName, $iIndex, $bIndexIsUid = true, $sMimeIndex = '')
+ {
+ if (!is_callable($mCallback))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oImapClient->FolderSelect($sFolderName);
+
+ $sFileName = '';
+ $sContentType = '';
+ $sMailEncodingName = '';
+
+ $sMimeIndex = trim($sMimeIndex);
+ $aFetchResponse = $this->oImapClient->Fetch(array(
+ 0 === \strlen($sMimeIndex)
+ ? \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK
+ : \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sMimeIndex.'.MIME]'
+ ), $iIndex, $bIndexIsUid);
+
+ if (0 < \count($aFetchResponse))
+ {
+ $sMime = $aFetchResponse[0]->GetFetchValue(
+ 0 === \strlen($sMimeIndex)
+ ? \MailSo\Imap\Enumerations\FetchType::BODY_HEADER
+ : \MailSo\Imap\Enumerations\FetchType::BODY.'['.$sMimeIndex.'.MIME]'
+ );
+
+ if (0 < \strlen($sMime))
+ {
+ $oHeaders = \MailSo\Mime\HeaderCollection::NewInstance()->Parse($sMime);
+
+ if (0 < \strlen($sMimeIndex))
+ {
+ $sFileName = $oHeaders->ParameterValue(
+ \MailSo\Mime\Enumerations\Header::CONTENT_DISPOSITION,
+ \MailSo\Mime\Enumerations\Parameter::FILENAME);
+
+ if (0 === \strlen($sFileName))
+ {
+ $sFileName = $oHeaders->ParameterValue(
+ \MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
+ \MailSo\Mime\Enumerations\Parameter::NAME);
+ }
+
+ $sMailEncodingName = $oHeaders->ValueByName(
+ \MailSo\Mime\Enumerations\Header::CONTENT_TRANSFER_ENCODING);
+
+ $sContentType = $oHeaders->ValueByName(
+ \MailSo\Mime\Enumerations\Header::CONTENT_TYPE);
+ }
+ else
+ {
+ $sSubject = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::SUBJECT);
+
+ $sFileName = 0 === \strlen($sSubject) ? (string) $iIndex : $sSubject;
+ $sFileName .= '.eml';
+
+ $sContentType = 'message/rfc822';
+ }
+ }
+ }
+
+ $aFetchResponse = $this->oImapClient->Fetch(array(
+ array(\MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sMimeIndex.']',
+ function ($sParent, $sLiteralAtomUpperCase, $rImapLiteralStream) use ($mCallback, $sMimeIndex, $sMailEncodingName, $sContentType, $sFileName)
+ {
+ if (0 < \strlen($sLiteralAtomUpperCase))
+ {
+ if (is_resource($rImapLiteralStream) && 'FETCH' === $sParent)
+ {
+ $rMessageMimeIndexStream = (0 === \strlen($sMailEncodingName))
+ ? $rImapLiteralStream
+ : \MailSo\Base\StreamWrappers\Binary::CreateStream($rImapLiteralStream,
+ \MailSo\Base\StreamWrappers\Binary::GetInlineDecodeOrEncodeFunctionName(
+ $sMailEncodingName, true));
+
+ \call_user_func($mCallback, $rMessageMimeIndexStream, $sContentType, $sFileName, $sMimeIndex);
+ }
+ }
+ }
+ )), $iIndex, $bIndexIsUid);
+
+ return ($aFetchResponse && 1 === \count($aFetchResponse));
+ }
+
+ /**
+ * @param string $sFolder
+ * @param array $aIndexRange
+ * @param bool $bIndexIsUid
+ * @param bool $bUseExpunge = true
+ * @param bool $bExpungeAll = false
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageDelete($sFolder, $aIndexRange, $bIndexIsUid, $bUseExpunge = true, $bExpungeAll = false)
+ {
+ if (0 === \strlen($sFolder) || !\is_array($aIndexRange) || 0 === \count($aIndexRange))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oImapClient->FolderSelect($sFolder);
+
+ $sIndexRange = \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange);
+
+ $this->oImapClient->MessageStoreFlag($sIndexRange, $bIndexIsUid,
+ array(\MailSo\Imap\Enumerations\MessageFlag::DELETED),
+ \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT
+ );
+
+ if ($bUseExpunge)
+ {
+ $this->oImapClient->MessageExpunge($bIndexIsUid ? $sIndexRange : '', $bIndexIsUid, $bExpungeAll);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sFromFolder
+ * @param string $sToFolder
+ * @param array $aIndexRange
+ * @param bool $bIndexIsUid
+ * @param bool $bUseMoveSupported = false
+ * @param bool $bExpungeAll = false
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageMove($sFromFolder, $sToFolder, $aIndexRange, $bIndexIsUid, $bUseMoveSupported = false, $bExpungeAll = false)
+ {
+ if (0 === \strlen($sFromFolder) || 0 === \strlen($sToFolder) ||
+ !\is_array($aIndexRange) || 0 === \count($aIndexRange))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oImapClient->FolderSelect($sFromFolder);
+
+ if ($bUseMoveSupported && $this->oImapClient->IsSupported('MOVE'))
+ {
+ $this->oImapClient->MessageMove($sToFolder,
+ \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), $bIndexIsUid);
+ }
+ else
+ {
+ $this->oImapClient->MessageCopy($sToFolder,
+ \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), $bIndexIsUid);
+
+ $this->MessageDelete($sFromFolder, $aIndexRange, $bIndexIsUid, true, $bExpungeAll);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sFromFolder
+ * @param string $sToFolder
+ * @param array $aIndexRange
+ * @param bool $bIndexIsUid
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageCopy($sFromFolder, $sToFolder, $aIndexRange, $bIndexIsUid)
+ {
+ if (0 === \strlen($sFromFolder) || 0 === \strlen($sToFolder) ||
+ !\is_array($aIndexRange) || 0 === \count($aIndexRange))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oImapClient->FolderSelect($sFromFolder);
+ $this->oImapClient->MessageCopy($sToFolder,
+ \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), $bIndexIsUid);
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderUnSelect()
+ {
+ if ($this->oImapClient->IsSelected())
+ {
+ $this->oImapClient->FolderUnSelect();
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param resource $rMessageStream
+ * @param int $iMessageStreamSize
+ * @param string $sFolderToSave
+ * @param array $aAppendFlags = null
+ * @param int $iUid = null
+ *
+ * @return \MailSo\Mail\MailClient
+ */
+ public function MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderToSave, $aAppendFlags = null, &$iUid = null)
+ {
+ if (!\is_resource($rMessageStream) || 0 === \strlen($sFolderToSave))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oImapClient->MessageAppendStream(
+ $sFolderToSave, $rMessageStream, $iMessageStreamSize, $aAppendFlags, $iUid);
+
+ return $this;
+ }
+
+ /**
+ * @param string $sMessageFileName
+ * @param string $sFolderToSave
+ * @param array $aAppendFlags = null
+ * @param int &$iUid = null
+ *
+ * @return \MailSo\Mail\MailClient
+ */
+ public function MessageAppendFile($sMessageFileName, $sFolderToSave, $aAppendFlags = null, &$iUid = null)
+ {
+ if (!@\is_file($sMessageFileName) || !@\is_readable($sMessageFileName))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $iMessageStreamSize = \filesize($sMessageFileName);
+ $rMessageStream = \fopen($sMessageFileName, 'rb');
+
+ $this->MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderToSave, $aAppendFlags, $iUid);
+
+ if (\is_resource($rMessageStream))
+ {
+ @fclose($rMessageStream);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param int $iCount
+ * @param int $iUnseenCount
+ * @param string $sUidNext
+ * @param string $sHighestModSeq
+ *
+ * @return void
+ */
+ protected function initFolderValues($sFolderName, &$iCount, &$iUnseenCount,
+ &$sUidNext, &$sHighestModSeq = '')
+ {
+ $aTypes = array(
+ \MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES,
+ \MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN,
+ \MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT
+ );
+
+ if ($this->oImapClient->IsSupported('CONDSTORE'))
+ {
+ $aTypes[] = \MailSo\Imap\Enumerations\FolderResponseStatus::HIGHESTMODSEQ;
+ }
+
+ $aFolderStatus = $this->oImapClient->FolderStatus($sFolderName, $aTypes);
+
+ $iCount = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES])
+ ? (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES] : 0;
+
+ $iUnseenCount = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN])
+ ? (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN] : 0;
+
+ $sUidNext = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT])
+ ? (string) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT] : '0';
+
+ $sHighestModSeq = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::HIGHESTMODSEQ])
+ ? (string) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::HIGHESTMODSEQ] : '';
+
+ if ($this->IsGmail() &&
+ ('INBOX' === $sFolderName || '[gmail]' === \strtolower(\substr($sFolderName, 0, 7))))
+ {
+ $oFolder = $this->oImapClient->FolderCurrentInformation();
+ if ($oFolder && null !== $oFolder->Exists && $oFolder->FolderName === $sFolderName)
+ {
+ $iSubCount = (int) $oFolder->Exists;
+ if (0 < $iSubCount && $iSubCount < $iCount)
+ {
+ $iCount = $iSubCount;
+ }
+ }
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function GenerateImapClientHash()
+ {
+ return \md5('ImapClientHash/'.
+ $this->oImapClient->GetLogginedUser().'@'.
+ $this->oImapClient->GetConnectedHost().':'.
+ $this->oImapClient->GetConnectedPort()
+ );
+ }
+
+ /**
+ * @param string $sFolder
+ * @param int $iCount
+ * @param int $iUnseenCount
+ * @param string $sUidNext
+ * @param string $sHighestModSeq = ''
+ *
+ * @return string
+ */
+ public function GenerateFolderHash($sFolder, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq = '')
+ {
+ $iUnseenCount = 0; // unneccessery
+ return \md5('FolderHash/'.$sFolder.'-'.$iCount.'-'.$iUnseenCount.'-'.$sUidNext.'-'.
+ $sHighestModSeq.'-'.$this->GenerateImapClientHash().'-'.
+ \MailSo\Config::$MessageListPermanentFilter
+ );
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param string $sPrevUidNext
+ * @param string $sCurrentUidNext
+ *
+ * @return array
+ */
+ private function getFolderNextMessageInformation($sFolderName, $sPrevUidNext, $sCurrentUidNext)
+ {
+ $aNewMessages = array();
+
+ if (0 < \strlen($sPrevUidNext) && (string) $sPrevUidNext !== (string) $sCurrentUidNext)
+ {
+ $this->oImapClient->FolderSelect($sFolderName);
+
+ $aFetchResponse = $this->oImapClient->Fetch(array(
+ \MailSo\Imap\Enumerations\FetchType::INDEX,
+ \MailSo\Imap\Enumerations\FetchType::UID,
+ \MailSo\Imap\Enumerations\FetchType::FLAGS,
+ \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array(
+ \MailSo\Mime\Enumerations\Header::FROM_,
+ \MailSo\Mime\Enumerations\Header::SUBJECT,
+ \MailSo\Mime\Enumerations\Header::CONTENT_TYPE
+ ))
+ ), $sPrevUidNext.':*', true);
+
+ if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse))
+ {
+ foreach ($aFetchResponse as /* @var $oFetchResponse \MailSo\Imap\FetchResponse */ $oFetchResponse)
+ {
+ $aFlags = \array_map('strtolower', $oFetchResponse->GetFetchValue(
+ \MailSo\Imap\Enumerations\FetchType::FLAGS));
+
+ if (!\in_array(\strtolower(\MailSo\Imap\Enumerations\MessageFlag::SEEN), $aFlags))
+ {
+ $sUid = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID);
+ $sHeaders = $oFetchResponse->GetHeaderFieldsValue();
+
+ $oHeaders = \MailSo\Mime\HeaderCollection::NewInstance()->Parse($sHeaders);
+
+ $sContentTypeCharset = $oHeaders->ParameterValue(
+ \MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
+ \MailSo\Mime\Enumerations\Parameter::CHARSET
+ );
+
+ $sCharset = '';
+ if (0 < \strlen($sContentTypeCharset))
+ {
+ $sCharset = $sContentTypeCharset;
+ }
+
+ if (0 < \strlen($sCharset))
+ {
+ $oHeaders->SetParentCharset($sCharset);
+ }
+
+ $aNewMessages[] = array(
+ 'Folder' => $sFolderName,
+ 'Uid' => $sUid,
+ 'Subject' => $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::SUBJECT, 0 === \strlen($sCharset)),
+ 'From' => $oHeaders->GetAsEmailCollection(\MailSo\Mime\Enumerations\Header::FROM_, 0 === \strlen($sCharset))
+ );
+ }
+ }
+ }
+ }
+
+ return $aNewMessages;
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param string $sPrevUidNext = ''
+ * @param array $aUids = ''
+ *
+ * @return string
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderInformation($sFolderName, $sPrevUidNext = '', $aUids = array())
+ {
+ $aFlags = array();
+
+ $bSelect = false;
+ if ($this->IsGmail() &&
+ ('INBOX' === $sFolderName || '[gmail]' === \strtolower(\substr($sFolderName, 0, 7))))
+ {
+ $this->oImapClient->FolderSelect($sFolderName);
+ $bSelect = true;
+ }
+
+ if (\is_array($aUids) && 0 < \count($aUids))
+ {
+ if (!$bSelect)
+ {
+ $this->oImapClient->FolderSelect($sFolderName);
+ }
+
+ $aFetchResponse = $this->oImapClient->Fetch(array(
+ \MailSo\Imap\Enumerations\FetchType::INDEX,
+ \MailSo\Imap\Enumerations\FetchType::UID,
+ \MailSo\Imap\Enumerations\FetchType::FLAGS
+ ), \MailSo\Base\Utils::PrepearFetchSequence($aUids), true);
+
+ if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse))
+ {
+ foreach ($aFetchResponse as $oFetchResponse)
+ {
+ $sUid = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID);
+ $aFlags[(\is_numeric($sUid) ? (int) $sUid : 0)] =
+ $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::FLAGS);
+ }
+ }
+ }
+
+ $iCount = 0;
+ $iUnseenCount = 0;
+ $sUidNext = '0';
+ $sHighestModSeq = '';
+
+ $this->initFolderValues($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq);
+
+ $aResult = array(
+ 'Folder' => $sFolderName,
+ 'Hash' => $this->GenerateFolderHash($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq),
+ 'MessageCount' => $iCount,
+ 'MessageUnseenCount' => $iUnseenCount,
+ 'UidNext' => $sUidNext,
+ 'Flags' => $aFlags,
+ 'HighestModSeq' => $sHighestModSeq,
+ 'NewMessages' => 'INBOX' === $sFolderName && \MailSo\Config::$CheckNewMessages ?
+ $this->getFolderNextMessageInformation($sFolderName, $sPrevUidNext, $sUidNext) : array()
+ );
+
+ return $aResult;
+ }
+
+ /**
+ * @param string $sFolderName
+ *
+ * @return string
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderHash($sFolderName)
+ {
+ $iCount = 0;
+ $iUnseenCount = 0;
+ $sUidNext = '0';
+ $sHighestModSeq = '';
+
+ $this->initFolderValues($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq);
+
+ return $this->GenerateFolderHash($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq);
+ }
+
+ /**
+ * @return int
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function InboxUnreadCount()
+ {
+ $aFolderStatus = $this->oImapClient->FolderStatus('INBOX', array(
+ \MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN
+ ));
+
+ $iResult = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN]) ?
+ (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN] : 0;
+
+ return 0 < $iResult ? $iResult : 0;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsGmail()
+ {
+ return 'ssl://imap.gmail.com' === \strtolower($this->oImapClient->GetConnectedHost());
+ }
+
+ /**
+ * @param string $sSearch
+ * @param bool $bDetectGmail = true
+ *
+ * @return string
+ */
+ private function escapeSearchString($sSearch, $bDetectGmail = true)
+ {
+ return !\MailSo\Base\Utils::IsAscii($sSearch)
+ ? '{'.\strlen($sSearch).'}'."\r\n".$sSearch : $this->oImapClient->EscapeString($sSearch);
+// return ($bDetectGmail && !\MailSo\Base\Utils::IsAscii($sSearch) && $this->IsGmail())
+// ? '{'.\strlen($sSearch).'+}'."\r\n".$sSearch : $this->oImapClient->EscapeString($sSearch);
+ }
+
+ /**
+ * @param string $sDate
+ * @param int $iTimeZoneOffset
+ *
+ * @return int
+ */
+ private function parseSearchDate($sDate, $iTimeZoneOffset)
+ {
+ $iResult = 0;
+ if (0 < \strlen($sDate))
+ {
+ $oDateTime = \DateTime::createFromFormat('Y.m.d', $sDate, \MailSo\Base\DateTimeHelper::GetUtcTimeZoneObject());
+ return $oDateTime ? $oDateTime->getTimestamp() - $iTimeZoneOffset : 0;
+ }
+
+ return $iResult;
+ }
+
+ /**
+ * @param string $sSize
+ *
+ * @return int
+ */
+ private function parseFriendlySize($sSize)
+ {
+ $sSize = preg_replace('/[^0-9bBkKmM]/', '', $sSize);
+
+ $iResult = 0;
+ $aMatch = array();
+
+ if (\preg_match('/([\d]+)(B|KB|M|MB|G|GB)$/i', $sSize, $aMatch) && isset($aMatch[1], $aMatch[2]))
+ {
+ $iResult = (int) $aMatch[1];
+ switch (\strtoupper($aMatch[2]))
+ {
+ case 'K':
+ case 'KB':
+ $iResult *= 1024;
+ case 'M':
+ case 'MB':
+ $iResult *= 1024;
+ case 'G':
+ case 'GB':
+ $iResult *= 1024;
+ }
+ }
+ else
+ {
+ $iResult = (int) $sSize;
+ }
+
+ return $iResult;
+ }
+
+ /**
+ * @param string $sSearch
+ *
+ * @return array
+ */
+ private function parseSearchString($sSearch)
+ {
+ $aResult = array(
+ 'OTHER' => ''
+ );
+
+ $aCache = array();
+
+ $sReg = 'e?mail|from|to|subject|has|is|date|text|body|size|larger|bigger|smaller|maxsize|minsize';
+
+ $sSearch = \MailSo\Base\Utils::StripSpaces($sSearch);
+ $sSearch = \trim(\preg_replace('/('.$sReg.'): /i', '\\1:', $sSearch));
+
+ $mMatch = array();
+ \preg_match_all('/".*?(? $sName)
+ {
+ if (isset($mMatch[2][$iIndex]) && 0 < \strlen($mMatch[2][$iIndex]))
+ {
+ $sName = \strtoupper($sName);
+ $sValue = $mMatch[2][$iIndex];
+ switch ($sName)
+ {
+ case 'TEXT':
+ case 'BODY':
+ case 'EMAIL':
+ case 'MAIL':
+ case 'FROM':
+ case 'TO':
+ case 'SUBJECT':
+ case 'IS':
+ case 'HAS':
+ case 'SIZE':
+ case 'SMALLER':
+ case 'LARGER':
+ case 'BIGGER':
+ case 'MAXSIZE':
+ case 'MINSIZE':
+ case 'DATE':
+ if ('MAIL' === $sName)
+ {
+ $sName = 'EMAIL';
+ }
+ if ('BODY' === $sName)
+ {
+ $sName = 'TEXT';
+ }
+ if ('SIZE' === $sName || 'BIGGER' === $sName || 'MINSIZE' === $sName)
+ {
+ $sName = 'LARGER';
+ }
+ if ('MAXSIZE' === $sName)
+ {
+ $sName = 'SMALLER';
+ }
+ $aResult[$sName] = $sValue;
+ break;
+ }
+ }
+ }
+ }
+
+ $aResult['OTHER'] = $sSearch;
+ foreach ($aResult as $sName => $sValue)
+ {
+ if (isset($aCache[$sValue]))
+ {
+ $aResult[$sName] = \trim($aCache[$sValue], '"\' ');
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @param string $sSearch
+ * @param string $sFilter
+ * @param int $iTimeZoneOffset = 0
+ * @param bool $bUseCache = true
+ *
+ * @return string
+ */
+ private function getImapSearchCriterias($sSearch, $sFilter, $iTimeZoneOffset = 0, &$bUseCache = true)
+ {
+ $bUseCache = true;
+ $iTimeFilter = 0;
+ $aCriteriasResult = array();
+
+ if (0 < \MailSo\Config::$MessageListDateFilter)
+ {
+ $iD = \time() - 3600 * 24 * 30 * \MailSo\Config::$MessageListDateFilter;
+ $iTimeFilter = \gmmktime(1, 1, 1, \gmdate('n', $iD), 1, \gmdate('Y', $iD));
+ }
+
+ if (0 < \strlen(\trim($sSearch)))
+ {
+ $sGmailRawSearch = '';
+ $sResultBodyTextSearch = '';
+
+ $aLines = $this->parseSearchString($sSearch);
+ $bIsGmail = $this->oImapClient->IsSupported('X-GM-EXT-1');
+
+ if (1 === \count($aLines) && isset($aLines['OTHER']))
+ {
+ $sValue = $this->escapeSearchString($aLines['OTHER']);
+
+ if (\MailSo\Config::$MessageListFastSimpleSearch)
+ {
+ $aCriteriasResult[] = 'OR OR OR';
+ $aCriteriasResult[] = 'FROM';
+ $aCriteriasResult[] = $sValue;
+ $aCriteriasResult[] = 'TO';
+ $aCriteriasResult[] = $sValue;
+ $aCriteriasResult[] = 'CC';
+ $aCriteriasResult[] = $sValue;
+ $aCriteriasResult[] = 'SUBJECT';
+ $aCriteriasResult[] = $sValue;
+ }
+ else
+ {
+ $aCriteriasResult[] = 'TEXT';
+ $aCriteriasResult[] = $sValue;
+ }
+ }
+ else
+ {
+ if (isset($aLines['EMAIL']))
+ {
+ $sValue = $this->escapeSearchString($aLines['EMAIL']);
+
+ $aCriteriasResult[] = 'OR OR';
+ $aCriteriasResult[] = 'FROM';
+ $aCriteriasResult[] = $sValue;
+ $aCriteriasResult[] = 'TO';
+ $aCriteriasResult[] = $sValue;
+ $aCriteriasResult[] = 'CC';
+ $aCriteriasResult[] = $sValue;
+
+ unset($aLines['EMAIL']);
+ }
+
+ if (isset($aLines['TO']))
+ {
+ $sValue = $this->escapeSearchString($aLines['TO']);
+
+ $aCriteriasResult[] = 'OR';
+ $aCriteriasResult[] = 'TO';
+ $aCriteriasResult[] = $sValue;
+ $aCriteriasResult[] = 'CC';
+ $aCriteriasResult[] = $sValue;
+
+ unset($aLines['TO']);
+ }
+
+ $sMainText = '';
+ foreach ($aLines as $sName => $sRawValue)
+ {
+ if ('' === \trim($sRawValue))
+ {
+ continue;
+ }
+
+ $sValue = $this->escapeSearchString($sRawValue);
+ switch ($sName)
+ {
+ case 'FROM':
+ $aCriteriasResult[] = 'FROM';
+ $aCriteriasResult[] = $sValue;
+ break;
+ case 'SUBJECT':
+ $aCriteriasResult[] = 'SUBJECT';
+ $aCriteriasResult[] = $sValue;
+ break;
+ case 'OTHER':
+ case 'TEXT':
+ $sMainText .= ' '.$sRawValue;
+ break;
+ case 'HAS':
+ $aValue = \explode(',', \strtolower($sRawValue));
+ $aValue = \array_map('trim', $aValue);
+
+ $aCompareArray = array('file', 'files', 'attach', 'attachs', 'attachment', 'attachments');
+ if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue)))
+ {
+ if ($bIsGmail)
+ {
+ $sGmailRawSearch .= ' has:attachment';
+ }
+ else
+ {
+ // Simple, is not detailed search (Sometimes doesn't work)
+ $aCriteriasResult[] = 'OR OR OR';
+ $aCriteriasResult[] = 'HEADER Content-Type application/';
+ $aCriteriasResult[] = 'HEADER Content-Type multipart/m';
+ $aCriteriasResult[] = 'HEADER Content-Type multipart/signed';
+ $aCriteriasResult[] = 'HEADER Content-Type multipart/report';
+ }
+ }
+
+ case 'IS':
+ $aValue = \explode(',', \strtolower($sRawValue));
+ $aValue = \array_map('trim', $aValue);
+
+ $aCompareArray = array('flag', 'flagged', 'star', 'starred', 'pinned');
+ $aCompareArray2 = array('unflag', 'unflagged', 'unstar', 'unstarred', 'unpinned');
+ if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue)))
+ {
+ $aCriteriasResult[] = 'FLAGGED';
+ $bUseCache = false;
+ }
+ else if (\count($aCompareArray2) > \count(\array_diff($aCompareArray2, $aValue)))
+ {
+ $aCriteriasResult[] = 'UNFLAGGED';
+ $bUseCache = false;
+ }
+
+ $aCompareArray = array('unread', 'unseen');
+ $aCompareArray2 = array('read', 'seen');
+ if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue)))
+ {
+ $aCriteriasResult[] = 'UNSEEN';
+ $bUseCache = false;
+ }
+ else if (\count($aCompareArray2) > \count(\array_diff($aCompareArray2, $aValue)))
+ {
+ $aCriteriasResult[] = 'SEEN';
+ $bUseCache = false;
+ }
+ break;
+
+ case 'LARGER':
+ $aCriteriasResult[] = 'LARGER';
+ $aCriteriasResult[] = $this->parseFriendlySize($sRawValue);
+ break;
+ case 'SMALLER':
+ $aCriteriasResult[] = 'SMALLER';
+ $aCriteriasResult[] = $this->parseFriendlySize($sRawValue);
+ break;
+ case 'DATE':
+ $iDateStampFrom = $iDateStampTo = 0;
+
+ $sDate = $sRawValue;
+ $aDate = \explode('/', $sDate);
+
+ if (\is_array($aDate) && 2 === \count($aDate))
+ {
+ if (0 < \strlen($aDate[0]))
+ {
+ $iDateStampFrom = $this->parseSearchDate($aDate[0], $iTimeZoneOffset);
+ }
+
+ if (0 < \strlen($aDate[1]))
+ {
+ $iDateStampTo = $this->parseSearchDate($aDate[1], $iTimeZoneOffset);
+ $iDateStampTo += 60 * 60 * 24;
+ }
+ }
+ else
+ {
+ if (0 < \strlen($sDate))
+ {
+ $iDateStampFrom = $this->parseSearchDate($sDate, $iTimeZoneOffset);
+ $iDateStampTo = $iDateStampFrom + 60 * 60 * 24;
+ }
+ }
+
+ if (0 < $iDateStampFrom)
+ {
+ $aCriteriasResult[] = 'SINCE';
+ $aCriteriasResult[] = \gmdate('j-M-Y', $iTimeFilter > $iDateStampFrom ?
+ $iTimeFilter : $iDateStampFrom);
+
+ $iTimeFilter = 0;
+ }
+
+ if (0 < $iDateStampTo)
+ {
+ $aCriteriasResult[] = 'BEFORE';
+ $aCriteriasResult[] = \gmdate('j-M-Y', $iDateStampTo);
+ }
+ break;
+ }
+ }
+
+ if ('' !== \trim($sMainText))
+ {
+ $sMainText = \trim(\MailSo\Base\Utils::StripSpaces($sMainText), '"');
+ if ($bIsGmail)
+ {
+ $sGmailRawSearch .= ' '.$sMainText;
+ }
+ else
+ {
+ $sResultBodyTextSearch .= ' '.$sMainText;
+ }
+ }
+ }
+
+ $sGmailRawSearch = \trim($sGmailRawSearch);
+ if ($bIsGmail && 0 < \strlen($sGmailRawSearch))
+ {
+ $aCriteriasResult[] = 'X-GM-RAW';
+ $aCriteriasResult[] = $this->escapeSearchString($sGmailRawSearch, false);
+ }
+
+ $sResultBodyTextSearch = \trim($sResultBodyTextSearch);
+ if (0 < \strlen($sResultBodyTextSearch))
+ {
+ $aCriteriasResult[] = 'BODY';
+ $aCriteriasResult[] = $this->escapeSearchString($sResultBodyTextSearch);
+ }
+ }
+
+ $sCriteriasResult = \trim(\implode(' ', $aCriteriasResult));
+
+ if (0 < $iTimeFilter)
+ {
+ $sCriteriasResult .= ' SINCE '.\gmdate('j-M-Y', $iTimeFilter);
+ }
+
+ $sCriteriasResult = \trim($sCriteriasResult);
+ if (\MailSo\Config::$MessageListUndeletedOnly)
+ {
+ $sCriteriasResult = \trim($sCriteriasResult.' UNDELETED');
+ }
+
+ $sFilter = \trim($sFilter);
+ if ('' !== $sFilter)
+ {
+ $sCriteriasResult .= ' '.$sFilter;
+ }
+
+ $sCriteriasResult = \trim($sCriteriasResult);
+ if ('' !== \MailSo\Config::$MessageListPermanentFilter)
+ {
+ $sCriteriasResult = \trim($sCriteriasResult.' '.\MailSo\Config::$MessageListPermanentFilter);
+ }
+
+ $sCriteriasResult = \trim($sCriteriasResult);
+ if ('' === $sCriteriasResult)
+ {
+ $sCriteriasResult = 'ALL';
+ }
+
+ return $sCriteriasResult;
+ }
+
+ /**
+ * @param array $aThreads
+ * @return array
+ */
+ private function threadArrayMap($aThreads)
+ {
+ $aNew = array();
+ foreach ($aThreads as $mItem)
+ {
+ if (!\is_array($mItem))
+ {
+ $aNew[] = $mItem;
+ }
+ else
+ {
+ $mMap = $this->threadArrayMap($mItem);
+ if (\is_array($mMap) && 0 < \count($mMap))
+ {
+ $aNew = \array_merge($aNew, $mMap);
+ }
+ }
+ }
+
+ return $aNew;
+ }
+
+ /**
+ * @param array $aThreads
+ *
+ * @return array
+ */
+ private function compileThreadArray($aThreads)
+ {
+ $aResult = array();
+ foreach ($aThreads as $mItem)
+ {
+ if (\is_array($mItem))
+ {
+ $aMap = $this->threadArrayMap($mItem);
+ if (\is_array($aMap))
+ {
+ if (1 < \count($aMap))
+ {
+ $aResult[] = $aMap;
+ }
+ else if (0 < \count($aMap))
+ {
+ $aResult[] = $aMap[0];
+ }
+ }
+ }
+ else
+ {
+ $aResult[] = $mItem;
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param string $sFolderHash
+ * @param array $aIndexOrUids
+ * @param \MailSo\Cache\CacheClient $oCacher
+ * @param bool $bCacheOnly = false
+ *
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageListThreadsMap($sFolderName, $sFolderHash, $aIndexOrUids, $oCacher, $bCacheOnly = false)
+ {
+ $iThreadLimit = \MailSo\Config::$LargeThreadLimit;
+
+ $sSearchHash = '';
+ if (0 < \MailSo\Config::$MessageListDateFilter)
+ {
+ $iD = \time() - 3600 * 24 * 30 * \MailSo\Config::$MessageListDateFilter;
+ $iTimeFilter = \gmmktime(1, 1, 1, \gmdate('n', $iD), 1, \gmdate('Y', $iD));
+
+ $sSearchHash .= ' SINCE '.\gmdate('j-M-Y', $iTimeFilter);
+ }
+
+ if ('' === \trim($sSearchHash))
+ {
+ $sSearchHash = 'ALL';
+ }
+
+ if ($oCacher && $oCacher->IsInited())
+ {
+ $sSerializedHashKey =
+ 'ThreadsMapSorted/'.$sSearchHash.'/'.
+ 'Limit='.$iThreadLimit.'/'.$sFolderName.'/'.$sFolderHash;
+
+ if ($this->oLogger)
+ {
+ $this->oLogger->Write($sSerializedHashKey);
+ }
+
+ $sSerializedUids = $oCacher->Get($sSerializedHashKey);
+ if (!empty($sSerializedUids))
+ {
+ $aSerializedUids = @\json_decode($sSerializedUids, true);
+ if (isset($aSerializedUids['ThreadsUids']) && \is_array($aSerializedUids['ThreadsUids']))
+ {
+ if ($this->oLogger)
+ {
+ $this->oLogger->Write('Get Serialized Thread UIDS from cache ("'.$sFolderName.'" / '.$sSearchHash.') [count:'.\count($aSerializedUids['ThreadsUids']).']');
+ }
+
+ return $aSerializedUids['ThreadsUids'];
+ }
+ }
+ }
+
+ if ($bCacheOnly)
+ {
+ return null;
+ }
+
+ $this->oImapClient->FolderExamine($sFolderName);
+
+ $aThreadUids = array();
+ try
+ {
+ $aThreadUids = $this->oImapClient->MessageSimpleThread($sSearchHash);
+ }
+ catch (\MailSo\Imap\Exceptions\RuntimeException $oException)
+ {
+ unset($oException);
+ $aThreadUids = array();
+ }
+
+ $aResult = array();
+ $aCompiledThreads = $this->compileThreadArray($aThreadUids);
+
+ foreach ($aCompiledThreads as $mData)
+ {
+ if (\is_array($mData))
+ {
+ foreach ($mData as $mSubData)
+ {
+ $aResult[(int) $mSubData] =
+ \array_diff($mData, array((int) $mSubData));
+ }
+ }
+ else if (\is_int($mData) || \is_string($mData))
+ {
+ $aResult[(int) $mData] = (int) $mData;
+ }
+ }
+
+ $aParentsMap = array();
+ foreach ($aIndexOrUids as $iUid)
+ {
+ if (isset($aResult[$iUid]) && \is_array($aResult[$iUid]))
+ {
+ foreach ($aResult[$iUid] as $iTempUid)
+ {
+ $aParentsMap[$iTempUid] = $iUid;
+ if (isset($aResult[$iTempUid]))
+ {
+ unset($aResult[$iTempUid]);
+ }
+ }
+ }
+ }
+
+ $aSortedThreads = array();
+ foreach ($aIndexOrUids as $iUid)
+ {
+ if (isset($aResult[$iUid]))
+ {
+ $aSortedThreads[$iUid] = $iUid;
+ }
+ }
+
+ foreach ($aIndexOrUids as $iUid)
+ {
+ if (!isset($aSortedThreads[$iUid]) &&
+ isset($aParentsMap[$iUid]) &&
+ isset($aSortedThreads[$aParentsMap[$iUid]]))
+ {
+ if (!\is_array($aSortedThreads[$aParentsMap[$iUid]]))
+ {
+ $aSortedThreads[$aParentsMap[$iUid]] = array();
+ }
+
+ $aSortedThreads[$aParentsMap[$iUid]][] = $iUid;
+ }
+ }
+
+ $aResult = $aSortedThreads;
+ unset($aParentsMap, $aSortedThreads);
+
+ $aTemp = array();
+ foreach ($aResult as $iUid => $mValue)
+ {
+ if (0 < $iThreadLimit && \is_array($mValue) && $iThreadLimit < \count($mValue))
+ {
+ $aParts = \array_chunk($mValue, $iThreadLimit);
+ if (0 < count($aParts))
+ {
+ foreach ($aParts as $iIndex => $aItem)
+ {
+ if (0 === $iIndex)
+ {
+ $aResult[$iUid] = $aItem;
+ }
+ else if (0 < $iIndex && \is_array($aItem))
+ {
+ $mFirst = \array_shift($aItem);
+ if (!empty($mFirst))
+ {
+ $aTemp[$mFirst] = 0 < \count($aItem) ? $aItem : $mFirst;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ foreach ($aTemp as $iUid => $mValue)
+ {
+ $aResult[$iUid] = $mValue;
+ }
+
+ unset($aTemp);
+
+ $aLastResult = array();
+ foreach ($aIndexOrUids as $iUid)
+ {
+ if (isset($aResult[$iUid]))
+ {
+ $aLastResult[$iUid] = $aResult[$iUid];
+ }
+ }
+
+ $aResult = $aLastResult;
+ unset($aLastResult);
+
+ if ($oCacher && $oCacher->IsInited() && !empty($sSerializedHashKey))
+ {
+ $oCacher->Set($sSerializedHashKey, @\json_encode(array(
+ 'ThreadsUids' => $aResult
+ )));
+
+ if ($this->oLogger)
+ {
+ $this->oLogger->Write('Save Serialized Thread UIDS to cache ("'.$sFolderName.'" / '.$sSearchHash.') [count:'.\count($aResult).']');
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @param \MailSo\Mail\MessageCollection &$oMessageCollection
+ * @param array $aRequestIndexOrUids
+ * @param bool $bIndexAsUid
+ * @param bool $bSimple = false
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageListByRequestIndexOrUids(&$oMessageCollection, $aRequestIndexOrUids, $bIndexAsUid, $bSimple = false)
+ {
+ if (\is_array($aRequestIndexOrUids) && 0 < \count($aRequestIndexOrUids))
+ {
+ $aFetchResponse = $this->oImapClient->Fetch(array(
+ \MailSo\Imap\Enumerations\FetchType::INDEX,
+ \MailSo\Imap\Enumerations\FetchType::UID,
+ \MailSo\Imap\Enumerations\FetchType::RFC822_SIZE,
+ \MailSo\Imap\Enumerations\FetchType::INTERNALDATE,
+ \MailSo\Imap\Enumerations\FetchType::FLAGS,
+ \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE,
+ $bSimple ?
+ $this->getEnvelopeOrHeadersRequestStringForSimpleList() :
+ $this->getEnvelopeOrHeadersRequestString()
+ ), \MailSo\Base\Utils::PrepearFetchSequence($aRequestIndexOrUids), $bIndexAsUid);
+
+ if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse))
+ {
+ $aFetchIndexArray = array();
+ $oFetchResponseItem = null;
+ foreach ($aFetchResponse as /* @var $oFetchResponseItem \MailSo\Imap\FetchResponse */ &$oFetchResponseItem)
+ {
+ $aFetchIndexArray[($bIndexAsUid)
+ ? $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID)
+ : $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::INDEX)] =& $oFetchResponseItem;
+
+ unset($oFetchResponseItem);
+ }
+
+ foreach ($aRequestIndexOrUids as $iFUid)
+ {
+ if (isset($aFetchIndexArray[$iFUid]))
+ {
+ $oMessageCollection->Add(
+ Message::NewFetchResponseInstance(
+ $oMessageCollection->FolderName, $aFetchIndexArray[$iFUid]));
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @return bool
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ public function IsThreadsSupported()
+ {
+ return $this->oImapClient->IsSupported('THREAD=REFS') ||
+ $this->oImapClient->IsSupported('THREAD=REFERENCES') ||
+ $this->oImapClient->IsSupported('THREAD=ORDEREDSUBJECT');
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param array $aUids
+ *
+ * @return \MailSo\Mail\MessageCollection
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageListSimple($sFolderName, $aUids)
+ {
+ if (0 === \strlen($sFolderName) || !\MailSo\Base\Validator::NotEmptyArray($aUids))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oImapClient->FolderExamine($sFolderName);
+
+ $oMessageCollection = \MailSo\Mail\MessageCollection::NewInstance();
+ $oMessageCollection->FolderName = $sFolderName;
+
+ $this->MessageListByRequestIndexOrUids($oMessageCollection, $aUids, true, true);
+
+ return $oMessageCollection->GetAsArray();
+ }
+
+ /**
+ * @param \MailSo\Cache\CacheClient|null $oCacher
+ * @param string $sSearch
+ * @param string $sFilter
+ * @param string $sFolderName
+ * @param string $sFolderHash
+ * @param bool $bUseSortIfSupported = false
+ *
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function GetUids($oCacher, $sSearch, $sFilter, $sFolderName, $sFolderHash, $bUseSortIfSupported = false)
+ {
+ $aResultUids = false;
+ $bUidsFromCacher = false;
+ $bUseCacheAfterSearch = true;
+
+ $sSerializedHash = '';
+ $sSerializedLog = '';
+
+ $bUseSortIfSupported = $bUseSortIfSupported ? !!$this->oImapClient->IsSupported('SORT') : false;
+
+ if (0 < \strlen($sSearch))
+ {
+ $bUseSortIfSupported = false;
+ }
+
+ $sSearchCriterias = $this->getImapSearchCriterias($sSearch, $sFilter, 0, $bUseCacheAfterSearch);
+ if ($bUseCacheAfterSearch && $oCacher && $oCacher->IsInited())
+ {
+ $sSerializedHash = 'GetUids/'.
+ ($bUseSortIfSupported ? 'S': 'N').'/'.
+ $this->GenerateImapClientHash().'/'.
+ $sFolderName.'/'.$sSearchCriterias;
+
+ $sSerializedLog = '"'.$sFolderName.'" / '.$sSearchCriterias.'';
+
+ $sSerialized = $oCacher->Get($sSerializedHash);
+ if (!empty($sSerialized))
+ {
+ $aSerialized = @\json_decode($sSerialized, true);
+ if (\is_array($aSerialized) && isset($aSerialized['FolderHash'], $aSerialized['Uids']) &&
+ $sFolderHash === $aSerialized['FolderHash'] &&
+ \is_array($aSerialized['Uids'])
+ )
+ {
+ if ($this->oLogger)
+ {
+ $this->oLogger->Write('Get Serialized UIDS from cache ('.$sSerializedLog.') [count:'.\count($aSerialized['Uids']).']');
+ }
+
+ $aResultUids = $aSerialized['Uids'];
+ $bUidsFromCacher = true;
+ }
+ }
+ }
+
+ if (!\is_array($aResultUids))
+ {
+ $aResultUids = $bUseSortIfSupported ?
+ $this->oImapClient->MessageSimpleSort(array('REVERSE ARRIVAL'), $sSearchCriterias, true) :
+ $this->oImapClient->MessageSimpleSearch($sSearchCriterias, true, \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? '' : 'UTF-8')
+ ;
+
+ if (!$bUidsFromCacher && $bUseCacheAfterSearch && \is_array($aResultUids) && $oCacher && $oCacher->IsInited() && 0 < \strlen($sSerializedHash))
+ {
+ $oCacher->Set($sSerializedHash, @\json_encode(array(
+ 'FolderHash' => $sFolderHash,
+ 'Uids' => $aResultUids
+ )));
+
+ if ($this->oLogger)
+ {
+ $this->oLogger->Write('Save Serialized UIDS to cache ('.$sSerializedLog.') [count:'.\count($aResultUids).']');
+ }
+ }
+ }
+
+ return \is_array($aResultUids) ? $aResultUids : array();
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param int $iOffset = 0
+ * @param int $iLimit = 10
+ * @param string $sSearch = ''
+ * @param string $sPrevUidNext = ''
+ * @param \MailSo\Cache\CacheClient|null $oCacher = null
+ * @param bool $bUseSortIfSupported = false
+ * @param bool $bUseThreadSortIfSupported = false
+ * @param bool $bUseESearchOrESortRequest = false
+ * @param string $sThreadUid = ''
+ * @param string $sFilter = ''
+ *
+ * @return \MailSo\Mail\MessageCollection
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageList($sFolderName, $iOffset = 0, $iLimit = 10, $sSearch = '', $sPrevUidNext = '', $oCacher = null,
+ $bUseSortIfSupported = false, $bUseThreadSortIfSupported = false, $sThreadUid = '', $sFilter = '')
+ {
+ $sFilter = \trim($sFilter);
+ $sSearch = \trim($sSearch);
+ if (!\MailSo\Base\Validator::RangeInt($iOffset, 0) ||
+ !\MailSo\Base\Validator::RangeInt($iLimit, 0, 999))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $bUseFilter = '' !== $sFilter;
+
+ $this->oImapClient->FolderSelect($sFolderName);
+
+ $oMessageCollection = MessageCollection::NewInstance();
+ $oMessageCollection->FolderName = $sFolderName;
+ $oMessageCollection->Offset = $iOffset;
+ $oMessageCollection->Limit = $iLimit;
+ $oMessageCollection->Search = $sSearch;
+ $oMessageCollection->ThreadUid = $sThreadUid;
+ $oMessageCollection->Filtered = '' !== \MailSo\Config::$MessageListPermanentFilter;
+
+ $aUids = array();
+ $mAllSortedUids = null;
+ $mAllThreads = null;
+
+ $iThreadUid = empty($sThreadUid) ? 0 : (int) $sThreadUid;
+
+ $iMessageRealCount = 0;
+ $iMessageUnseenCount = 0;
+ $sUidNext = '0';
+ $sHighestModSeq = '';
+
+ $bUseSortIfSupported = $bUseSortIfSupported ? $this->oImapClient->IsSupported('SORT') : false;
+
+ $bUseThreadSortIfSupported = $bUseThreadSortIfSupported ?
+ ($this->oImapClient->IsSupported('THREAD=REFS') || $this->oImapClient->IsSupported('THREAD=REFERENCES') || $this->oImapClient->IsSupported('THREAD=ORDEREDSUBJECT')) : false;
+
+ if (!empty($sThreadUid) && !$bUseThreadSortIfSupported)
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ if (!$oCacher || !($oCacher instanceof \MailSo\Cache\CacheClient))
+ {
+ $oCacher = null;
+ }
+
+ $this->initFolderValues($sFolderName, $iMessageRealCount, $iMessageUnseenCount, $sUidNext, $sHighestModSeq);
+
+ if ($bUseFilter)
+ {
+ $iMessageUnseenCount = 0;
+ }
+
+ $oMessageCollection->FolderHash = $this->GenerateFolderHash(
+ $sFolderName, $iMessageRealCount, $iMessageUnseenCount, $sUidNext, $sHighestModSeq);
+
+ $oMessageCollection->UidNext = $sUidNext;
+
+ if (empty($sThreadUid) && 0 < \strlen($sPrevUidNext) && 'INBOX' === $sFolderName)
+ {
+ $oMessageCollection->NewMessages = $this->getFolderNextMessageInformation(
+ $sFolderName, $sPrevUidNext, $sUidNext);
+ }
+
+ $bSearch = false;
+ $bMessageListOptimization = 0 < \MailSo\Config::$MessageListCountLimitTrigger &&
+ \MailSo\Config::$MessageListCountLimitTrigger < $iMessageRealCount;
+
+ if ($bMessageListOptimization)
+ {
+ $bUseSortIfSupported = false;
+ $bUseThreadSortIfSupported = false;
+ }
+
+ if (0 < $iMessageRealCount && !$bMessageListOptimization)
+ {
+ $mAllSortedUids = $this->GetUids($oCacher, '', $sFilter,
+ $oMessageCollection->FolderName, $oMessageCollection->FolderHash, $bUseSortIfSupported);
+
+ $mAllThreads = $bUseThreadSortIfSupported ? $this->MessageListThreadsMap(
+ $oMessageCollection->FolderName, $oMessageCollection->FolderHash, $mAllSortedUids, $oCacher) : null;
+
+ if ($bUseThreadSortIfSupported && 0 < $iThreadUid && \is_array($mAllThreads))
+ {
+ $aUids = array();
+ $iResultRootUid = 0;
+
+ if (isset($mAllThreads[$iThreadUid]))
+ {
+ $iResultRootUid = $iThreadUid;
+ if (\is_array($mAllThreads[$iThreadUid]))
+ {
+ $aUids = $mAllThreads[$iThreadUid];
+ }
+ }
+ else
+ {
+ foreach ($mAllThreads as $iRootUid => $mSubUids)
+ {
+ if (\is_array($mSubUids) && \in_array($iThreadUid, $mSubUids))
+ {
+ $iResultRootUid = $iRootUid;
+ $aUids = $mSubUids;
+ continue;
+ }
+ }
+ }
+
+ if (0 < $iResultRootUid && \in_array($iResultRootUid, $mAllSortedUids))
+ {
+ \array_unshift($aUids, $iResultRootUid);
+ }
+ }
+ else if ($bUseThreadSortIfSupported && \is_array($mAllThreads))
+ {
+ $aUids = \array_keys($mAllThreads);
+ }
+ else
+ {
+ $bUseThreadSortIfSupported = false;
+ $aUids = $mAllSortedUids;
+ }
+
+ if (0 < \strlen($sSearch) && \is_array($aUids))
+ {
+ $aSearchedUids = $this->GetUids($oCacher, $sSearch, $sFilter,
+ $oMessageCollection->FolderName, $oMessageCollection->FolderHash);
+
+ if (\is_array($aSearchedUids) && 0 < \count($aSearchedUids))
+ {
+ $aFlippedSearchedUids = \array_flip($aSearchedUids);
+
+ $bSearch = true;
+ $aNewUids = array();
+
+ foreach ($aUids as $iUid)
+ {
+ if (isset($aFlippedSearchedUids[$iUid]))
+ {
+ $aNewUids[] = $iUid;
+ }
+ else if ($bUseThreadSortIfSupported && 0 === $iThreadUid && isset($mAllThreads[$iUid]) && \is_array($mAllThreads[$iUid]))
+ {
+ foreach ($mAllThreads[$iUid] as $iSubUid)
+ {
+ if (isset($aFlippedSearchedUids[$iSubUid]))
+ {
+ $aNewUids[] = $iUid;
+ continue;
+ }
+ }
+ }
+ }
+
+ $aUids = \array_unique($aNewUids);
+ unset($aNewUids);
+ }
+ else
+ {
+ $aUids = array();
+ }
+ }
+
+ if (\is_array($aUids))
+ {
+ $oMessageCollection->MessageCount = $iMessageRealCount;
+ $oMessageCollection->MessageUnseenCount = $iMessageUnseenCount;
+ $oMessageCollection->MessageResultCount = \count($aUids);
+
+ if (0 < \count($aUids))
+ {
+ $aRequestUids = \array_slice($aUids, $iOffset, $iLimit);
+ $this->MessageListByRequestIndexOrUids($oMessageCollection, $aRequestUids, true);
+ }
+ }
+ }
+ else if (0 < $iMessageRealCount)
+ {
+ if ($this->oLogger)
+ {
+ $this->oLogger->Write('List optimization (count: '.$iMessageRealCount.
+ ', limit:'.\MailSo\Config::$MessageListCountLimitTrigger.')');
+ }
+
+ $oMessageCollection->MessageCount = $iMessageRealCount;
+ $oMessageCollection->MessageUnseenCount = $iMessageUnseenCount;
+
+ if (0 < \strlen($sSearch) || $bUseFilter)
+ {
+ $aUids = $this->GetUids($oCacher, $sSearch, $sFilter,
+ $oMessageCollection->FolderName, $oMessageCollection->FolderHash);
+
+ if (0 < \count($aUids))
+ {
+ $oMessageCollection->MessageResultCount = \count($aUids);
+
+ $aRequestUids = \array_slice($aUids, $iOffset, $iLimit);
+ $this->MessageListByRequestIndexOrUids($oMessageCollection, $aRequestUids, true);
+ }
+ else
+ {
+ $oMessageCollection->MessageResultCount = 0;
+ }
+ }
+ else
+ {
+ $oMessageCollection->MessageResultCount = $iMessageRealCount;
+
+ if (1 < $iMessageRealCount)
+ {
+ $aRequestIndexes = \array_slice(array_reverse(range(1, $iMessageRealCount)), $iOffset, $iLimit);
+ }
+ else
+ {
+ $aRequestIndexes = \array_slice(array(1), $iOffset, $iLimit);
+ }
+
+ $this->MessageListByRequestIndexOrUids($oMessageCollection, $aRequestIndexes, false);
+ }
+ }
+
+ if ($bUseThreadSortIfSupported && 0 === $iThreadUid && \is_array($mAllThreads) && 0 < \count($mAllThreads))
+ {
+ $oMessageCollection->ForeachList(function (/* @var $oMessage \MailSo\Mail\Message */ $oMessage) use ($mAllThreads) {
+
+ $iUid = $oMessage->Uid();
+ if (isset($mAllThreads[$iUid]) && \is_array($mAllThreads[$iUid]) && 0 < \count($mAllThreads[$iUid]))
+ {
+ $aSubThreads = $mAllThreads[$iUid];
+ \array_unshift($aSubThreads, $iUid);
+
+ $oMessage->SetThreads(\array_map('trim', $aSubThreads));
+ unset($aSubThreads);
+ }
+ });
+ }
+
+ return $oMessageCollection;
+ }
+
+ /**
+ * @return array|false
+ */
+ public function Quota()
+ {
+ return $this->oImapClient->Quota();
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param string $sMessageId
+ *
+ * @return int|null
+ */
+ public function FindMessageUidByMessageId($sFolderName, $sMessageId)
+ {
+ if (0 === \strlen($sMessageId))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oImapClient->FolderExamine($sFolderName);
+
+ $aUids = $this->oImapClient->MessageSimpleSearch(
+ 'HEADER Message-ID '.$sMessageId, true);
+
+ return \is_array($aUids) && 1 === \count($aUids) && \is_numeric($aUids[0]) ? (int) $aUids[0] : null;
+ }
+
+ /**
+ * @param array $aMailFoldersHelper
+ * @param int $iOptimizationLimit = 0
+ *
+ * @return array
+ */
+ public function folderListOptimization($aMailFoldersHelper, $iOptimizationLimit = 0)
+ {
+ // optimization
+ if (10 < $iOptimizationLimit && \is_array($aMailFoldersHelper) && $iOptimizationLimit < \count($aMailFoldersHelper))
+ {
+ if ($this->oLogger)
+ {
+ $this->oLogger->Write('Start optimization (limit:'.$iOptimizationLimit.') for '.\count($aMailFoldersHelper).' folders');
+ }
+
+ $iForeachLimit = 1;
+
+ $aFilteredNames = array(
+ 'inbox',
+ 'sent', 'send', 'outbox', 'sentmail', 'sendmail',
+ 'drafts', 'draft',
+ 'junk', 'spam', 'spambucket',
+ 'trash', 'bin', 'deleted',
+ 'archives', 'archive', 'allmail', 'all',
+ 'starred', 'flagged', 'important',
+ 'contacts', 'chats'
+ );
+
+ $aNewMailFoldersHelper = array();
+
+ $iCountLimit = $iForeachLimit;
+
+ foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder)
+ {
+ // mandatory folders
+ if ($oFolder && \in_array(\str_replace(' ', '', \strtolower($oFolder->NameRaw())), $aFilteredNames))
+ {
+ $aNewMailFoldersHelper[] = $oFolder;
+ $aMailFoldersHelper[$iIndex] = null;
+ }
+ }
+
+ foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder)
+ {
+ // subscribed folders
+ if ($oFolder && $oFolder->IsSubscribed())
+ {
+ $aNewMailFoldersHelper[] = $oFolder;
+
+ $aMailFoldersHelper[$iIndex] = null;
+ $iCountLimit--;
+ }
+
+ if (0 > $iCountLimit)
+ {
+ if ($iOptimizationLimit < \count($aNewMailFoldersHelper))
+ {
+ break;
+ }
+ else
+ {
+ $iCountLimit = $iForeachLimit;
+ }
+ }
+ }
+
+ $iCountLimit = $iForeachLimit;
+ if ($iOptimizationLimit >= \count($aNewMailFoldersHelper))
+ {
+ // name filter
+ foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder)
+ {
+ if ($oFolder && !\preg_match('/[{}\[\]]/', $oFolder->NameRaw()))
+ {
+ $aNewMailFoldersHelper[] = $oFolder;
+
+ $aMailFoldersHelper[$iIndex] = null;
+ $iCountLimit--;
+ }
+
+ if (0 > $iCountLimit)
+ {
+ if ($iOptimizationLimit < \count($aNewMailFoldersHelper))
+ {
+ break;
+ }
+ else
+ {
+ $iCountLimit = $iForeachLimit;
+ }
+ }
+ }
+ }
+
+ $iCountLimit = $iForeachLimit;
+ if ($iOptimizationLimit >= \count($aNewMailFoldersHelper))
+ {
+ // other
+ foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder)
+ {
+ if ($oFolder)
+ {
+ $aNewMailFoldersHelper[] = $oFolder;
+
+ $aMailFoldersHelper[$iIndex] = null;
+ $iCountLimit--;
+ }
+
+ if (0 > $iCountLimit)
+ {
+ if ($iOptimizationLimit < \count($aNewMailFoldersHelper))
+ {
+ break;
+ }
+ else
+ {
+ $iCountLimit = $iForeachLimit;
+ }
+ }
+ }
+ }
+
+ $aMailFoldersHelper = $aNewMailFoldersHelper;
+
+ if ($this->oLogger)
+ {
+ $this->oLogger->Write('Result optimization: '.\count($aMailFoldersHelper).' folders');
+ }
+ }
+
+ return $aMailFoldersHelper;
+ }
+
+ /**
+ * @param string $sParent = ''
+ * @param string $sListPattern = '*'
+ * @param bool $bUseListSubscribeStatus = false
+ * @param int $iOptimizationLimit = 0
+ *
+ * @return \MailSo\Mail\FolderCollection|false
+ */
+ public function Folders($sParent = '', $sListPattern = '*', $bUseListSubscribeStatus = true, $iOptimizationLimit = 0)
+ {
+ $oFolderCollection = false;
+
+ $aSubscribedFolders = null;
+ if ($bUseListSubscribeStatus)
+ {
+ try
+ {
+ $aSubscribedFolders = $this->oImapClient->FolderSubscribeList($sParent, $sListPattern);
+ }
+ catch (\Exception $oException)
+ {
+ unset($oException);
+ }
+ }
+
+ $aImapSubscribedFoldersHelper = null;
+ if (\is_array($aSubscribedFolders))
+ {
+ $aImapSubscribedFoldersHelper = array();
+ foreach ($aSubscribedFolders as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder)
+ {
+ $aImapSubscribedFoldersHelper[] = $oImapFolder->FullNameRaw();
+ }
+ }
+
+ $aFolders = $this->oImapClient->FolderList($sParent, $sListPattern);
+
+ $bOptimized = false;
+ $aMailFoldersHelper = null;
+
+ if (\is_array($aFolders))
+ {
+ $aMailFoldersHelper = array();
+
+ foreach ($aFolders as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder)
+ {
+ $aMailFoldersHelper[] = Folder::NewInstance($oImapFolder,
+ (null === $aImapSubscribedFoldersHelper || \in_array($oImapFolder->FullNameRaw(), $aImapSubscribedFoldersHelper)) ||
+ $oImapFolder->IsInbox()
+ );
+ }
+
+ $iCount = \count($aMailFoldersHelper);
+ $aMailFoldersHelper = $this->folderListOptimization($aMailFoldersHelper, $iOptimizationLimit);
+
+ $bOptimized = $iCount !== \count($aMailFoldersHelper);
+ }
+
+ if (\is_array($aMailFoldersHelper))
+ {
+ $oFolderCollection = FolderCollection::NewInstance();
+ $oFolderCollection->InitByUnsortedMailFolderArray($aMailFoldersHelper);
+
+ $oFolderCollection->Optimized = $bOptimized;
+ }
+
+ if ($oFolderCollection)
+ {
+ $oFolderCollection->SortByCallback(function ($oFolderA, $oFolderB) {
+ $sA = \strtoupper($oFolderA->FullNameRaw());
+ $sB = \strtoupper($oFolderB->FullNameRaw());
+ switch (true)
+ {
+ case 'INBOX' === $sA:
+ return -1;
+ case 'INBOX' === $sB:
+ return 1;
+ case '[GMAIL]' === $sA:
+ return -1;
+ case '[GMAIL]' === $sB:
+ return 1;
+ }
+
+ return \strnatcasecmp($oFolderA->FullName(), $oFolderB->FullName());
+ });
+
+ $oNamespace = $this->oImapClient->GetNamespace();
+ if ($oNamespace)
+ {
+ $oFolderCollection->SetNamespace($oNamespace->GetPersonalNamespace());
+ }
+
+ $oFolderCollection->IsThreadsSupported = $this->IsThreadsSupported();
+ }
+
+ return $oFolderCollection;
+ }
+
+ /**
+ * @param string $sFolderNameInUtf8
+ * @param string $sFolderParentFullNameRaw = ''
+ * @param bool $bSubscribeOnCreation = true
+ * @param string $sDelimiter = ''
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function FolderCreate($sFolderNameInUtf8, $sFolderParentFullNameRaw = '', $bSubscribeOnCreation = true, $sDelimiter = '')
+ {
+ if (!\MailSo\Base\Validator::NotEmptyString($sFolderNameInUtf8, true) ||
+ !\is_string($sFolderParentFullNameRaw))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $sFolderNameInUtf8 = \trim($sFolderNameInUtf8);
+
+ if (0 === \strlen($sDelimiter) || 0 < \strlen(\trim($sFolderParentFullNameRaw)))
+ {
+ $aFolders = $this->oImapClient->FolderList('', 0 === \strlen(\trim($sFolderParentFullNameRaw)) ? 'INBOX' : $sFolderParentFullNameRaw);
+ if (!\is_array($aFolders) || !isset($aFolders[0]))
+ {
+ // TODO
+ throw new \MailSo\Mail\Exceptions\RuntimeException(
+ 0 === \strlen(trim($sFolderParentFullNameRaw))
+ ? 'Cannot get folder delimiter'
+ : 'Cannot create folder in non-existen parent folder');
+ }
+
+ $sDelimiter = $aFolders[0]->Delimiter();
+ if (0 < \strlen($sDelimiter) && 0 < \strlen(\trim($sFolderParentFullNameRaw)))
+ {
+ $sFolderParentFullNameRaw .= $sDelimiter;
+ }
+ }
+
+ $sFullNameRawToCreate = \MailSo\Base\Utils::ConvertEncoding($sFolderNameInUtf8,
+ \MailSo\Base\Enumerations\Charset::UTF_8,
+ \MailSo\Base\Enumerations\Charset::UTF_7_IMAP);
+
+ if (0 < \strlen($sDelimiter) && false !== \strpos($sFullNameRawToCreate, $sDelimiter))
+ {
+ // TODO
+ throw new \MailSo\Mail\Exceptions\RuntimeException(
+ 'New folder name contains delimiter');
+ }
+
+ $sFullNameRawToCreate = $sFolderParentFullNameRaw.$sFullNameRawToCreate;
+
+ $this->oImapClient->FolderCreate($sFullNameRawToCreate);
+
+ if ($bSubscribeOnCreation)
+ {
+ $this->oImapClient->FolderSubscribe($sFullNameRawToCreate);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sPrevFolderFullNameRaw
+ * @param string $sNextFolderFullNameInUtf
+ * @param bool $bSubscribeOnMove = true
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function FolderMove($sPrevFolderFullNameRaw, $sNextFolderFullNameInUtf, $bSubscribeOnMove = true)
+ {
+ return $this->folderModify($sPrevFolderFullNameRaw, $sNextFolderFullNameInUtf, false, $bSubscribeOnMove);
+ }
+
+ /**
+ * @param string $sPrevFolderFullNameRaw
+ * @param string $sNewTopFolderNameInUtf
+ * @param bool $bSubscribeOnRename = true
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function FolderRename($sPrevFolderFullNameRaw, $sNewTopFolderNameInUtf, $bSubscribeOnRename = true)
+ {
+ return $this->folderModify($sPrevFolderFullNameRaw, $sNewTopFolderNameInUtf, true, $bSubscribeOnRename);
+ }
+
+ /**
+ * @param string $sPrevFolderFullNameRaw
+ * @param string $sNextFolderNameInUtf
+ * @param bool $bRenameOrMove
+ * @param bool $bSubscribeOnModify
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function folderModify($sPrevFolderFullNameRaw, $sNextFolderNameInUtf, $bRenameOrMove, $bSubscribeOnModify)
+ {
+ if (0 === \strlen($sPrevFolderFullNameRaw) || 0 === \strlen($sNextFolderNameInUtf))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $aFolders = $this->oImapClient->FolderList('', $sPrevFolderFullNameRaw);
+ if (!\is_array($aFolders) || !isset($aFolders[0]))
+ {
+ // TODO
+ throw new \MailSo\Mail\Exceptions\RuntimeException('Cannot rename non-existen folder');
+ }
+
+ $sDelimiter = $aFolders[0]->Delimiter();
+ $iLast = \strrpos($sPrevFolderFullNameRaw, $sDelimiter);
+
+ $mSubscribeFolders = null;
+ if ($bSubscribeOnModify)
+ {
+ $mSubscribeFolders = $this->oImapClient->FolderSubscribeList($sPrevFolderFullNameRaw, '*');
+ if (\is_array($mSubscribeFolders) && 0 < count($mSubscribeFolders))
+ {
+ foreach ($mSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder)
+ {
+ $this->oImapClient->FolderUnSubscribe($oFolder->FullNameRaw());
+ }
+ }
+ }
+
+ $sNewFolderFullNameRaw = \MailSo\Base\Utils::ConvertEncoding($sNextFolderNameInUtf,
+ \MailSo\Base\Enumerations\Charset::UTF_8,
+ \MailSo\Base\Enumerations\Charset::UTF_7_IMAP);
+
+ if($bRenameOrMove)
+ {
+ if (0 < \strlen($sDelimiter) && false !== \strpos($sNewFolderFullNameRaw, $sDelimiter))
+ {
+ // TODO
+ throw new \MailSo\Mail\Exceptions\RuntimeException('New folder name contains delimiter');
+ }
+
+ $sFolderParentFullNameRaw = false === $iLast ? '' : \substr($sPrevFolderFullNameRaw, 0, $iLast + 1);
+ $sNewFolderFullNameRaw = $sFolderParentFullNameRaw.$sNewFolderFullNameRaw;
+ }
+
+ $this->oImapClient->FolderRename($sPrevFolderFullNameRaw, $sNewFolderFullNameRaw);
+
+ if (\is_array($mSubscribeFolders) && 0 < count($mSubscribeFolders))
+ {
+ foreach ($mSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder)
+ {
+ $sFolderFullNameRawForResubscrine = $oFolder->FullNameRaw();
+ if (0 === \strpos($sFolderFullNameRawForResubscrine, $sPrevFolderFullNameRaw))
+ {
+ $sNewFolderFullNameRawForResubscrine = $sNewFolderFullNameRaw.
+ \substr($sFolderFullNameRawForResubscrine, \strlen($sPrevFolderFullNameRaw));
+
+ $this->oImapClient->FolderSubscribe($sNewFolderFullNameRawForResubscrine);
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sFolderFullNameRaw
+ * @param bool $bUnsubscribeOnDeletion = true
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Mail\Exceptions\RuntimeException
+ */
+ public function FolderDelete($sFolderFullNameRaw, $bUnsubscribeOnDeletion = true)
+ {
+ if (0 === \strlen($sFolderFullNameRaw) || 'INBOX' === $sFolderFullNameRaw)
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oImapClient->FolderExamine($sFolderFullNameRaw);
+
+ $aIndexOrUids = $this->oImapClient->MessageSimpleSearch('ALL');
+ if (0 < \count($aIndexOrUids))
+ {
+ throw new \MailSo\Mail\Exceptions\NonEmptyFolder();
+ }
+
+ $this->oImapClient->FolderExamine('INBOX');
+
+ if ($bUnsubscribeOnDeletion)
+ {
+ $this->oImapClient->FolderUnSubscribe($sFolderFullNameRaw);
+ }
+
+ $this->oImapClient->FolderDelete($sFolderFullNameRaw);
+
+ return $this;
+ }
+
+ /**
+ * @param string $sFolderFullNameRaw
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function FolderClear($sFolderFullNameRaw)
+ {
+ $this->oImapClient->FolderSelect($sFolderFullNameRaw);
+
+ $oFolderInformation = $this->oImapClient->FolderCurrentInformation();
+ if ($oFolderInformation && $oFolderInformation->Exists && 0 < $oFolderInformation->Exists) // STATUS?
+ {
+ $this->oImapClient->MessageStoreFlag('1:*', false,
+ array(\MailSo\Imap\Enumerations\MessageFlag::DELETED),
+ \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT
+ );
+
+ $this->oImapClient->MessageExpunge();
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sFolderFullNameRaw
+ * @param bool $bSubscribe
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function FolderSubscribe($sFolderFullNameRaw, $bSubscribe)
+ {
+ if (0 === \strlen($sFolderFullNameRaw))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oImapClient->{($bSubscribe) ? 'FolderSubscribe' : 'FolderUnSubscribe'}($sFolderFullNameRaw);
+
+ return $this;
+ }
+
+ /**
+ * @param \MailSo\Log\Logger $oLogger
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function SetLogger($oLogger)
+ {
+ if (!($oLogger instanceof \MailSo\Log\Logger))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oLogger = $oLogger;
+ $this->oImapClient->SetLogger($this->oLogger);
+
+ return $this;
+ }
+}
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mail/Message.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Message.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mail/Message.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/Message.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mail/MessageCollection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/MessageCollection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mail/MessageCollection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mail/MessageCollection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/MailSo.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/MailSo.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/MailSo.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/MailSo.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/Attachment.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Attachment.php
similarity index 94%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/Attachment.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Attachment.php
index 4d15555d94a9f77f793781f959f710dc164055ed..ed1c2acea691625c92ae8d7cb9ff4bb0230189ad 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/Attachment.php
+++ b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Attachment.php
@@ -1,197 +1,197 @@
-rResource = $rResource;
- $this->sFileName = $sFileName;
- $this->iFileSize = $iFileSize;
- $this->bIsInline = $bIsInline;
- $this->bIsLinked = $bIsLinked;
- $this->sCID = $sCID;
- $this->aCustomContentTypeParams = $aCustomContentTypeParams;
- $this->sContentLocation = $sContentLocation;
- }
-
- /**
- * @param resource $rResource
- * @param string $sFileName = ''
- * @param int $iFileSize = 0
- * @param bool $bIsInline = false
- * @param bool $bIsLinked = false
- * @param string $sCID = ''
- * @param array $aCustomContentTypeParams = array()
- * @param string $sContentLocation = ''
- *
- * @return \MailSo\Mime\Attachment
- */
- public static function NewInstance($rResource, $sFileName = '', $iFileSize = 0, $bIsInline = false,
- $bIsLinked = false, $sCID = '', $aCustomContentTypeParams = array(), $sContentLocation = '')
- {
- return new self($rResource, $sFileName, $iFileSize, $bIsInline, $bIsLinked, $sCID, $aCustomContentTypeParams, $sContentLocation);
- }
-
- /**
- * @return resource
- */
- public function Resource()
- {
- return $this->rResource;
- }
-
- /**
- * @return string
- */
- public function ContentType()
- {
- return \MailSo\Base\Utils::MimeContentType($this->sFileName);
- }
-
- /**
- * @return array
- */
- public function CustomContentTypeParams()
- {
- return $this->aCustomContentTypeParams;
- }
-
- /**
- * @return string
- */
- public function CID()
- {
- return $this->sCID;
- }
-
- /**
- * @return string
- */
- public function ContentLocation()
- {
- return $this->sContentLocation;
- }
-
- /**
- * @return string
- */
- public function FileName()
- {
- return $this->sFileName;
- }
-
- /**
- * @return int
- */
- public function FileSize()
- {
- return $this->iFileSize;
- }
-
- /**
- * @return bool
- */
- public function IsInline()
- {
- return $this->bIsInline;
- }
-
- /**
- * @return bool
- */
- public function IsImage()
- {
- return 'image' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName());
- }
-
- /**
- * @return bool
- */
- public function IsArchive()
- {
- return 'archive' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName());
- }
-
- /**
- * @return bool
- */
- public function IsPdf()
- {
- return 'pdf' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName());
- }
-
- /**
- * @return bool
- */
- public function IsDoc()
- {
- return 'doc' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName());
- }
-
- /**
- * @return bool
- */
- public function IsLinked()
- {
- return $this->bIsLinked && 0 < \strlen($this->sCID);
- }
+rResource = $rResource;
+ $this->sFileName = $sFileName;
+ $this->iFileSize = $iFileSize;
+ $this->bIsInline = $bIsInline;
+ $this->bIsLinked = $bIsLinked;
+ $this->sCID = $sCID;
+ $this->aCustomContentTypeParams = $aCustomContentTypeParams;
+ $this->sContentLocation = $sContentLocation;
+ }
+
+ /**
+ * @param resource $rResource
+ * @param string $sFileName = ''
+ * @param int $iFileSize = 0
+ * @param bool $bIsInline = false
+ * @param bool $bIsLinked = false
+ * @param string $sCID = ''
+ * @param array $aCustomContentTypeParams = array()
+ * @param string $sContentLocation = ''
+ *
+ * @return \MailSo\Mime\Attachment
+ */
+ public static function NewInstance($rResource, $sFileName = '', $iFileSize = 0, $bIsInline = false,
+ $bIsLinked = false, $sCID = '', $aCustomContentTypeParams = array(), $sContentLocation = '')
+ {
+ return new self($rResource, $sFileName, $iFileSize, $bIsInline, $bIsLinked, $sCID, $aCustomContentTypeParams, $sContentLocation);
+ }
+
+ /**
+ * @return resource
+ */
+ public function Resource()
+ {
+ return $this->rResource;
+ }
+
+ /**
+ * @return string
+ */
+ public function ContentType()
+ {
+ return \MailSo\Base\Utils::MimeContentType($this->sFileName);
+ }
+
+ /**
+ * @return array
+ */
+ public function CustomContentTypeParams()
+ {
+ return $this->aCustomContentTypeParams;
+ }
+
+ /**
+ * @return string
+ */
+ public function CID()
+ {
+ return $this->sCID;
+ }
+
+ /**
+ * @return string
+ */
+ public function ContentLocation()
+ {
+ return $this->sContentLocation;
+ }
+
+ /**
+ * @return string
+ */
+ public function FileName()
+ {
+ return $this->sFileName;
+ }
+
+ /**
+ * @return int
+ */
+ public function FileSize()
+ {
+ return $this->iFileSize;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsInline()
+ {
+ return $this->bIsInline;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsImage()
+ {
+ return 'image' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName());
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsArchive()
+ {
+ return 'archive' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName());
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsPdf()
+ {
+ return 'pdf' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName());
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsDoc()
+ {
+ return 'doc' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName());
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsLinked()
+ {
+ return $this->bIsLinked && 0 < \strlen($this->sCID);
+ }
}
\ No newline at end of file
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/AttachmentCollection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/AttachmentCollection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/AttachmentCollection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/AttachmentCollection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/Email.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Email.php
similarity index 95%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/Email.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Email.php
index 9dd393f5d0417192cf9e352362779f423bf81477..6347f0f813255f3dc202f85ef13c08c1f9102792 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/Email.php
+++ b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Email.php
@@ -1,315 +1,315 @@
-sEmail = \MailSo\Base\Utils::IdnToAscii(
- \MailSo\Base\Utils::Trim($sEmail), true);
-
- $this->sDisplayName = \MailSo\Base\Utils::Trim($sDisplayName);
-
- $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::NONE;
- $this->sDkimValue = '';
- }
-
- /**
- * @param string $sEmail
- * @param string $sDisplayName = ''
- *
- * @return \MailSo\Mime\Email
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- */
- public static function NewInstance($sEmail, $sDisplayName = '')
- {
- return new self($sEmail, $sDisplayName);
- }
-
- /**
- * @param string $sEmailAddress
- * @return \MailSo\Mime\Email
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- */
- public static function Parse($sEmailAddress)
- {
- $sEmailAddress = \MailSo\Base\Utils::Trim($sEmailAddress);
- if (!\MailSo\Base\Validator::NotEmptyString($sEmailAddress, true))
- {
- throw new \MailSo\Base\Exceptions\InvalidArgumentException();
- }
-
- $sName = '';
- $sEmail = '';
- $sComment = '';
-
- $bInName = false;
- $bInAddress = false;
- $bInComment = false;
-
- $iStartIndex = 0;
- $iEndIndex = 0;
- $iCurrentIndex = 0;
-
- while ($iCurrentIndex < \strlen($sEmailAddress))
- {
- switch ($sEmailAddress{$iCurrentIndex})
- {
-// case '\'':
- case '"':
-// $sQuoteChar = $sEmailAddress{$iCurrentIndex};
- if ((!$bInName) && (!$bInAddress) && (!$bInComment))
- {
- $bInName = true;
- $iStartIndex = $iCurrentIndex;
- }
- else if ((!$bInAddress) && (!$bInComment))
- {
- $iEndIndex = $iCurrentIndex;
- $sName = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
- $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
- $iEndIndex = 0;
- $iCurrentIndex = 0;
- $iStartIndex = 0;
- $bInName = false;
- }
- break;
- case '<':
- if ((!$bInName) && (!$bInAddress) && (!$bInComment))
- {
- if ($iCurrentIndex > 0 && \strlen($sName) === 0)
- {
- $sName = \substr($sEmailAddress, 0, $iCurrentIndex);
- }
-
- $bInAddress = true;
- $iStartIndex = $iCurrentIndex;
- }
- break;
- case '>':
- if ($bInAddress)
- {
- $iEndIndex = $iCurrentIndex;
- $sEmail = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
- $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
- $iEndIndex = 0;
- $iCurrentIndex = 0;
- $iStartIndex = 0;
- $bInAddress = false;
- }
- break;
- case '(':
- if ((!$bInName) && (!$bInAddress) && (!$bInComment))
- {
- $bInComment = true;
- $iStartIndex = $iCurrentIndex;
- }
- break;
- case ')':
- if ($bInComment)
- {
- $iEndIndex = $iCurrentIndex;
- $sComment = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
- $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
- $iEndIndex = 0;
- $iCurrentIndex = 0;
- $iStartIndex = 0;
- $bInComment = false;
- }
- break;
- case '\\':
- $iCurrentIndex++;
- break;
- }
-
- $iCurrentIndex++;
- }
-
- if (\strlen($sEmail) === 0)
- {
- $aRegs = array('');
- if (\preg_match('/[^@\s]+@\S+/i', $sEmailAddress, $aRegs) && isset($aRegs[0]))
- {
- $sEmail = $aRegs[0];
- }
- else
- {
- $sName = $sEmailAddress;
- }
- }
-
- if ((\strlen($sEmail) > 0) && (\strlen($sName) == 0) && (\strlen($sComment) == 0))
- {
- $sName = \str_replace($sEmail, '', $sEmailAddress);
- }
-
- $sEmail = \trim(\trim($sEmail), '<>');
- $sEmail = \rtrim(\trim($sEmail), '.');
- $sEmail = \trim($sEmail);
-
- $sName = \trim(\trim($sName), '"');
- $sName = \trim($sName, '\'');
- $sComment = \trim(\trim($sComment), '()');
-
- // Remove backslash
- $sName = \preg_replace('/\\\\(.)/s', '$1', $sName);
- $sComment = \preg_replace('/\\\\(.)/s', '$1', $sComment);
-
- return Email::NewInstance($sEmail, $sName);
- }
-
- /**
- * @param bool $bIdn = false
- *
- * @return string
- */
- public function GetEmail($bIdn = false)
- {
- return $bIdn ? \MailSo\Base\Utils::IdnToUtf8($this->sEmail) : $this->sEmail;
- }
-
- /**
- * @return string
- */
- public function GetDisplayName()
- {
- return $this->sDisplayName;
- }
-
- /**
- * @return string
- */
- public function GetDkimStatus()
- {
- return $this->sDkimStatus;
- }
-
- /**
- * @return string
- */
- public function GetDkimValue()
- {
- return $this->sDkimValue;
- }
-
- /**
- * @return string
- */
- public function GetAccountName()
- {
- return \MailSo\Base\Utils::GetAccountNameFromEmail($this->GetEmail(false));
- }
-
- /**
- * @param bool $bIdn = false
- *
- * @return string
- */
- public function GetDomain($bIdn = false)
- {
- return \MailSo\Base\Utils::GetDomainFromEmail($this->GetEmail($bIdn));
- }
-
- /**
- * @param string $sDkimStatus
- * @param string $sDkimValue = ''
- */
- public function SetDkimStatusAndValue($sDkimStatus, $sDkimValue = '')
- {
- $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::normalizeValue($sDkimStatus);
- $this->sDkimValue = $sDkimValue;
- }
-
- /**
- * @param bool $bIdn = false
- * @param bool $bDkim = true
- *
- * @return array
- */
- public function ToArray($bIdn = false, $bDkim = true)
- {
- return $bDkim ?
- array($this->sDisplayName, $this->GetEmail($bIdn), $this->sDkimStatus, $this->sDkimValue) :
- array($this->sDisplayName, $this->GetEmail($bIdn));
- }
-
- /**
- * @param bool $bConvertSpecialsName = false
- * @param bool $bIdn = false
- *
- * @return string
- */
- public function ToString($bConvertSpecialsName = false, $bIdn = false)
- {
- $sReturn = '';
-
- $sDisplayName = \str_replace('"', '\"', $this->sDisplayName);
- if ($bConvertSpecialsName)
- {
- $sDisplayName = 0 === \strlen($sDisplayName) ? '' : \MailSo\Base\Utils::EncodeUnencodedValue(
- \MailSo\Base\Enumerations\Encoding::BASE64_SHORT,
- $sDisplayName);
- }
-
- $sDisplayName = 0 === \strlen($sDisplayName) ? '' : '"'.$sDisplayName.'"';
- if (0 < \strlen($this->sEmail))
- {
- $sReturn = $this->GetEmail($bIdn);
- if (0 < \strlen($sDisplayName))
- {
- $sReturn = $sDisplayName.' <'.$sReturn.'>';
- }
- }
-
- return \trim($sReturn);
- }
-}
+sEmail = \MailSo\Base\Utils::IdnToAscii(
+ \MailSo\Base\Utils::Trim($sEmail), true);
+
+ $this->sDisplayName = \MailSo\Base\Utils::Trim($sDisplayName);
+
+ $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::NONE;
+ $this->sDkimValue = '';
+ }
+
+ /**
+ * @param string $sEmail
+ * @param string $sDisplayName = ''
+ *
+ * @return \MailSo\Mime\Email
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public static function NewInstance($sEmail, $sDisplayName = '')
+ {
+ return new self($sEmail, $sDisplayName);
+ }
+
+ /**
+ * @param string $sEmailAddress
+ * @return \MailSo\Mime\Email
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public static function Parse($sEmailAddress)
+ {
+ $sEmailAddress = \MailSo\Base\Utils::Trim($sEmailAddress);
+ if (!\MailSo\Base\Validator::NotEmptyString($sEmailAddress, true))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $sName = '';
+ $sEmail = '';
+ $sComment = '';
+
+ $bInName = false;
+ $bInAddress = false;
+ $bInComment = false;
+
+ $iStartIndex = 0;
+ $iEndIndex = 0;
+ $iCurrentIndex = 0;
+
+ while ($iCurrentIndex < \strlen($sEmailAddress))
+ {
+ switch ($sEmailAddress{$iCurrentIndex})
+ {
+// case '\'':
+ case '"':
+// $sQuoteChar = $sEmailAddress{$iCurrentIndex};
+ if ((!$bInName) && (!$bInAddress) && (!$bInComment))
+ {
+ $bInName = true;
+ $iStartIndex = $iCurrentIndex;
+ }
+ else if ((!$bInAddress) && (!$bInComment))
+ {
+ $iEndIndex = $iCurrentIndex;
+ $sName = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
+ $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
+ $iEndIndex = 0;
+ $iCurrentIndex = 0;
+ $iStartIndex = 0;
+ $bInName = false;
+ }
+ break;
+ case '<':
+ if ((!$bInName) && (!$bInAddress) && (!$bInComment))
+ {
+ if ($iCurrentIndex > 0 && \strlen($sName) === 0)
+ {
+ $sName = \substr($sEmailAddress, 0, $iCurrentIndex);
+ }
+
+ $bInAddress = true;
+ $iStartIndex = $iCurrentIndex;
+ }
+ break;
+ case '>':
+ if ($bInAddress)
+ {
+ $iEndIndex = $iCurrentIndex;
+ $sEmail = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
+ $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
+ $iEndIndex = 0;
+ $iCurrentIndex = 0;
+ $iStartIndex = 0;
+ $bInAddress = false;
+ }
+ break;
+ case '(':
+ if ((!$bInName) && (!$bInAddress) && (!$bInComment))
+ {
+ $bInComment = true;
+ $iStartIndex = $iCurrentIndex;
+ }
+ break;
+ case ')':
+ if ($bInComment)
+ {
+ $iEndIndex = $iCurrentIndex;
+ $sComment = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
+ $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
+ $iEndIndex = 0;
+ $iCurrentIndex = 0;
+ $iStartIndex = 0;
+ $bInComment = false;
+ }
+ break;
+ case '\\':
+ $iCurrentIndex++;
+ break;
+ }
+
+ $iCurrentIndex++;
+ }
+
+ if (\strlen($sEmail) === 0)
+ {
+ $aRegs = array('');
+ if (\preg_match('/[^@\s]+@\S+/i', $sEmailAddress, $aRegs) && isset($aRegs[0]))
+ {
+ $sEmail = $aRegs[0];
+ }
+ else
+ {
+ $sName = $sEmailAddress;
+ }
+ }
+
+ if ((\strlen($sEmail) > 0) && (\strlen($sName) == 0) && (\strlen($sComment) == 0))
+ {
+ $sName = \str_replace($sEmail, '', $sEmailAddress);
+ }
+
+ $sEmail = \trim(\trim($sEmail), '<>');
+ $sEmail = \rtrim(\trim($sEmail), '.');
+ $sEmail = \trim($sEmail);
+
+ $sName = \trim(\trim($sName), '"');
+ $sName = \trim($sName, '\'');
+ $sComment = \trim(\trim($sComment), '()');
+
+ // Remove backslash
+ $sName = \preg_replace('/\\\\(.)/s', '$1', $sName);
+ $sComment = \preg_replace('/\\\\(.)/s', '$1', $sComment);
+
+ return Email::NewInstance($sEmail, $sName);
+ }
+
+ /**
+ * @param bool $bIdn = false
+ *
+ * @return string
+ */
+ public function GetEmail($bIdn = false)
+ {
+ return $bIdn ? \MailSo\Base\Utils::IdnToUtf8($this->sEmail) : $this->sEmail;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetDisplayName()
+ {
+ return $this->sDisplayName;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetDkimStatus()
+ {
+ return $this->sDkimStatus;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetDkimValue()
+ {
+ return $this->sDkimValue;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetAccountName()
+ {
+ return \MailSo\Base\Utils::GetAccountNameFromEmail($this->GetEmail(false));
+ }
+
+ /**
+ * @param bool $bIdn = false
+ *
+ * @return string
+ */
+ public function GetDomain($bIdn = false)
+ {
+ return \MailSo\Base\Utils::GetDomainFromEmail($this->GetEmail($bIdn));
+ }
+
+ /**
+ * @param string $sDkimStatus
+ * @param string $sDkimValue = ''
+ */
+ public function SetDkimStatusAndValue($sDkimStatus, $sDkimValue = '')
+ {
+ $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::normalizeValue($sDkimStatus);
+ $this->sDkimValue = $sDkimValue;
+ }
+
+ /**
+ * @param bool $bIdn = false
+ * @param bool $bDkim = true
+ *
+ * @return array
+ */
+ public function ToArray($bIdn = false, $bDkim = true)
+ {
+ return $bDkim ?
+ array($this->sDisplayName, $this->GetEmail($bIdn), $this->sDkimStatus, $this->sDkimValue) :
+ array($this->sDisplayName, $this->GetEmail($bIdn));
+ }
+
+ /**
+ * @param bool $bConvertSpecialsName = false
+ * @param bool $bIdn = false
+ *
+ * @return string
+ */
+ public function ToString($bConvertSpecialsName = false, $bIdn = false)
+ {
+ $sReturn = '';
+
+ $sDisplayName = \str_replace('"', '\"', $this->sDisplayName);
+ if ($bConvertSpecialsName)
+ {
+ $sDisplayName = 0 === \strlen($sDisplayName) ? '' : \MailSo\Base\Utils::EncodeUnencodedValue(
+ \MailSo\Base\Enumerations\Encoding::BASE64_SHORT,
+ $sDisplayName);
+ }
+
+ $sDisplayName = 0 === \strlen($sDisplayName) ? '' : '"'.$sDisplayName.'"';
+ if (0 < \strlen($this->sEmail))
+ {
+ $sReturn = $this->GetEmail($bIdn);
+ if (0 < \strlen($sDisplayName))
+ {
+ $sReturn = $sDisplayName.' <'.$sReturn.'>';
+ }
+ }
+
+ return \trim($sReturn);
+ }
+}
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/EmailCollection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/EmailCollection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/EmailCollection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/EmailCollection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/EmailDep.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/EmailDep.php
similarity index 95%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/EmailDep.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/EmailDep.php
index 64173bed359adca51f07c560605a7e34997ab6d5..7a923faee2a6f91054415c3f8fd74e6c82aaf009 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/EmailDep.php
+++ b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/EmailDep.php
@@ -1,339 +1,339 @@
-sEmail = \MailSo\Base\Utils::IdnToAscii(
- \MailSo\Base\Utils::Trim($sEmail), true);
-
- $this->sDisplayName = \MailSo\Base\Utils::Trim($sDisplayName);
- $this->sRemark = \MailSo\Base\Utils::Trim($sRemark);
-
- $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::NONE;
- $this->sDkimValue = '';
- }
-
- /**
- * @param string $sEmail
- * @param string $sDisplayName = ''
- * @param string $sRemark = ''
- *
- * @return \MailSo\Mime\Email
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- */
- public static function NewInstance($sEmail, $sDisplayName = '', $sRemark = '')
- {
- return new self($sEmail, $sDisplayName, $sRemark);
- }
-
- /**
- * @param string $sEmailAddress
- * @return \MailSo\Mime\Email
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- */
- public static function Parse($sEmailAddress)
- {
- $sEmailAddress = \MailSo\Base\Utils::Trim($sEmailAddress);
- if (!\MailSo\Base\Validator::NotEmptyString($sEmailAddress, true))
- {
- throw new \MailSo\Base\Exceptions\InvalidArgumentException();
- }
-
- $sName = '';
- $sEmail = '';
- $sComment = '';
-
- $bInName = false;
- $bInAddress = false;
- $bInComment = false;
-
- $iStartIndex = 0;
- $iEndIndex = 0;
- $iCurrentIndex = 0;
-
- while ($iCurrentIndex < \strlen($sEmailAddress))
- {
- switch ($sEmailAddress{$iCurrentIndex})
- {
-// case '\'':
- case '"':
-// $sQuoteChar = $sEmailAddress{$iCurrentIndex};
- if ((!$bInName) && (!$bInAddress) && (!$bInComment))
- {
- $bInName = true;
- $iStartIndex = $iCurrentIndex;
- }
- else if ((!$bInAddress) && (!$bInComment))
- {
- $iEndIndex = $iCurrentIndex;
- $sName = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
- $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
- $iEndIndex = 0;
- $iCurrentIndex = 0;
- $iStartIndex = 0;
- $bInName = false;
- }
- break;
- case '<':
- if ((!$bInName) && (!$bInAddress) && (!$bInComment))
- {
- if ($iCurrentIndex > 0 && \strlen($sName) === 0)
- {
- $sName = \substr($sEmailAddress, 0, $iCurrentIndex);
- }
-
- $bInAddress = true;
- $iStartIndex = $iCurrentIndex;
- }
- break;
- case '>':
- if ($bInAddress)
- {
- $iEndIndex = $iCurrentIndex;
- $sEmail = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
- $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
- $iEndIndex = 0;
- $iCurrentIndex = 0;
- $iStartIndex = 0;
- $bInAddress = false;
- }
- break;
- case '(':
- if ((!$bInName) && (!$bInAddress) && (!$bInComment))
- {
- $bInComment = true;
- $iStartIndex = $iCurrentIndex;
- }
- break;
- case ')':
- if ($bInComment)
- {
- $iEndIndex = $iCurrentIndex;
- $sComment = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
- $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
- $iEndIndex = 0;
- $iCurrentIndex = 0;
- $iStartIndex = 0;
- $bInComment = false;
- }
- break;
- case '\\':
- $iCurrentIndex++;
- break;
- }
-
- $iCurrentIndex++;
- }
-
- if (\strlen($sEmail) === 0)
- {
- $aRegs = array('');
- if (\preg_match('/[^@\s]+@\S+/i', $sEmailAddress, $aRegs) && isset($aRegs[0]))
- {
- $sEmail = $aRegs[0];
- }
- else
- {
- $sName = $sEmailAddress;
- }
- }
-
- if ((\strlen($sEmail) > 0) && (\strlen($sName) == 0) && (\strlen($sComment) == 0))
- {
- $sName = \str_replace($sEmail, '', $sEmailAddress);
- }
-
- $sEmail = \trim(\trim($sEmail), '<>');
- $sEmail = \rtrim(\trim($sEmail), '.');
- $sEmail = \trim($sEmail);
-
- $sName = \trim(\trim($sName), '"');
- $sName = \trim($sName, '\'');
- $sComment = \trim(\trim($sComment), '()');
-
- // Remove backslash
- $sName = \preg_replace('/\\\\(.)/s', '$1', $sName);
- $sComment = \preg_replace('/\\\\(.)/s', '$1', $sComment);
-
- return Email::NewInstance($sEmail, $sName, $sComment);
- }
-
- /**
- * @param bool $bIdn = false
- *
- * @return string
- */
- public function GetEmail($bIdn = false)
- {
- return $bIdn ? \MailSo\Base\Utils::IdnToUtf8($this->sEmail) : $this->sEmail;
- }
-
- /**
- * @return string
- */
- public function GetDisplayName()
- {
- return $this->sDisplayName;
- }
-
- /**
- * @return string
- */
- public function GetRemark()
- {
- return $this->sRemark;
- }
-
- /**
- * @return string
- */
- public function GetDkimStatus()
- {
- return $this->sDkimStatus;
- }
-
- /**
- * @return string
- */
- public function GetDkimValue()
- {
- return $this->sDkimValue;
- }
-
- /**
- * @return string
- */
- public function GetAccountName()
- {
- return \MailSo\Base\Utils::GetAccountNameFromEmail($this->GetEmail(false));
- }
-
- /**
- * @param bool $bIdn = false
- *
- * @return string
- */
- public function GetDomain($bIdn = false)
- {
- return \MailSo\Base\Utils::GetDomainFromEmail($this->GetEmail($bIdn));
- }
-
- /**
- * @param string $sDkimStatus
- * @param string $sDkimValue = ''
- */
- public function SetDkimStatusAndValue($sDkimStatus, $sDkimValue = '')
- {
- $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::normalizeValue($sDkimStatus);
- $this->sDkimValue = $sDkimValue;
- }
-
- /**
- * @param bool $bIdn = false
- * @param bool $bDkim = true
- *
- * @return array
- */
- public function ToArray($bIdn = false, $bDkim = true)
- {
- return $bDkim ? array($this->sDisplayName, $this->GetEmail($bIdn), $this->sRemark, $this->sDkimStatus, $this->sDkimValue) :
- array($this->sDisplayName, $this->GetEmail($bIdn), $this->sRemark);
- }
-
- /**
- * @param bool $bConvertSpecialsName = false
- * @param bool $bIdn = false
- *
- * @return string
- */
- public function ToString($bConvertSpecialsName = false, $bIdn = false)
- {
- $sReturn = '';
-
- $sRemark = \str_replace(')', '\)', $this->sRemark);
- $sDisplayName = \str_replace('"', '\"', $this->sDisplayName);
-
- if ($bConvertSpecialsName)
- {
- $sDisplayName = 0 === \strlen($sDisplayName) ? '' : \MailSo\Base\Utils::EncodeUnencodedValue(
- \MailSo\Base\Enumerations\Encoding::BASE64_SHORT,
- $sDisplayName);
-
- $sRemark = 0 === \strlen($sRemark) ? '' : \MailSo\Base\Utils::EncodeUnencodedValue(
- \MailSo\Base\Enumerations\Encoding::BASE64_SHORT,
- $sRemark);
- }
-
- $sDisplayName = 0 === \strlen($sDisplayName) ? '' : '"'.$sDisplayName.'"';
- $sRemark = 0 === \strlen($sRemark) ? '' : '('.$sRemark.')';
-
- if (0 < \strlen($this->sEmail))
- {
- $sReturn = $this->GetEmail($bIdn);
- if (0 < \strlen($sDisplayName.$sRemark))
- {
- $sReturn = $sDisplayName.' <'.$sReturn.'> '.$sRemark;
- }
- }
-
- return \trim($sReturn);
- }
-}
+sEmail = \MailSo\Base\Utils::IdnToAscii(
+ \MailSo\Base\Utils::Trim($sEmail), true);
+
+ $this->sDisplayName = \MailSo\Base\Utils::Trim($sDisplayName);
+ $this->sRemark = \MailSo\Base\Utils::Trim($sRemark);
+
+ $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::NONE;
+ $this->sDkimValue = '';
+ }
+
+ /**
+ * @param string $sEmail
+ * @param string $sDisplayName = ''
+ * @param string $sRemark = ''
+ *
+ * @return \MailSo\Mime\Email
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public static function NewInstance($sEmail, $sDisplayName = '', $sRemark = '')
+ {
+ return new self($sEmail, $sDisplayName, $sRemark);
+ }
+
+ /**
+ * @param string $sEmailAddress
+ * @return \MailSo\Mime\Email
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public static function Parse($sEmailAddress)
+ {
+ $sEmailAddress = \MailSo\Base\Utils::Trim($sEmailAddress);
+ if (!\MailSo\Base\Validator::NotEmptyString($sEmailAddress, true))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $sName = '';
+ $sEmail = '';
+ $sComment = '';
+
+ $bInName = false;
+ $bInAddress = false;
+ $bInComment = false;
+
+ $iStartIndex = 0;
+ $iEndIndex = 0;
+ $iCurrentIndex = 0;
+
+ while ($iCurrentIndex < \strlen($sEmailAddress))
+ {
+ switch ($sEmailAddress{$iCurrentIndex})
+ {
+// case '\'':
+ case '"':
+// $sQuoteChar = $sEmailAddress{$iCurrentIndex};
+ if ((!$bInName) && (!$bInAddress) && (!$bInComment))
+ {
+ $bInName = true;
+ $iStartIndex = $iCurrentIndex;
+ }
+ else if ((!$bInAddress) && (!$bInComment))
+ {
+ $iEndIndex = $iCurrentIndex;
+ $sName = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
+ $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
+ $iEndIndex = 0;
+ $iCurrentIndex = 0;
+ $iStartIndex = 0;
+ $bInName = false;
+ }
+ break;
+ case '<':
+ if ((!$bInName) && (!$bInAddress) && (!$bInComment))
+ {
+ if ($iCurrentIndex > 0 && \strlen($sName) === 0)
+ {
+ $sName = \substr($sEmailAddress, 0, $iCurrentIndex);
+ }
+
+ $bInAddress = true;
+ $iStartIndex = $iCurrentIndex;
+ }
+ break;
+ case '>':
+ if ($bInAddress)
+ {
+ $iEndIndex = $iCurrentIndex;
+ $sEmail = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
+ $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
+ $iEndIndex = 0;
+ $iCurrentIndex = 0;
+ $iStartIndex = 0;
+ $bInAddress = false;
+ }
+ break;
+ case '(':
+ if ((!$bInName) && (!$bInAddress) && (!$bInComment))
+ {
+ $bInComment = true;
+ $iStartIndex = $iCurrentIndex;
+ }
+ break;
+ case ')':
+ if ($bInComment)
+ {
+ $iEndIndex = $iCurrentIndex;
+ $sComment = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
+ $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
+ $iEndIndex = 0;
+ $iCurrentIndex = 0;
+ $iStartIndex = 0;
+ $bInComment = false;
+ }
+ break;
+ case '\\':
+ $iCurrentIndex++;
+ break;
+ }
+
+ $iCurrentIndex++;
+ }
+
+ if (\strlen($sEmail) === 0)
+ {
+ $aRegs = array('');
+ if (\preg_match('/[^@\s]+@\S+/i', $sEmailAddress, $aRegs) && isset($aRegs[0]))
+ {
+ $sEmail = $aRegs[0];
+ }
+ else
+ {
+ $sName = $sEmailAddress;
+ }
+ }
+
+ if ((\strlen($sEmail) > 0) && (\strlen($sName) == 0) && (\strlen($sComment) == 0))
+ {
+ $sName = \str_replace($sEmail, '', $sEmailAddress);
+ }
+
+ $sEmail = \trim(\trim($sEmail), '<>');
+ $sEmail = \rtrim(\trim($sEmail), '.');
+ $sEmail = \trim($sEmail);
+
+ $sName = \trim(\trim($sName), '"');
+ $sName = \trim($sName, '\'');
+ $sComment = \trim(\trim($sComment), '()');
+
+ // Remove backslash
+ $sName = \preg_replace('/\\\\(.)/s', '$1', $sName);
+ $sComment = \preg_replace('/\\\\(.)/s', '$1', $sComment);
+
+ return Email::NewInstance($sEmail, $sName, $sComment);
+ }
+
+ /**
+ * @param bool $bIdn = false
+ *
+ * @return string
+ */
+ public function GetEmail($bIdn = false)
+ {
+ return $bIdn ? \MailSo\Base\Utils::IdnToUtf8($this->sEmail) : $this->sEmail;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetDisplayName()
+ {
+ return $this->sDisplayName;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetRemark()
+ {
+ return $this->sRemark;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetDkimStatus()
+ {
+ return $this->sDkimStatus;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetDkimValue()
+ {
+ return $this->sDkimValue;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetAccountName()
+ {
+ return \MailSo\Base\Utils::GetAccountNameFromEmail($this->GetEmail(false));
+ }
+
+ /**
+ * @param bool $bIdn = false
+ *
+ * @return string
+ */
+ public function GetDomain($bIdn = false)
+ {
+ return \MailSo\Base\Utils::GetDomainFromEmail($this->GetEmail($bIdn));
+ }
+
+ /**
+ * @param string $sDkimStatus
+ * @param string $sDkimValue = ''
+ */
+ public function SetDkimStatusAndValue($sDkimStatus, $sDkimValue = '')
+ {
+ $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::normalizeValue($sDkimStatus);
+ $this->sDkimValue = $sDkimValue;
+ }
+
+ /**
+ * @param bool $bIdn = false
+ * @param bool $bDkim = true
+ *
+ * @return array
+ */
+ public function ToArray($bIdn = false, $bDkim = true)
+ {
+ return $bDkim ? array($this->sDisplayName, $this->GetEmail($bIdn), $this->sRemark, $this->sDkimStatus, $this->sDkimValue) :
+ array($this->sDisplayName, $this->GetEmail($bIdn), $this->sRemark);
+ }
+
+ /**
+ * @param bool $bConvertSpecialsName = false
+ * @param bool $bIdn = false
+ *
+ * @return string
+ */
+ public function ToString($bConvertSpecialsName = false, $bIdn = false)
+ {
+ $sReturn = '';
+
+ $sRemark = \str_replace(')', '\)', $this->sRemark);
+ $sDisplayName = \str_replace('"', '\"', $this->sDisplayName);
+
+ if ($bConvertSpecialsName)
+ {
+ $sDisplayName = 0 === \strlen($sDisplayName) ? '' : \MailSo\Base\Utils::EncodeUnencodedValue(
+ \MailSo\Base\Enumerations\Encoding::BASE64_SHORT,
+ $sDisplayName);
+
+ $sRemark = 0 === \strlen($sRemark) ? '' : \MailSo\Base\Utils::EncodeUnencodedValue(
+ \MailSo\Base\Enumerations\Encoding::BASE64_SHORT,
+ $sRemark);
+ }
+
+ $sDisplayName = 0 === \strlen($sDisplayName) ? '' : '"'.$sDisplayName.'"';
+ $sRemark = 0 === \strlen($sRemark) ? '' : '('.$sRemark.')';
+
+ if (0 < \strlen($this->sEmail))
+ {
+ $sReturn = $this->GetEmail($bIdn);
+ if (0 < \strlen($sDisplayName.$sRemark))
+ {
+ $sReturn = $sDisplayName.' <'.$sReturn.'> '.$sRemark;
+ }
+ }
+
+ return \trim($sReturn);
+ }
+}
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/Enumerations/Constants.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Enumerations/Constants.php
similarity index 94%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/Enumerations/Constants.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Enumerations/Constants.php
index 7f52ee8909dccb153a56784d4af29b292d6c6b18..41da58188336178fe93c674daab378bb3bf58897 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/Enumerations/Constants.php
+++ b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Enumerations/Constants.php
@@ -1,25 +1,25 @@
-sRawHeaders = '';
- $this->sParentCharset = '';
-
- if (0 < \strlen($sRawHeaders))
- {
- $this->Parse($sRawHeaders, $bStoreRawHeaders);
- }
- }
-
- /**
- * @param string $sRawHeaders = ''
- * @param bool $bStoreRawHeaders = true
- *
- * @return \MailSo\Mime\HeaderCollection
- */
- public static function NewInstance($sRawHeaders = '', $bStoreRawHeaders = true)
- {
- return new self($sRawHeaders, $bStoreRawHeaders);
- }
-
- /**
- * @param string $sName
- * @param string $sValue
- * @param bool $bToTop = false
- *
- * @return \MailSo\Mime\HeaderCollection
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- */
- public function AddByName($sName, $sValue, $bToTop = false)
- {
- return $this->Add(Header::NewInstance($sName, $sValue), $bToTop);
- }
-
- /**
- * @param string $sName
- * @param string $sValue
- * @param bool $bToTop = false
- *
- * @return \MailSo\Mime\HeaderCollection
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- */
- public function SetByName($sName, $sValue, $bToTop = false)
- {
- return $this->RemoveByName($sName)->Add(Header::NewInstance($sName, $sValue), $bToTop);
- }
-
- /**
- * @return \MailSo\Mime\Header | null
- */
- public function &GetByIndex($iIndex)
- {
- $mResult = null;
- $mResult =& parent::GetByIndex($iIndex);
- return $mResult;
- }
-
- /**
- * @param string $sHeaderName
- * @param bool $bCharsetAutoDetect = false
- * @return string
- */
- public function ValueByName($sHeaderName, $bCharsetAutoDetect = false)
- {
- $oHeader = null;
- $oHeader =& $this->GetByName($sHeaderName);
- return (null !== $oHeader) ? ($bCharsetAutoDetect ? $oHeader->ValueWithCharsetAutoDetect() : $oHeader->Value()) : '';
- }
-
- /**
- * @param string $sHeaderName
- * @param bool $bCharsetAutoDetect = false
- * @return array
- */
- public function ValuesByName($sHeaderName, $bCharsetAutoDetect = false)
- {
- $aResult = array();
- $oHeader = null;
-
- $sHeaderNameLower = \strtolower($sHeaderName);
- $aHeaders =& $this->GetAsArray();
- foreach ($aHeaders as /* @var $oHeader \MailSo\Mime\Header */ &$oHeader)
- {
- if ($sHeaderNameLower === \strtolower($oHeader->Name()))
- {
- $aResult[] = $bCharsetAutoDetect ? $oHeader->ValueWithCharsetAutoDetect() : $oHeader->Value();
- }
- }
-
- return $aResult;
- }
-
- /**
- * @param string $sHeaderName
- *
- * @return \MailSo\Mime\HeaderCollection
- */
- public function RemoveByName($sHeaderName)
- {
- $aResult = $this->FilterList(function ($oHeader) use ($sHeaderName) {
- return $oHeader && \strtolower($oHeader->Name()) !== \strtolower($sHeaderName);
- });
-
- return $this->SetAsArray($aResult);
- }
-
- /**
- * @param string $sHeaderName
- * @param bool $bCharsetAutoDetect = false
- *
- * @return \MailSo\Mime\EmailCollection|null
- */
- public function GetAsEmailCollection($sHeaderName, $bCharsetAutoDetect = false)
- {
- $oResult = null;
- $sValue = $this->ValueByName($sHeaderName, $bCharsetAutoDetect);
- if (0 < \strlen($sValue))
- {
- $oResult = \MailSo\Mime\EmailCollection::NewInstance($sValue);
- }
-
- return $oResult && 0 < $oResult->Count() ? $oResult : null;
- }
-
- /**
- * @param string $sHeaderName
- * @return \MailSo\Mime\ParameterCollection|null
- */
- public function ParametersByName($sHeaderName)
- {
- $oParameters = $oHeader = null;
- $oHeader =& $this->GetByName($sHeaderName);
- if ($oHeader)
- {
- $oParameters = $oHeader->Parameters();
- }
-
- return $oParameters;
- }
-
- /**
- * @param string $sHeaderName
- * @param string $sParamName
- * @return string
- */
- public function ParameterValue($sHeaderName, $sParamName)
- {
- $oParameters = $this->ParametersByName($sHeaderName);
- return (null !== $oParameters) ? $oParameters->ParameterValueByName($sParamName) : '';
- }
-
- /**
- * @param string $sHeaderName
- * @return \MailSo\Mime\Header | false
- */
- public function &GetByName($sHeaderName)
- {
- $oResult = $oHeader = null;
-
- $sHeaderNameLower = \strtolower($sHeaderName);
- $aHeaders =& $this->GetAsArray();
- foreach ($aHeaders as /* @var $oHeader \MailSo\Mime\Header */ &$oHeader)
- {
- if ($sHeaderNameLower === \strtolower($oHeader->Name()))
- {
- $oResult =& $oHeader;
- break;
- }
- }
-
- return $oResult;
- }
-
- /**
- * @param array $aList
- * @return \MailSo\Mime\HeaderCollection
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- */
- public function SetAsArray($aList)
- {
- parent::SetAsArray($aList);
-
- return $this;
- }
-
- /**
- * @param string $sParentCharset
- * @return \MailSo\Mime\HeaderCollection
- */
- public function SetParentCharset($sParentCharset)
- {
- if (0 < \strlen($sParentCharset))
- {
- if ($this->sParentCharset !== $sParentCharset)
- {
- $oHeader = null;
- $aHeaders =& $this->GetAsArray();
-
- foreach ($aHeaders as /* @var $oHeader \MailSo\Mime\Header */ &$oHeader)
- {
- $oHeader->SetParentCharset($sParentCharset);
- }
-
- $this->sParentCharset = $sParentCharset;
- }
- }
-
- return $this;
- }
-
- /**
- * @return void
- */
- public function Clear()
- {
- parent::Clear();
-
- $this->sRawHeaders = '';
- }
-
- /**
- * @param string $sRawHeaders
- * @param bool $bStoreRawHeaders = false
- * @param string $sParentCharset = ''
- *
- * @return \MailSo\Mime\HeaderCollection
- */
- public function Parse($sRawHeaders, $bStoreRawHeaders = false, $sParentCharset = '')
- {
- $this->Clear();
-
- if ($bStoreRawHeaders)
- {
- $this->sRawHeaders = $sRawHeaders;
- }
-
- if (0 === \strlen($this->sParentCharset))
- {
- $this->sParentCharset = $sParentCharset;
- }
-
- $aHeaders = \explode("\n", \str_replace("\r", '', $sRawHeaders));
-
- $sName = null;
- $sValue = null;
- foreach ($aHeaders as $sHeadersValue)
- {
- if (0 === strlen($sHeadersValue))
- {
- continue;
- }
-
- $sFirstChar = \substr($sHeadersValue, 0, 1);
- if ($sFirstChar !== ' ' && $sFirstChar !== "\t" && false === \strpos($sHeadersValue, ':'))
- {
- continue;
- }
- else if (null !== $sName && ($sFirstChar === ' ' || $sFirstChar === "\t"))
- {
- $sValue = \is_null($sValue) ? '' : $sValue;
-
- if ('?=' === \substr(\rtrim($sHeadersValue), -2))
- {
- $sHeadersValue = \rtrim($sHeadersValue);
- }
-
- if ('=?' === \substr(\ltrim($sHeadersValue), 0, 2))
- {
- $sHeadersValue = \ltrim($sHeadersValue);
- }
-
- if ('=?' === \substr($sHeadersValue, 0, 2))
- {
- $sValue .= $sHeadersValue;
- }
- else
- {
- $sValue .= "\n".$sHeadersValue;
- }
- }
- else
- {
- if (null !== $sName)
- {
- $oHeader = Header::NewInstanceFromEncodedString($sName.': '.$sValue, $this->sParentCharset);
- if ($oHeader)
- {
- $this->Add($oHeader);
- }
-
- $sName = null;
- $sValue = null;
- }
-
- $aHeaderParts = \explode(':', $sHeadersValue, 2);
- $sName = $aHeaderParts[0];
- $sValue = isset($aHeaderParts[1]) ? $aHeaderParts[1] : '';
-
- if ('?=' === \substr(\rtrim($sValue), -2))
- {
- $sValue = \rtrim($sValue);
- }
- }
- }
-
- if (null !== $sName)
- {
- $oHeader = Header::NewInstanceFromEncodedString($sName.': '.$sValue, $this->sParentCharset);
- if ($oHeader)
- {
- $this->Add($oHeader);
- }
- }
-
- return $this;
- }
-
- /**
- * @return int
- */
- public function DkimStatuses()
- {
- $aResult = array();
-
- $aHeaders = $this->ValuesByName(\MailSo\Mime\Enumerations\Header::AUTHENTICATION_RESULTS);
- if (\is_array($aHeaders) && 0 < \count($aHeaders))
- {
- foreach ($aHeaders as $sHeaderValue)
- {
- $sStatus = '';
- $sHeader = '';
- $sDkimLine = '';
-
- $aMatch = array();
-
- $sHeaderValue = \preg_replace('/[\r\n\t\s]+/', ' ', $sHeaderValue);
-
- if (\preg_match('/dkim=.+/i', $sHeaderValue, $aMatch) && !empty($aMatch[0]))
- {
- $sDkimLine = $aMatch[0];
-
- $aMatch = array();
- if (\preg_match('/dkim=([a-zA-Z0-9]+)/i', $sDkimLine, $aMatch) && !empty($aMatch[1]))
- {
- $sStatus = $aMatch[1];
- }
-
- $aMatch = array();
- if (\preg_match('/header\.(d|i|from)=([^\s;]+)/i', $sDkimLine, $aMatch) && !empty($aMatch[2]))
- {
- $sHeader = \trim($aMatch[2]);
- }
-
- if (!empty($sStatus) && !empty($sHeader))
- {
- $aResult[] = array($sStatus, $sHeader, $sDkimLine);
- }
- }
- }
- }
- else
- {
- // X-DKIM-Authentication-Results: signer="hostinger.com" status="pass"
- $aHeaders = $this->ValuesByName(\MailSo\Mime\Enumerations\Header::X_DKIM_AUTHENTICATION_RESULTS);
- if (\is_array($aHeaders) && 0 < \count($aHeaders))
- {
- foreach ($aHeaders as $sHeaderValue)
- {
- $sStatus = '';
- $sHeader = '';
-
- $aMatch = array();
-
- $sHeaderValue = \preg_replace('/[\r\n\t\s]+/', ' ', $sHeaderValue);
-
- if (\preg_match('/status[\s]?=[\s]?"([a-zA-Z0-9]+)"/i', $sHeaderValue, $aMatch) && !empty($aMatch[1]))
- {
- $sStatus = $aMatch[1];
- }
-
- if (\preg_match('/signer[\s]?=[\s]?"([^";]+)"/i', $sHeaderValue, $aMatch) && !empty($aMatch[1]))
- {
- $sHeader = \trim($aMatch[1]);
- }
-
- if (!empty($sStatus) && !empty($sHeader))
- {
- $aResult[] = array($sStatus, $sHeader, $sHeaderValue);
- }
- }
- }
- }
-
- return $aResult;
- }
-
- /**
- * @return int
- */
- public function PopulateEmailColectionByDkim($oEmails)
- {
- if ($oEmails && $oEmails instanceof \MailSo\Mime\EmailCollection)
- {
- $aDkimStatuses = $this->DkimStatuses();
- if (\is_array($aDkimStatuses) && 0 < \count($aDkimStatuses))
- {
- $oEmails->ForeachList(function (/* @var $oItem \MailSo\Mime\Email */ $oItem) use ($aDkimStatuses) {
- if ($oItem && $oItem instanceof \MailSo\Mime\Email)
- {
- $sEmail = $oItem->GetEmail();
- foreach ($aDkimStatuses as $aDkimData)
- {
- if (isset($aDkimData[0], $aDkimData[1]) &&
- $aDkimData[1] === \strstr($sEmail, $aDkimData[1]))
- {
- $oItem->SetDkimStatusAndValue($aDkimData[0], empty($aDkimData[2]) ? '' : $aDkimData[2]);
- }
- }
- }
- });
- }
- }
- }
-
- /**
- * @return string
- */
- public function ToEncodedString()
- {
- $aResult = array();
- $aHeaders =& $this->GetAsArray();
- foreach ($aHeaders as /* @var $oHeader \MailSo\Mime\Header */ &$oHeader)
- {
- $aResult[] = $oHeader->EncodedValue();
- }
-
- return \implode(\MailSo\Mime\Enumerations\Constants::CRLF, $aResult);
- }
-}
+sRawHeaders = '';
+ $this->sParentCharset = '';
+
+ if (0 < \strlen($sRawHeaders))
+ {
+ $this->Parse($sRawHeaders, $bStoreRawHeaders);
+ }
+ }
+
+ /**
+ * @param string $sRawHeaders = ''
+ * @param bool $bStoreRawHeaders = true
+ *
+ * @return \MailSo\Mime\HeaderCollection
+ */
+ public static function NewInstance($sRawHeaders = '', $bStoreRawHeaders = true)
+ {
+ return new self($sRawHeaders, $bStoreRawHeaders);
+ }
+
+ /**
+ * @param string $sName
+ * @param string $sValue
+ * @param bool $bToTop = false
+ *
+ * @return \MailSo\Mime\HeaderCollection
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function AddByName($sName, $sValue, $bToTop = false)
+ {
+ return $this->Add(Header::NewInstance($sName, $sValue), $bToTop);
+ }
+
+ /**
+ * @param string $sName
+ * @param string $sValue
+ * @param bool $bToTop = false
+ *
+ * @return \MailSo\Mime\HeaderCollection
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function SetByName($sName, $sValue, $bToTop = false)
+ {
+ return $this->RemoveByName($sName)->Add(Header::NewInstance($sName, $sValue), $bToTop);
+ }
+
+ /**
+ * @return \MailSo\Mime\Header | null
+ */
+ public function &GetByIndex($iIndex)
+ {
+ $mResult = null;
+ $mResult =& parent::GetByIndex($iIndex);
+ return $mResult;
+ }
+
+ /**
+ * @param string $sHeaderName
+ * @param bool $bCharsetAutoDetect = false
+ * @return string
+ */
+ public function ValueByName($sHeaderName, $bCharsetAutoDetect = false)
+ {
+ $oHeader = null;
+ $oHeader =& $this->GetByName($sHeaderName);
+ return (null !== $oHeader) ? ($bCharsetAutoDetect ? $oHeader->ValueWithCharsetAutoDetect() : $oHeader->Value()) : '';
+ }
+
+ /**
+ * @param string $sHeaderName
+ * @param bool $bCharsetAutoDetect = false
+ * @return array
+ */
+ public function ValuesByName($sHeaderName, $bCharsetAutoDetect = false)
+ {
+ $aResult = array();
+ $oHeader = null;
+
+ $sHeaderNameLower = \strtolower($sHeaderName);
+ $aHeaders =& $this->GetAsArray();
+ foreach ($aHeaders as /* @var $oHeader \MailSo\Mime\Header */ &$oHeader)
+ {
+ if ($sHeaderNameLower === \strtolower($oHeader->Name()))
+ {
+ $aResult[] = $bCharsetAutoDetect ? $oHeader->ValueWithCharsetAutoDetect() : $oHeader->Value();
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @param string $sHeaderName
+ *
+ * @return \MailSo\Mime\HeaderCollection
+ */
+ public function RemoveByName($sHeaderName)
+ {
+ $aResult = $this->FilterList(function ($oHeader) use ($sHeaderName) {
+ return $oHeader && \strtolower($oHeader->Name()) !== \strtolower($sHeaderName);
+ });
+
+ return $this->SetAsArray($aResult);
+ }
+
+ /**
+ * @param string $sHeaderName
+ * @param bool $bCharsetAutoDetect = false
+ *
+ * @return \MailSo\Mime\EmailCollection|null
+ */
+ public function GetAsEmailCollection($sHeaderName, $bCharsetAutoDetect = false)
+ {
+ $oResult = null;
+ $sValue = $this->ValueByName($sHeaderName, $bCharsetAutoDetect);
+ if (0 < \strlen($sValue))
+ {
+ $oResult = \MailSo\Mime\EmailCollection::NewInstance($sValue);
+ }
+
+ return $oResult && 0 < $oResult->Count() ? $oResult : null;
+ }
+
+ /**
+ * @param string $sHeaderName
+ * @return \MailSo\Mime\ParameterCollection|null
+ */
+ public function ParametersByName($sHeaderName)
+ {
+ $oParameters = $oHeader = null;
+ $oHeader =& $this->GetByName($sHeaderName);
+ if ($oHeader)
+ {
+ $oParameters = $oHeader->Parameters();
+ }
+
+ return $oParameters;
+ }
+
+ /**
+ * @param string $sHeaderName
+ * @param string $sParamName
+ * @return string
+ */
+ public function ParameterValue($sHeaderName, $sParamName)
+ {
+ $oParameters = $this->ParametersByName($sHeaderName);
+ return (null !== $oParameters) ? $oParameters->ParameterValueByName($sParamName) : '';
+ }
+
+ /**
+ * @param string $sHeaderName
+ * @return \MailSo\Mime\Header | false
+ */
+ public function &GetByName($sHeaderName)
+ {
+ $oResult = $oHeader = null;
+
+ $sHeaderNameLower = \strtolower($sHeaderName);
+ $aHeaders =& $this->GetAsArray();
+ foreach ($aHeaders as /* @var $oHeader \MailSo\Mime\Header */ &$oHeader)
+ {
+ if ($sHeaderNameLower === \strtolower($oHeader->Name()))
+ {
+ $oResult =& $oHeader;
+ break;
+ }
+ }
+
+ return $oResult;
+ }
+
+ /**
+ * @param array $aList
+ * @return \MailSo\Mime\HeaderCollection
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function SetAsArray($aList)
+ {
+ parent::SetAsArray($aList);
+
+ return $this;
+ }
+
+ /**
+ * @param string $sParentCharset
+ * @return \MailSo\Mime\HeaderCollection
+ */
+ public function SetParentCharset($sParentCharset)
+ {
+ if (0 < \strlen($sParentCharset))
+ {
+ if ($this->sParentCharset !== $sParentCharset)
+ {
+ $oHeader = null;
+ $aHeaders =& $this->GetAsArray();
+
+ foreach ($aHeaders as /* @var $oHeader \MailSo\Mime\Header */ &$oHeader)
+ {
+ $oHeader->SetParentCharset($sParentCharset);
+ }
+
+ $this->sParentCharset = $sParentCharset;
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return void
+ */
+ public function Clear()
+ {
+ parent::Clear();
+
+ $this->sRawHeaders = '';
+ }
+
+ /**
+ * @param string $sRawHeaders
+ * @param bool $bStoreRawHeaders = false
+ * @param string $sParentCharset = ''
+ *
+ * @return \MailSo\Mime\HeaderCollection
+ */
+ public function Parse($sRawHeaders, $bStoreRawHeaders = false, $sParentCharset = '')
+ {
+ $this->Clear();
+
+ if ($bStoreRawHeaders)
+ {
+ $this->sRawHeaders = $sRawHeaders;
+ }
+
+ if (0 === \strlen($this->sParentCharset))
+ {
+ $this->sParentCharset = $sParentCharset;
+ }
+
+ $aHeaders = \explode("\n", \str_replace("\r", '', $sRawHeaders));
+
+ $sName = null;
+ $sValue = null;
+ foreach ($aHeaders as $sHeadersValue)
+ {
+ if (0 === strlen($sHeadersValue))
+ {
+ continue;
+ }
+
+ $sFirstChar = \substr($sHeadersValue, 0, 1);
+ if ($sFirstChar !== ' ' && $sFirstChar !== "\t" && false === \strpos($sHeadersValue, ':'))
+ {
+ continue;
+ }
+ else if (null !== $sName && ($sFirstChar === ' ' || $sFirstChar === "\t"))
+ {
+ $sValue = \is_null($sValue) ? '' : $sValue;
+
+ if ('?=' === \substr(\rtrim($sHeadersValue), -2))
+ {
+ $sHeadersValue = \rtrim($sHeadersValue);
+ }
+
+ if ('=?' === \substr(\ltrim($sHeadersValue), 0, 2))
+ {
+ $sHeadersValue = \ltrim($sHeadersValue);
+ }
+
+ if ('=?' === \substr($sHeadersValue, 0, 2))
+ {
+ $sValue .= $sHeadersValue;
+ }
+ else
+ {
+ $sValue .= "\n".$sHeadersValue;
+ }
+ }
+ else
+ {
+ if (null !== $sName)
+ {
+ $oHeader = Header::NewInstanceFromEncodedString($sName.': '.$sValue, $this->sParentCharset);
+ if ($oHeader)
+ {
+ $this->Add($oHeader);
+ }
+
+ $sName = null;
+ $sValue = null;
+ }
+
+ $aHeaderParts = \explode(':', $sHeadersValue, 2);
+ $sName = $aHeaderParts[0];
+ $sValue = isset($aHeaderParts[1]) ? $aHeaderParts[1] : '';
+
+ if ('?=' === \substr(\rtrim($sValue), -2))
+ {
+ $sValue = \rtrim($sValue);
+ }
+ }
+ }
+
+ if (null !== $sName)
+ {
+ $oHeader = Header::NewInstanceFromEncodedString($sName.': '.$sValue, $this->sParentCharset);
+ if ($oHeader)
+ {
+ $this->Add($oHeader);
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return int
+ */
+ public function DkimStatuses()
+ {
+ $aResult = array();
+
+ $aHeaders = $this->ValuesByName(\MailSo\Mime\Enumerations\Header::AUTHENTICATION_RESULTS);
+ if (\is_array($aHeaders) && 0 < \count($aHeaders))
+ {
+ foreach ($aHeaders as $sHeaderValue)
+ {
+ $sStatus = '';
+ $sHeader = '';
+ $sDkimLine = '';
+
+ $aMatch = array();
+
+ $sHeaderValue = \preg_replace('/[\r\n\t\s]+/', ' ', $sHeaderValue);
+
+ if (\preg_match('/dkim=.+/i', $sHeaderValue, $aMatch) && !empty($aMatch[0]))
+ {
+ $sDkimLine = $aMatch[0];
+
+ $aMatch = array();
+ if (\preg_match('/dkim=([a-zA-Z0-9]+)/i', $sDkimLine, $aMatch) && !empty($aMatch[1]))
+ {
+ $sStatus = $aMatch[1];
+ }
+
+ $aMatch = array();
+ if (\preg_match('/header\.(d|i|from)=([^\s;]+)/i', $sDkimLine, $aMatch) && !empty($aMatch[2]))
+ {
+ $sHeader = \trim($aMatch[2]);
+ }
+
+ if (!empty($sStatus) && !empty($sHeader))
+ {
+ $aResult[] = array($sStatus, $sHeader, $sDkimLine);
+ }
+ }
+ }
+ }
+ else
+ {
+ // X-DKIM-Authentication-Results: signer="hostinger.com" status="pass"
+ $aHeaders = $this->ValuesByName(\MailSo\Mime\Enumerations\Header::X_DKIM_AUTHENTICATION_RESULTS);
+ if (\is_array($aHeaders) && 0 < \count($aHeaders))
+ {
+ foreach ($aHeaders as $sHeaderValue)
+ {
+ $sStatus = '';
+ $sHeader = '';
+
+ $aMatch = array();
+
+ $sHeaderValue = \preg_replace('/[\r\n\t\s]+/', ' ', $sHeaderValue);
+
+ if (\preg_match('/status[\s]?=[\s]?"([a-zA-Z0-9]+)"/i', $sHeaderValue, $aMatch) && !empty($aMatch[1]))
+ {
+ $sStatus = $aMatch[1];
+ }
+
+ if (\preg_match('/signer[\s]?=[\s]?"([^";]+)"/i', $sHeaderValue, $aMatch) && !empty($aMatch[1]))
+ {
+ $sHeader = \trim($aMatch[1]);
+ }
+
+ if (!empty($sStatus) && !empty($sHeader))
+ {
+ $aResult[] = array($sStatus, $sHeader, $sHeaderValue);
+ }
+ }
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @return int
+ */
+ public function PopulateEmailColectionByDkim($oEmails)
+ {
+ if ($oEmails && $oEmails instanceof \MailSo\Mime\EmailCollection)
+ {
+ $aDkimStatuses = $this->DkimStatuses();
+ if (\is_array($aDkimStatuses) && 0 < \count($aDkimStatuses))
+ {
+ $oEmails->ForeachList(function (/* @var $oItem \MailSo\Mime\Email */ $oItem) use ($aDkimStatuses) {
+ if ($oItem && $oItem instanceof \MailSo\Mime\Email)
+ {
+ $sEmail = $oItem->GetEmail();
+ foreach ($aDkimStatuses as $aDkimData)
+ {
+ if (isset($aDkimData[0], $aDkimData[1]) &&
+ $aDkimData[1] === \strstr($sEmail, $aDkimData[1]))
+ {
+ $oItem->SetDkimStatusAndValue($aDkimData[0], empty($aDkimData[2]) ? '' : $aDkimData[2]);
+ }
+ }
+ }
+ });
+ }
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function ToEncodedString()
+ {
+ $aResult = array();
+ $aHeaders =& $this->GetAsArray();
+ foreach ($aHeaders as /* @var $oHeader \MailSo\Mime\Header */ &$oHeader)
+ {
+ $aResult[] = $oHeader->EncodedValue();
+ }
+
+ return \implode(\MailSo\Mime\Enumerations\Constants::CRLF, $aResult);
+ }
+}
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/Message.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Message.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/Message.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Message.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/Parameter.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Parameter.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/Parameter.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Parameter.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/ParameterCollection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/ParameterCollection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/ParameterCollection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/ParameterCollection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/Parser/ParserEmpty.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Parser/ParserEmpty.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/Parser/ParserEmpty.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Parser/ParserEmpty.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/Parser/ParserInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Parser/ParserInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/Parser/ParserInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Parser/ParserInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/Parser/ParserMemory.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Parser/ParserMemory.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/Parser/ParserMemory.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Parser/ParserMemory.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/Part.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Part.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/Part.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/Part.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/PartCollection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/PartCollection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Mime/PartCollection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Mime/PartCollection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Enumerations/ConnectionSecurityType.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Enumerations/ConnectionSecurityType.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Enumerations/ConnectionSecurityType.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Enumerations/ConnectionSecurityType.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Exceptions/ConnectionException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/ConnectionException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Exceptions/ConnectionException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/ConnectionException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Exceptions/Exception.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/Exception.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Exceptions/Exception.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/Exception.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Exceptions/InvalidArgumentException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/InvalidArgumentException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Exceptions/InvalidArgumentException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/InvalidArgumentException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Exceptions/SocketAlreadyConnectedException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketAlreadyConnectedException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Exceptions/SocketAlreadyConnectedException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketAlreadyConnectedException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Exceptions/SocketCanNotConnectToHostException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketCanNotConnectToHostException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Exceptions/SocketCanNotConnectToHostException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketCanNotConnectToHostException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Exceptions/SocketConnectionDoesNotAvailableException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketConnectionDoesNotAvailableException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Exceptions/SocketConnectionDoesNotAvailableException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketConnectionDoesNotAvailableException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Exceptions/SocketReadException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketReadException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Exceptions/SocketReadException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketReadException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Exceptions/SocketReadTimeoutException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketReadTimeoutException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Exceptions/SocketReadTimeoutException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketReadTimeoutException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Exceptions/SocketUnreadBufferException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketUnreadBufferException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Exceptions/SocketUnreadBufferException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketUnreadBufferException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Exceptions/SocketUnsuppoterdSecureConnectionException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketUnsuppoterdSecureConnectionException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Exceptions/SocketUnsuppoterdSecureConnectionException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketUnsuppoterdSecureConnectionException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Exceptions/SocketWriteException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketWriteException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/Exceptions/SocketWriteException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/Exceptions/SocketWriteException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/NetClient.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/NetClient.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Net/NetClient.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Net/NetClient.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Pop3/Exceptions/Exception.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Exceptions/Exception.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Pop3/Exceptions/Exception.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Exceptions/Exception.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Pop3/Exceptions/LoginBadCredentialsException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Exceptions/LoginBadCredentialsException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Pop3/Exceptions/LoginBadCredentialsException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Exceptions/LoginBadCredentialsException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Pop3/Exceptions/NegativeResponseException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Exceptions/NegativeResponseException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Pop3/Exceptions/NegativeResponseException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Exceptions/NegativeResponseException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Pop3/Exceptions/ResponseException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Exceptions/ResponseException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Pop3/Exceptions/ResponseException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Exceptions/ResponseException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Pop3/Exceptions/RuntimeException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Exceptions/RuntimeException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Pop3/Exceptions/RuntimeException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Exceptions/RuntimeException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Pop3/Pop3Client.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Pop3Client.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Pop3/Pop3Client.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Pop3/Pop3Client.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Poppassd/Exceptions/Exception.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/Exceptions/Exception.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Poppassd/Exceptions/Exception.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/Exceptions/Exception.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Poppassd/Exceptions/LoginBadCredentialsException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/Exceptions/LoginBadCredentialsException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Poppassd/Exceptions/LoginBadCredentialsException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/Exceptions/LoginBadCredentialsException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Poppassd/Exceptions/NegativeResponseException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/Exceptions/NegativeResponseException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Poppassd/Exceptions/NegativeResponseException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/Exceptions/NegativeResponseException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Poppassd/Exceptions/ResponseException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/Exceptions/ResponseException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Poppassd/Exceptions/ResponseException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/Exceptions/ResponseException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Poppassd/Exceptions/RuntimeException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/Exceptions/RuntimeException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Poppassd/Exceptions/RuntimeException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/Exceptions/RuntimeException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Poppassd/PoppassdClient.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/PoppassdClient.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Poppassd/PoppassdClient.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Poppassd/PoppassdClient.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Sieve/Exceptions/Exception.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/Exception.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Sieve/Exceptions/Exception.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/Exception.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Sieve/Exceptions/LoginBadCredentialsException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/LoginBadCredentialsException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Sieve/Exceptions/LoginBadCredentialsException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/LoginBadCredentialsException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Sieve/Exceptions/LoginBadMethodException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/LoginBadMethodException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Sieve/Exceptions/LoginBadMethodException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/LoginBadMethodException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Sieve/Exceptions/LoginException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/LoginException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Sieve/Exceptions/LoginException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/LoginException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Sieve/Exceptions/NegativeResponseException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/NegativeResponseException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Sieve/Exceptions/NegativeResponseException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/NegativeResponseException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Sieve/Exceptions/ResponseException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/ResponseException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Sieve/Exceptions/ResponseException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/ResponseException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Sieve/Exceptions/RuntimeException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/RuntimeException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Sieve/Exceptions/RuntimeException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/Exceptions/RuntimeException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Sieve/ManageSieveClient.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/ManageSieveClient.php
similarity index 95%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Sieve/ManageSieveClient.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/ManageSieveClient.php
index cd4e17982ab132da670ccf27ea49eef3edf712e6..77dd400f6cb6a7dc9b8a4bbda3b9ac39aa851ade 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Sieve/ManageSieveClient.php
+++ b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Sieve/ManageSieveClient.php
@@ -1,653 +1,653 @@
-bIsLoggined = false;
- $this->iRequestTime = 0;
- $this->aCapa = array();
- $this->aModules = array();
-
- $this->__USE_INITIAL_AUTH_PLAIN_COMMAND = true;
- }
-
- /**
- * @return \MailSo\Sieve\ManageSieveClient
- */
- public static function NewInstance()
- {
- return new self();
- }
-
- /**
- * @param string $sCapa
- *
- * @return bool
- */
- public function IsSupported($sCapa)
- {
- return isset($this->aCapa[\strtoupper($sCapa)]);
- }
-
- /**
- * @param string $sModule
- *
- * @return bool
- */
- public function IsModuleSupported($sModule)
- {
- return $this->IsSupported('SIEVE') && \in_array(\strtolower(\trim($sModule)), $this->aModules);
- }
-
- /**
- * @return array
- */
- public function Modules()
- {
- return $this->aModules;
- }
-
- /**
- * @param string $sAuth
- *
- * @return bool
- */
- public function IsAuthSupported($sAuth)
- {
- return $this->IsSupported('SASL') && \in_array(\strtoupper($sAuth), $this->aAuth);
- }
-
- /**
- * @param string $sServerName
- * @param int $iPort
- * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT
- * @param bool $bVerifySsl = false
- * @param bool $bAllowSelfSigned = true
- *
- * @return \MailSo\Sieve\ManageSieveClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Sieve\Exceptions\ResponseException
- */
- public function Connect($sServerName, $iPort,
- $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT,
- $bVerifySsl = false, $bAllowSelfSigned = true)
- {
- $this->iRequestTime = \microtime(true);
-
- parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned);
-
- $mResponse = $this->parseResponse();
- $this->validateResponse($mResponse);
- $this->parseStartupResponse($mResponse);
-
- if (\MailSo\Net\Enumerations\ConnectionSecurityType::UseStartTLS(
- $this->IsSupported('STARTTLS'), $this->iSecurityType))
- {
- $this->sendRequestWithCheck('STARTTLS');
- $this->EnableCrypto();
-
- $mResponse = $this->parseResponse();
- $this->validateResponse($mResponse);
- $this->parseStartupResponse($mResponse);
- }
- else if (\MailSo\Net\Enumerations\ConnectionSecurityType::STARTTLS === $this->iSecurityType)
- {
- $this->writeLogException(
- new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('STARTTLS is not supported'),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- return $this;
- }
-
- /**
- * @param string $sLogin
- * @param string $sPassword
- * @param string $sLoginAuthKey = ''
- *
- * @return \MailSo\Sieve\ManageSieveClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Sieve\Exceptions\LoginException
- */
- public function Login($sLogin, $sPassword, $sLoginAuthKey = '')
- {
- if (!\MailSo\Base\Validator::NotEmptyString($sLogin, true) ||
- !\MailSo\Base\Validator::NotEmptyString($sPassword, true))
- {
- $this->writeLogException(
- new \MailSo\Base\Exceptions\InvalidArgumentException(),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- if ($this->IsSupported('SASL'))
- {
- $bAuth = false;
- try
- {
- if ($this->IsAuthSupported('PLAIN'))
- {
- $sAuth = \base64_encode($sLoginAuthKey."\0".$sLogin."\0".$sPassword);
-
- if ($this->__USE_INITIAL_AUTH_PLAIN_COMMAND)
- {
- $this->sendRequest('AUTHENTICATE "PLAIN" "'.$sAuth.'"');
- }
- else
- {
- $this->sendRequest('AUTHENTICATE "PLAIN" {'.\strlen($sAuth).'+}');
- $this->sendRequest($sAuth);
- }
-
- $mResponse = $this->parseResponse();
- $this->validateResponse($mResponse);
- $this->parseStartupResponse($mResponse);
- $bAuth = true;
- }
- else if ($this->IsAuthSupported('LOGIN'))
- {
- $sLogin = \base64_encode($sLogin);
- $sPassword = \base64_encode($sPassword);
-
- $this->sendRequest('AUTHENTICATE "LOGIN"');
- $this->sendRequest('{'.\strlen($sLogin).'+}');
- $this->sendRequest($sLogin);
- $this->sendRequest('{'.\strlen($sPassword).'+}');
- $this->sendRequest($sPassword);
-
- $mResponse = $this->parseResponse();
- $this->validateResponse($mResponse);
- $this->parseStartupResponse($mResponse);
- $bAuth = true;
- }
- }
- catch (\MailSo\Sieve\Exceptions\NegativeResponseException $oException)
- {
- $this->writeLogException(
- new \MailSo\Sieve\Exceptions\LoginBadCredentialsException(
- $oException->GetResponses(), '', 0, $oException),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- if (!$bAuth)
- {
- $this->writeLogException(
- new \MailSo\Sieve\Exceptions\LoginBadMethodException(),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
- }
- else
- {
- $this->writeLogException(
- new \MailSo\Sieve\Exceptions\LoginException(),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- $this->bIsLoggined = true;
-
- return $this;
- }
-
- /**
- * @return \MailSo\Sieve\ManageSieveClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
- */
- public function Logout()
- {
- if ($this->bIsLoggined)
- {
- $this->sendRequestWithCheck('LOGOUT');
- $this->bIsLoggined = false;
- }
-
- return $this;
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
- */
- public function ListScripts()
- {
- $this->sendRequest('LISTSCRIPTS');
- $mResponse = $this->parseResponse();
- $this->validateResponse($mResponse);
-
- $aResult = array();
- if (\is_array($mResponse))
- {
- foreach ($mResponse as $sLine)
- {
- $aTokens = $this->parseLine($sLine);
- if (false === $aTokens)
- {
- continue;
- }
-
- $aResult[$aTokens[0]] = 'ACTIVE' === substr($sLine, -6);
- }
- }
-
- return $aResult;
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
- */
- public function Capability()
- {
- $this->sendRequest('CAPABILITY');
- $mResponse = $this->parseResponse();
- $this->validateResponse($mResponse);
- $this->parseStartupResponse($mResponse);
-
- return $this->aCapa;
- }
-
- /**
- * @return \MailSo\Sieve\ManageSieveClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
- */
- public function Noop()
- {
- $this->sendRequestWithCheck('NOOP');
-
- return $this;
- }
-
- /**
- * @param string $sScriptName
- *
- * @return string
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
- */
- public function GetScript($sScriptName)
- {
- $this->sendRequest('GETSCRIPT "'.$sScriptName.'"');
- $mResponse = $this->parseResponse();
- $this->validateResponse($mResponse);
-
- $sScript = '';
- if (\is_array($mResponse) && 0 < \count($mResponse))
- {
- if ('{' === $mResponse[0]{0})
- {
- \array_shift($mResponse);
- }
-
- if (\in_array(\substr($mResponse[\count($mResponse) - 1], 0, 2), array('OK', 'NO')))
- {
- \array_pop($mResponse);
- }
-
- $sScript = \implode("\n", $mResponse);
- }
-
- return $sScript;
- }
-
- /**
- * @param string $sScriptName
- * @param string $sScriptSource
- *
- * @return \MailSo\Sieve\ManageSieveClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
- */
- public function PutScript($sScriptName, $sScriptSource)
- {
- $this->sendRequest('PUTSCRIPT "'.$sScriptName.'" {'.\strlen($sScriptSource).'+}');
- $this->sendRequestWithCheck($sScriptSource);
-
- return $this;
- }
-
- /**
- * @param string $sScriptSource
- *
- * @return \MailSo\Sieve\ManageSieveClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
- */
- public function CheckScript($sScriptSource)
- {
- $this->sendRequest('CHECKSCRIPT {'.\strlen($sScriptSource).'+}');
- $this->sendRequestWithCheck($sScriptSource);
-
- return $this;
- }
-
- /**
- * @param string $sScriptName
- *
- * @return \MailSo\Sieve\ManageSieveClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
- */
- public function SetActiveScript($sScriptName)
- {
- $this->sendRequestWithCheck('SETACTIVE "'.$sScriptName.'"');
-
- return $this;
- }
-
- /**
- * @param string $sScriptName
- *
- * @return \MailSo\Sieve\ManageSieveClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
- */
- public function DeleteScript($sScriptName)
- {
- $this->sendRequestWithCheck('DELETESCRIPT "'.$sScriptName.'"');
-
- return $this;
- }
-
- /**
- * @return string
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
- */
- public function GetActiveScriptName()
- {
- $aList = $this->ListScripts();
- if (\is_array($aList) && 0 < \count($aList))
- {
- foreach ($aList as $sName => $bIsActive)
- {
- if ($bIsActive)
- {
- return $sName;
- }
- }
- }
-
- return '';
- }
-
- /**
- * @param string $sScriptName
- *
- * @return bool
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
- */
- public function IsActiveScript($sScriptName)
- {
- return $sScriptName === $this->GetActiveScriptName();
- }
-
- /**
- * @param string $sLine
- * @return array|false
- */
- private function parseLine($sLine)
- {
- if (false === $sLine || null === $sLine || \in_array(\substr($sLine, 0, 2), array('OK', 'NO')))
- {
- return false;
- }
-
- $iStart = -1;
- $iIndex = 0;
- $aResult = false;
-
- for ($iPos = 0; $iPos < \strlen($sLine); $iPos++)
- {
- if ('"' === $sLine[$iPos] && '\\' !== $sLine[$iPos])
- {
- if (-1 === $iStart)
- {
- $iStart = $iPos;
- }
- else
- {
- $aResult = \is_array($aResult) ? $aResult : array();
- $aResult[$iIndex++] = \substr($sLine, $iStart + 1, $iPos - $iStart - 1);
- $iStart = -1;
- }
- }
- }
-
- return \is_array($aResult) && isset($aResult[0]) ? $aResult : false;
- }
-
- /**
- * @param string $mResponse
- *
- * @return void
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- */
- private function parseStartupResponse($mResponse)
- {
- foreach ($mResponse as $sLine)
- {
- $aTokens = $this->parseLine($sLine);
-
- if (false === $aTokens || !isset($aTokens[0]) ||
- \in_array(\substr($sLine, 0, 2), array('OK', 'NO')))
- {
- continue;
- }
-
- $sToken = \strtoupper($aTokens[0]);
- $this->aCapa[$sToken] = isset($aTokens[1]) ? $aTokens[1] : '';
-
- if (isset($aTokens[1]))
- {
- switch ($sToken) {
- case 'SASL':
- $this->aAuth = \explode(' ', \strtoupper($aTokens[1]));
- break;
- case 'SIEVE':
- $this->aModules = \explode(' ', \strtolower($aTokens[1]));
- break;
- }
- }
- }
- }
-
- /**
- * @param string $sRequest
- *
- * @return void
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- */
- private function sendRequest($sRequest)
- {
- if (!\MailSo\Base\Validator::NotEmptyString($sRequest, true))
- {
- $this->writeLogException(
- new \MailSo\Base\Exceptions\InvalidArgumentException(),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- $this->IsConnected(true);
-
- $this->sendRaw($sRequest);
- }
-
- /**
- * @param string $sRequest
- *
- * @return void
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
- */
- private function sendRequestWithCheck($sRequest)
- {
- $this->sendRequest($sRequest);
- $this->validateResponse($this->parseResponse());
- }
-
- /**
- * @param string $sLine
- *
- * @return string
- */
- private function convertEndOfLine($sLine)
- {
- $sLine = \trim($sLine);
- if ('}' === \substr($sLine, -1))
- {
- $iPos = \strrpos($sLine, '{');
- if (false !== $iPos)
- {
- $sSunLine = \substr($sLine, $iPos + 1, -1);
- if (\is_numeric($sSunLine) && 0 < (int) $sSunLine)
- {
- $iLen = (int) $sSunLine;
-
- $this->getNextBuffer($iLen, true);
-
- if (\strlen($this->sResponseBuffer) === $iLen)
- {
- $sLine = \trim(\substr_replace($sLine, $this->sResponseBuffer, $iPos));
- }
- }
- }
- }
-
- return $sLine;
- }
-
- /**
- * @return array|bool
- */
- private function parseResponse()
- {
- $this->iRequestTime = \microtime(true);
-
- $aResult = array();
- do
- {
- $this->getNextBuffer();
-
- $sLine = $this->sResponseBuffer;
- if (false === $sLine)
- {
- break;
- }
- else if (\in_array(\substr($sLine, 0, 2), array('OK', 'NO')))
- {
- $aResult[] = $this->convertEndOfLine($sLine);
- break;
- }
- else
- {
- $aResult[] = $this->convertEndOfLine($sLine);
- }
- }
- while (true);
-
- $this->writeLog((\microtime(true) - $this->iRequestTime),
- \MailSo\Log\Enumerations\Type::TIME);
-
- return $aResult;
- }
-
- /**
- * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
- */
- private function validateResponse($aResponse)
- {
- if (!\is_array($aResponse) || 0 === \count($aResponse) ||
- 'OK' !== \substr($aResponse[\count($aResponse) - 1], 0, 2))
- {
- $this->writeLogException(
- new \MailSo\Sieve\Exceptions\NegativeResponseException($aResponse),
- \MailSo\Log\Enumerations\Type::WARNING, true);
- }
- }
-
- /**
- * @return string
- */
- protected function getLogName()
- {
- return 'SIEVE';
- }
-
- /**
- * @param \MailSo\Log\Logger $oLogger
- *
- * @return \MailSo\Sieve\ManageSieveClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- */
- public function SetLogger($oLogger)
- {
- parent::SetLogger($oLogger);
-
- return $this;
- }
-}
+bIsLoggined = false;
+ $this->iRequestTime = 0;
+ $this->aCapa = array();
+ $this->aModules = array();
+
+ $this->__USE_INITIAL_AUTH_PLAIN_COMMAND = true;
+ }
+
+ /**
+ * @return \MailSo\Sieve\ManageSieveClient
+ */
+ public static function NewInstance()
+ {
+ return new self();
+ }
+
+ /**
+ * @param string $sCapa
+ *
+ * @return bool
+ */
+ public function IsSupported($sCapa)
+ {
+ return isset($this->aCapa[\strtoupper($sCapa)]);
+ }
+
+ /**
+ * @param string $sModule
+ *
+ * @return bool
+ */
+ public function IsModuleSupported($sModule)
+ {
+ return $this->IsSupported('SIEVE') && \in_array(\strtolower(\trim($sModule)), $this->aModules);
+ }
+
+ /**
+ * @return array
+ */
+ public function Modules()
+ {
+ return $this->aModules;
+ }
+
+ /**
+ * @param string $sAuth
+ *
+ * @return bool
+ */
+ public function IsAuthSupported($sAuth)
+ {
+ return $this->IsSupported('SASL') && \in_array(\strtoupper($sAuth), $this->aAuth);
+ }
+
+ /**
+ * @param string $sServerName
+ * @param int $iPort
+ * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT
+ * @param bool $bVerifySsl = false
+ * @param bool $bAllowSelfSigned = true
+ *
+ * @return \MailSo\Sieve\ManageSieveClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Sieve\Exceptions\ResponseException
+ */
+ public function Connect($sServerName, $iPort,
+ $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT,
+ $bVerifySsl = false, $bAllowSelfSigned = true)
+ {
+ $this->iRequestTime = \microtime(true);
+
+ parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned);
+
+ $mResponse = $this->parseResponse();
+ $this->validateResponse($mResponse);
+ $this->parseStartupResponse($mResponse);
+
+ if (\MailSo\Net\Enumerations\ConnectionSecurityType::UseStartTLS(
+ $this->IsSupported('STARTTLS'), $this->iSecurityType))
+ {
+ $this->sendRequestWithCheck('STARTTLS');
+ $this->EnableCrypto();
+
+ $mResponse = $this->parseResponse();
+ $this->validateResponse($mResponse);
+ $this->parseStartupResponse($mResponse);
+ }
+ else if (\MailSo\Net\Enumerations\ConnectionSecurityType::STARTTLS === $this->iSecurityType)
+ {
+ $this->writeLogException(
+ new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('STARTTLS is not supported'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sLogin
+ * @param string $sPassword
+ * @param string $sLoginAuthKey = ''
+ *
+ * @return \MailSo\Sieve\ManageSieveClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Sieve\Exceptions\LoginException
+ */
+ public function Login($sLogin, $sPassword, $sLoginAuthKey = '')
+ {
+ if (!\MailSo\Base\Validator::NotEmptyString($sLogin, true) ||
+ !\MailSo\Base\Validator::NotEmptyString($sPassword, true))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ if ($this->IsSupported('SASL'))
+ {
+ $bAuth = false;
+ try
+ {
+ if ($this->IsAuthSupported('PLAIN'))
+ {
+ $sAuth = \base64_encode($sLoginAuthKey."\0".$sLogin."\0".$sPassword);
+
+ if ($this->__USE_INITIAL_AUTH_PLAIN_COMMAND)
+ {
+ $this->sendRequest('AUTHENTICATE "PLAIN" "'.$sAuth.'"');
+ }
+ else
+ {
+ $this->sendRequest('AUTHENTICATE "PLAIN" {'.\strlen($sAuth).'+}');
+ $this->sendRequest($sAuth);
+ }
+
+ $mResponse = $this->parseResponse();
+ $this->validateResponse($mResponse);
+ $this->parseStartupResponse($mResponse);
+ $bAuth = true;
+ }
+ else if ($this->IsAuthSupported('LOGIN'))
+ {
+ $sLogin = \base64_encode($sLogin);
+ $sPassword = \base64_encode($sPassword);
+
+ $this->sendRequest('AUTHENTICATE "LOGIN"');
+ $this->sendRequest('{'.\strlen($sLogin).'+}');
+ $this->sendRequest($sLogin);
+ $this->sendRequest('{'.\strlen($sPassword).'+}');
+ $this->sendRequest($sPassword);
+
+ $mResponse = $this->parseResponse();
+ $this->validateResponse($mResponse);
+ $this->parseStartupResponse($mResponse);
+ $bAuth = true;
+ }
+ }
+ catch (\MailSo\Sieve\Exceptions\NegativeResponseException $oException)
+ {
+ $this->writeLogException(
+ new \MailSo\Sieve\Exceptions\LoginBadCredentialsException(
+ $oException->GetResponses(), '', 0, $oException),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ if (!$bAuth)
+ {
+ $this->writeLogException(
+ new \MailSo\Sieve\Exceptions\LoginBadMethodException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+ }
+ else
+ {
+ $this->writeLogException(
+ new \MailSo\Sieve\Exceptions\LoginException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $this->bIsLoggined = true;
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Sieve\ManageSieveClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ public function Logout()
+ {
+ if ($this->bIsLoggined)
+ {
+ $this->sendRequestWithCheck('LOGOUT');
+ $this->bIsLoggined = false;
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ public function ListScripts()
+ {
+ $this->sendRequest('LISTSCRIPTS');
+ $mResponse = $this->parseResponse();
+ $this->validateResponse($mResponse);
+
+ $aResult = array();
+ if (\is_array($mResponse))
+ {
+ foreach ($mResponse as $sLine)
+ {
+ $aTokens = $this->parseLine($sLine);
+ if (false === $aTokens)
+ {
+ continue;
+ }
+
+ $aResult[$aTokens[0]] = 'ACTIVE' === substr($sLine, -6);
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ public function Capability()
+ {
+ $this->sendRequest('CAPABILITY');
+ $mResponse = $this->parseResponse();
+ $this->validateResponse($mResponse);
+ $this->parseStartupResponse($mResponse);
+
+ return $this->aCapa;
+ }
+
+ /**
+ * @return \MailSo\Sieve\ManageSieveClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ public function Noop()
+ {
+ $this->sendRequestWithCheck('NOOP');
+
+ return $this;
+ }
+
+ /**
+ * @param string $sScriptName
+ *
+ * @return string
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ public function GetScript($sScriptName)
+ {
+ $this->sendRequest('GETSCRIPT "'.$sScriptName.'"');
+ $mResponse = $this->parseResponse();
+ $this->validateResponse($mResponse);
+
+ $sScript = '';
+ if (\is_array($mResponse) && 0 < \count($mResponse))
+ {
+ if ('{' === $mResponse[0]{0})
+ {
+ \array_shift($mResponse);
+ }
+
+ if (\in_array(\substr($mResponse[\count($mResponse) - 1], 0, 2), array('OK', 'NO')))
+ {
+ \array_pop($mResponse);
+ }
+
+ $sScript = \implode("\n", $mResponse);
+ }
+
+ return $sScript;
+ }
+
+ /**
+ * @param string $sScriptName
+ * @param string $sScriptSource
+ *
+ * @return \MailSo\Sieve\ManageSieveClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ public function PutScript($sScriptName, $sScriptSource)
+ {
+ $this->sendRequest('PUTSCRIPT "'.$sScriptName.'" {'.\strlen($sScriptSource).'+}');
+ $this->sendRequestWithCheck($sScriptSource);
+
+ return $this;
+ }
+
+ /**
+ * @param string $sScriptSource
+ *
+ * @return \MailSo\Sieve\ManageSieveClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ public function CheckScript($sScriptSource)
+ {
+ $this->sendRequest('CHECKSCRIPT {'.\strlen($sScriptSource).'+}');
+ $this->sendRequestWithCheck($sScriptSource);
+
+ return $this;
+ }
+
+ /**
+ * @param string $sScriptName
+ *
+ * @return \MailSo\Sieve\ManageSieveClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ public function SetActiveScript($sScriptName)
+ {
+ $this->sendRequestWithCheck('SETACTIVE "'.$sScriptName.'"');
+
+ return $this;
+ }
+
+ /**
+ * @param string $sScriptName
+ *
+ * @return \MailSo\Sieve\ManageSieveClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ public function DeleteScript($sScriptName)
+ {
+ $this->sendRequestWithCheck('DELETESCRIPT "'.$sScriptName.'"');
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ public function GetActiveScriptName()
+ {
+ $aList = $this->ListScripts();
+ if (\is_array($aList) && 0 < \count($aList))
+ {
+ foreach ($aList as $sName => $bIsActive)
+ {
+ if ($bIsActive)
+ {
+ return $sName;
+ }
+ }
+ }
+
+ return '';
+ }
+
+ /**
+ * @param string $sScriptName
+ *
+ * @return bool
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ public function IsActiveScript($sScriptName)
+ {
+ return $sScriptName === $this->GetActiveScriptName();
+ }
+
+ /**
+ * @param string $sLine
+ * @return array|false
+ */
+ private function parseLine($sLine)
+ {
+ if (false === $sLine || null === $sLine || \in_array(\substr($sLine, 0, 2), array('OK', 'NO')))
+ {
+ return false;
+ }
+
+ $iStart = -1;
+ $iIndex = 0;
+ $aResult = false;
+
+ for ($iPos = 0; $iPos < \strlen($sLine); $iPos++)
+ {
+ if ('"' === $sLine[$iPos] && '\\' !== $sLine[$iPos])
+ {
+ if (-1 === $iStart)
+ {
+ $iStart = $iPos;
+ }
+ else
+ {
+ $aResult = \is_array($aResult) ? $aResult : array();
+ $aResult[$iIndex++] = \substr($sLine, $iStart + 1, $iPos - $iStart - 1);
+ $iStart = -1;
+ }
+ }
+ }
+
+ return \is_array($aResult) && isset($aResult[0]) ? $aResult : false;
+ }
+
+ /**
+ * @param string $mResponse
+ *
+ * @return void
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ private function parseStartupResponse($mResponse)
+ {
+ foreach ($mResponse as $sLine)
+ {
+ $aTokens = $this->parseLine($sLine);
+
+ if (false === $aTokens || !isset($aTokens[0]) ||
+ \in_array(\substr($sLine, 0, 2), array('OK', 'NO')))
+ {
+ continue;
+ }
+
+ $sToken = \strtoupper($aTokens[0]);
+ $this->aCapa[$sToken] = isset($aTokens[1]) ? $aTokens[1] : '';
+
+ if (isset($aTokens[1]))
+ {
+ switch ($sToken) {
+ case 'SASL':
+ $this->aAuth = \explode(' ', \strtoupper($aTokens[1]));
+ break;
+ case 'SIEVE':
+ $this->aModules = \explode(' ', \strtolower($aTokens[1]));
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * @param string $sRequest
+ *
+ * @return void
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ private function sendRequest($sRequest)
+ {
+ if (!\MailSo\Base\Validator::NotEmptyString($sRequest, true))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $this->IsConnected(true);
+
+ $this->sendRaw($sRequest);
+ }
+
+ /**
+ * @param string $sRequest
+ *
+ * @return void
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ private function sendRequestWithCheck($sRequest)
+ {
+ $this->sendRequest($sRequest);
+ $this->validateResponse($this->parseResponse());
+ }
+
+ /**
+ * @param string $sLine
+ *
+ * @return string
+ */
+ private function convertEndOfLine($sLine)
+ {
+ $sLine = \trim($sLine);
+ if ('}' === \substr($sLine, -1))
+ {
+ $iPos = \strrpos($sLine, '{');
+ if (false !== $iPos)
+ {
+ $sSunLine = \substr($sLine, $iPos + 1, -1);
+ if (\is_numeric($sSunLine) && 0 < (int) $sSunLine)
+ {
+ $iLen = (int) $sSunLine;
+
+ $this->getNextBuffer($iLen, true);
+
+ if (\strlen($this->sResponseBuffer) === $iLen)
+ {
+ $sLine = \trim(\substr_replace($sLine, $this->sResponseBuffer, $iPos));
+ }
+ }
+ }
+ }
+
+ return $sLine;
+ }
+
+ /**
+ * @return array|bool
+ */
+ private function parseResponse()
+ {
+ $this->iRequestTime = \microtime(true);
+
+ $aResult = array();
+ do
+ {
+ $this->getNextBuffer();
+
+ $sLine = $this->sResponseBuffer;
+ if (false === $sLine)
+ {
+ break;
+ }
+ else if (\in_array(\substr($sLine, 0, 2), array('OK', 'NO')))
+ {
+ $aResult[] = $this->convertEndOfLine($sLine);
+ break;
+ }
+ else
+ {
+ $aResult[] = $this->convertEndOfLine($sLine);
+ }
+ }
+ while (true);
+
+ $this->writeLog((\microtime(true) - $this->iRequestTime),
+ \MailSo\Log\Enumerations\Type::TIME);
+
+ return $aResult;
+ }
+
+ /**
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ private function validateResponse($aResponse)
+ {
+ if (!\is_array($aResponse) || 0 === \count($aResponse) ||
+ 'OK' !== \substr($aResponse[\count($aResponse) - 1], 0, 2))
+ {
+ $this->writeLogException(
+ new \MailSo\Sieve\Exceptions\NegativeResponseException($aResponse),
+ \MailSo\Log\Enumerations\Type::WARNING, true);
+ }
+ }
+
+ /**
+ * @return string
+ */
+ protected function getLogName()
+ {
+ return 'SIEVE';
+ }
+
+ /**
+ * @param \MailSo\Log\Logger $oLogger
+ *
+ * @return \MailSo\Sieve\ManageSieveClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function SetLogger($oLogger)
+ {
+ parent::SetLogger($oLogger);
+
+ return $this;
+ }
+}
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Smtp/Exceptions/Exception.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/Exception.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Smtp/Exceptions/Exception.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/Exception.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Smtp/Exceptions/LoginBadCredentialsException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/LoginBadCredentialsException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Smtp/Exceptions/LoginBadCredentialsException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/LoginBadCredentialsException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Smtp/Exceptions/LoginBadMethodException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/LoginBadMethodException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Smtp/Exceptions/LoginBadMethodException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/LoginBadMethodException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Smtp/Exceptions/LoginException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/LoginException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Smtp/Exceptions/LoginException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/LoginException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Smtp/Exceptions/NegativeResponseException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/NegativeResponseException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Smtp/Exceptions/NegativeResponseException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/NegativeResponseException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Smtp/Exceptions/ResponseException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/ResponseException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Smtp/Exceptions/ResponseException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/ResponseException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Smtp/Exceptions/RuntimeException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/RuntimeException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Smtp/Exceptions/RuntimeException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/Exceptions/RuntimeException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Smtp/SmtpClient.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/SmtpClient.php
similarity index 95%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Smtp/SmtpClient.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/SmtpClient.php
index f536b72ae549e4b8f760f9bc30926f5cc2c56434..ce09f029aabde5d4a173ea0916d6dc33be44fbec 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Smtp/SmtpClient.php
+++ b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Smtp/SmtpClient.php
@@ -1,838 +1,838 @@
-aAuthTypes = array();
-
- $this->iRequestTime = 0;
- $this->iSizeCapaValue = 0;
- $this->aResults = array();
- $this->aCapa = array();
-
- $this->bHelo = false;
- $this->bRcpt = false;
- $this->bMail = false;
- $this->bData = false;
- }
-
- /**
- * @return \MailSo\Smtp\SmtpClient
- */
- public static function NewInstance()
- {
- return new self();
- }
-
- /**
- * @return bool
- */
- public function IsSupported($sCapa)
- {
- return in_array(strtoupper($sCapa), $this->aCapa);
- }
-
- /**
- * @return bool
- */
- public function IsAuthSupported($sAuth)
- {
- return in_array(strtoupper($sAuth), $this->aAuthTypes);
- }
-
- /**
- * @return bool
- */
- public function HasSupportedAuth()
- {
- return $this->IsAuthSupported('PLAIN') || $this->IsAuthSupported('LOGIN');
- }
-
- /**
- * @return string
- */
- public static function EhloHelper()
- {
- $sEhloHost = empty($_SERVER['SERVER_NAME']) ? '' : \trim($_SERVER['SERVER_NAME']);
- if (empty($sEhloHost))
- {
- $sEhloHost = empty($_SERVER['HTTP_HOST']) ? '' : \trim($_SERVER['HTTP_HOST']);
- }
-
- if (empty($sEhloHost))
- {
- $sEhloHost = \function_exists('gethostname') ? \gethostname() : 'localhost';
- }
-
- $sEhloHost = \trim(\preg_replace('/:\d+$/', '', \trim($sEhloHost)));
-
- if (\preg_match('/^\d+\.\d+\.\d+\.\d+$/', $sEhloHost))
- {
- $sEhloHost = '['.$sEhloHost.']';
- }
-
- return empty($sEhloHost) ? 'localhost' : $sEhloHost;
- }
-
- /**
- * @param string $sServerName
- * @param int $iPort = 25
- * @param string $sEhloHost = '[127.0.0.1]'
- * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT
- * @param bool $bVerifySsl = false
- * @param bool $bAllowSelfSigned = true
- *
- * @return \MailSo\Smtp\SmtpClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Smtp\Exceptions\ResponseException
- */
- public function Connect($sServerName, $iPort = 25, $sEhloHost = '[127.0.0.1]',
- $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT,
- $bVerifySsl = false, $bAllowSelfSigned = true)
- {
- $this->iRequestTime = microtime(true);
-
- parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned);
-
- $this->validateResponse(220);
-
- $this->preLoginStartTLSAndEhloProcess($sEhloHost);
-
- return $this;
- }
-
- /**
- * @param string $sLogin
- * @param string $sPassword
- * @param boolean $bUseAuthPlainIfSupported = true
- * @param boolean $bUseAuthCramMd5IfSupported = true
- *
- * @return \MailSo\Smtp\SmtpClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Smtp\Exceptions\Exception
- */
- public function Login($sLogin, $sPassword, $bUseAuthPlainIfSupported = true, $bUseAuthCramMd5IfSupported = true)
- {
- $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.' '.\MailSo\Base\Utils::Hmac($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);
- }
- }
- 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
- {
- $this->writeLogException(
- new \MailSo\Smtp\Exceptions\LoginBadMethodException(),
- \MailSo\Log\Enumerations\Type::NOTICE, true);
- }
-
- return $this;
- }
-
- /**
- * @param string $sXOAuth2Token
- *
- * @return \MailSo\Smtp\SmtpClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Smtp\Exceptions\Exception
- */
- public function LoginWithXOauth2($sXOAuth2Token)
- {
- if ($this->IsAuthSupported('XOAUTH2'))
- {
- try
- {
- $this->sendRequestWithCheck('AUTH', 235, 'XOAUTH2 '.\trim($sXOAuth2Token));
- }
- 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
- {
- $this->writeLogException(
- new \MailSo\Smtp\Exceptions\LoginBadMethodException(),
- \MailSo\Log\Enumerations\Type::NOTICE, true);
- }
-
- return $this;
- }
-
- /**
- * @param string $sFrom
- * @param string $sSizeIfSupported = ''
- * @param bool $bDsn = false
- *
- * @return \MailSo\Smtp\SmtpClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Smtp\Exceptions\Exception
- */
- public function MailFrom($sFrom, $sSizeIfSupported = '', $bDsn = false)
- {
- $sFrom = \MailSo\Base\Utils::IdnToAscii(
- \MailSo\Base\Utils::Trim($sFrom), true);
-
- $sCmd = 'FROM:<'.$sFrom.'>';
-
- $sSizeIfSupported = (string) $sSizeIfSupported;
- if (0 < \strlen($sSizeIfSupported) && \is_numeric($sSizeIfSupported) && $this->IsSupported('SIZE'))
- {
- $sCmd .= ' SIZE='.$sSizeIfSupported;
- }
-
- if ($bDsn && $this->IsSupported('DSN'))
- {
- $sCmd .= ' RET=HDRS';
- }
-
- $this->sendRequestWithCheck('MAIL', 250, $sCmd);
-
- $this->bMail = true;
- $this->bRcpt = false;
- $this->bData = false;
-
- return $this;
- }
-
- /**
- * @param string $sTo
- * @param bool $bDsn = false
- *
- * @return \MailSo\Smtp\SmtpClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Smtp\Exceptions\Exception
- */
- public function Rcpt($sTo, $bDsn = false)
- {
- if (!$this->bMail)
- {
- $this->writeLogException(
- new Exceptions\RuntimeException('No sender reverse path has been supplied'),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- $sTo = \MailSo\Base\Utils::IdnToAscii(
- \MailSo\Base\Utils::Trim($sTo), true);
-
- $sCmd = 'TO:<'.$sTo.'>';
-
- if ($bDsn && $this->IsSupported('DSN'))
- {
- $sCmd .= ' NOTIFY=SUCCESS,FAILURE';
- }
-
- $this->sendRequestWithCheck(
- 'RCPT', array(250, 251), $sCmd, false,
- 'Failed to add recipient "'.$sTo.'"'
- );
-
- $this->bRcpt = true;
-
- return $this;
- }
-
- /**
- * @param string $sTo
- *
- * @return \MailSo\Smtp\SmtpClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Smtp\Exceptions\Exception
- */
- public function MailTo($sTo)
- {
- return $this->Rcpt($sTo);
- }
-
- /**
- * @param string $sData
- *
- * @return \MailSo\Smtp\SmtpClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Smtp\Exceptions\Exception
- */
- public function Data($sData)
- {
- if (!\MailSo\Base\Validator::NotEmptyString($sData, true))
- {
- throw new \MailSo\Base\Exceptions\InvalidArgumentException();
- }
-
- $rDataStream = \MailSo\Base\ResourceRegistry::CreateMemoryResourceFromString($sData);
- unset($sData);
- $this->DataWithStream($rDataStream);
- \MailSo\Base\ResourceRegistry::CloseMemoryResource($rDataStream);
-
- return $this;
- }
-
- /**
- * @param resource $rDataStream
- *
- * @return \MailSo\Smtp\SmtpClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Smtp\Exceptions\Exception
- */
- public function DataWithStream($rDataStream)
- {
- if (!\is_resource($rDataStream))
- {
- throw new \MailSo\Base\Exceptions\InvalidArgumentException();
- }
-
- if (!$this->bRcpt)
- {
- $this->writeLogException(
- new Exceptions\RuntimeException('No recipient forward path has been supplied'),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- $this->sendRequestWithCheck('DATA', 354);
-
- $this->writeLog('Message data.', \MailSo\Log\Enumerations\Type::NOTE);
-
- $this->bRunningCallback = true;
-
- while (!\feof($rDataStream))
- {
- $sBuffer = \fgets($rDataStream);
- if (false !== $sBuffer)
- {
- if (0 === \strpos($sBuffer, '.'))
- {
- $sBuffer = '.'.$sBuffer;
- }
-
- $this->sendRaw(\rtrim($sBuffer, "\r\n"), false);
-
- \MailSo\Base\Utils::ResetTimeLimit();
- continue;
- }
- else if (!\feof($rDataStream))
- {
- $this->writeLogException(
- new Exceptions\RuntimeException('Cannot read input resource'),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- break;
- }
-
- $this->sendRequestWithCheck('.', 250);
-
- $this->bRunningCallback = false;
-
- $this->bData = true;
-
- return $this;
- }
-
- /**
- * @return \MailSo\Smtp\SmtpClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Smtp\Exceptions\Exception
- */
- public function Rset()
- {
- $this->sendRequestWithCheck('RSET', array(250, 220));
-
- $this->bMail = false;
- $this->bRcpt = false;
- $this->bData = false;
-
- return $this;
- }
-
- /**
- * @return \MailSo\Smtp\SmtpClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Smtp\Exceptions\Exception
- */
- public function Vrfy($sUser)
- {
- $sUser = \MailSo\Base\Utils::IdnToAscii(
- \MailSo\Base\Utils::Trim($sUser));
-
- $this->sendRequestWithCheck('VRFY', array(250, 251, 252), $sUser);
-
- return $this;
- }
-
- /**
- * @return \MailSo\Smtp\SmtpClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Smtp\Exceptions\Exception
- */
- public function Noop()
- {
- $this->sendRequestWithCheck('NOOP', 250);
-
- return $this;
- }
-
- /**
- * @return \MailSo\Smtp\SmtpClient
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Smtp\Exceptions\Exception
- */
- public function Logout()
- {
- if ($this->IsConnected())
- {
- $this->sendRequestWithCheck('QUIT', 221);
- }
-
- $this->bHelo = false;
- $this->bMail = false;
- $this->bRcpt = false;
- $this->bData = false;
-
- return $this;
- }
-
- /**
- * @param string $sEhloHost
- *
- * @return void
- */
- private function preLoginStartTLSAndEhloProcess($sEhloHost)
- {
- if ($this->bHelo)
- {
- $this->writeLogException(
- new Exceptions\RuntimeException('Cannot issue EHLO/HELO to existing session'),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- $this->ehloOrHelo($sEhloHost);
-
- if (\MailSo\Net\Enumerations\ConnectionSecurityType::UseStartTLS(
- $this->IsSupported('STARTTLS'), $this->iSecurityType, $this->HasSupportedAuth()))
- {
- $this->sendRequestWithCheck('STARTTLS', 220);
- $this->EnableCrypto();
-
- $this->ehloOrHelo($sEhloHost);
- }
- else if (\MailSo\Net\Enumerations\ConnectionSecurityType::STARTTLS === $this->iSecurityType)
- {
- $this->writeLogException(
- new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('STARTTLS is not supported'),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- $this->bHelo = true;
- }
-
- /**
- * @param string $sCommand
- * @param string $sAddToCommand = ''
- * @param bool $bSecureLog = false
- *
- * @return void
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- */
- private function sendRequest($sCommand, $sAddToCommand = '', $bSecureLog = false)
- {
- if (!\MailSo\Base\Validator::NotEmptyString($sCommand, true))
- {
- $this->writeLogException(
- new \MailSo\Base\Exceptions\InvalidArgumentException(),
- \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- $this->IsConnected(true);
-
- $sCommand = \trim($sCommand);
- $sRealCommand = $sCommand.(0 === \strlen($sAddToCommand) ? '' : ' '.$sAddToCommand);
-
- $sFakeCommand = ($bSecureLog) ? '********' : '';
-
- $this->iRequestTime = \microtime(true);
- $this->sendRaw($sRealCommand, true, $sFakeCommand);
-
- return $this;
- }
-
- /**
- * @param string $sCommand
- * @param int|array $mExpectCode
- * @param string $sAddToCommand = ''
- * @param bool $bSecureLog = false
- * @param string $sErrorPrefix = ''
- *
- * @return void
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Smtp\Exceptions\Exception
- */
- private function sendRequestWithCheck($sCommand, $mExpectCode, $sAddToCommand = '', $bSecureLog = false, $sErrorPrefix = '')
- {
- $this->sendRequest($sCommand, $sAddToCommand, $bSecureLog);
- $this->validateResponse($mExpectCode, $sErrorPrefix);
- }
-
- /**
- * @param string $sHost
- *
- * @return void
- */
- private function ehloOrHelo($sHost)
- {
- try
- {
- $this->ehlo($sHost);
- }
- catch (\Exception $oException)
- {
- try
- {
- $this->helo($sHost);
- }
- catch (\Exception $oException)
- {
- throw $oException;
- }
- }
-
- return $this;
- }
-
- /**
- * @param string $sHost
- *
- * @return void
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Smtp\Exceptions\Exception
- */
- private function ehlo($sHost)
- {
- $this->sendRequestWithCheck('EHLO', 250, $sHost);
-
- foreach ($this->aResults as $sLine)
- {
- $aMatch = array();
- if (\preg_match('/[\d]+[ \-](.+)$/', $sLine, $aMatch) && isset($aMatch[1]) && 0 < \strlen($aMatch[1]))
- {
- $sLine = \trim($aMatch[1]);
- $aLine = \preg_split('/[ =]/', $sLine, 2);
- if (\is_array($aLine) && 0 < \count($aLine) && !empty($aLine[0]))
- {
- $sCapa = \strtoupper($aLine[0]);
- if (('AUTH' === $sCapa || 'SIZE' === $sCapa) && !empty($aLine[1]))
- {
- $sSubLine = \trim(\strtoupper($aLine[1]));
- if (0 < \strlen($sSubLine))
- {
- if ('AUTH' === $sCapa)
- {
- $this->aAuthTypes = \explode(' ', $sSubLine);
- }
- else if ('SIZE' === $sCapa && \is_numeric($sSubLine))
- {
- $this->iSizeCapaValue = (int) $sSubLine;
- }
- }
- }
-
- $this->aCapa[] = $sCapa;
- }
- }
- }
- }
-
- /**
- * @param string $sHost
- *
- * @return void
- *
- * @throws \MailSo\Net\Exceptions\Exception
- * @throws \MailSo\Smtp\Exceptions\Exception
- */
- private function helo($sHost)
- {
- $this->sendRequestWithCheck('HELO', 250, $sHost);
- $this->aAuthTypes = array();
- $this->iSizeCapaValue = 0;
- $this->aCapa = array();
- }
-
- /**
- * @param int|array $mExpectCode
- * @param string $sErrorPrefix = ''
- *
- * @return void
- *
- * @throws \MailSo\Smtp\Exceptions\ResponseException
- */
- private function validateResponse($mExpectCode, $sErrorPrefix = '')
- {
- if (!\is_array($mExpectCode))
- {
- $mExpectCode = array((int) $mExpectCode);
- }
- else
- {
- $mExpectCode = \array_map('intval', $mExpectCode);
- }
-
- $aParts = array('', '', '');
- $this->aResults = array();
- do
- {
- $this->getNextBuffer();
- $aParts = \preg_split('/([\s\-]+)/', $this->sResponseBuffer, 2, PREG_SPLIT_DELIM_CAPTURE);
-
- if (\is_array($aParts) && 3 === \count($aParts) && \is_numeric($aParts[0]))
- {
- if ('-' !== \substr($aParts[1], 0, 1) && !\in_array((int) $aParts[0], $mExpectCode))
- {
- $this->writeLogException(
- new Exceptions\NegativeResponseException($this->aResults,
- ('' === $sErrorPrefix ? '' : $sErrorPrefix.': ').\trim(
- (0 < \count($this->aResults) ? \implode("\r\n", $this->aResults)."\r\n" : '').
- $this->sResponseBuffer)), \MailSo\Log\Enumerations\Type::ERROR, true);
- }
- }
- else
- {
- $this->writeLogException(
- new Exceptions\ResponseException($this->aResults,
- ('' === $sErrorPrefix ? '' : $sErrorPrefix.': ').\trim(
- (0 < \count($this->aResults) ? \implode("\r\n", $this->aResults)."\r\n" : '').
- $this->sResponseBuffer)), \MailSo\Log\Enumerations\Type::ERROR, true);
- }
-
- $this->aResults[] = $this->sResponseBuffer;
- }
- while ('-' === \substr($aParts[1], 0, 1));
-
- $this->writeLog((microtime(true) - $this->iRequestTime),
- \MailSo\Log\Enumerations\Type::TIME);
- }
-
- /**
- * @return string
- */
- protected function getLogName()
- {
- return 'SMTP';
- }
-
- /**
- * @param \MailSo\Log\Logger $oLogger
- *
- * @return \MailSo\Smtp\SmtpClient
- *
- * @throws \MailSo\Base\Exceptions\InvalidArgumentException
- */
- public function SetLogger($oLogger)
- {
- parent::SetLogger($oLogger);
-
- return $this;
- }
-}
+aAuthTypes = array();
+
+ $this->iRequestTime = 0;
+ $this->iSizeCapaValue = 0;
+ $this->aResults = array();
+ $this->aCapa = array();
+
+ $this->bHelo = false;
+ $this->bRcpt = false;
+ $this->bMail = false;
+ $this->bData = false;
+ }
+
+ /**
+ * @return \MailSo\Smtp\SmtpClient
+ */
+ public static function NewInstance()
+ {
+ return new self();
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsSupported($sCapa)
+ {
+ return in_array(strtoupper($sCapa), $this->aCapa);
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsAuthSupported($sAuth)
+ {
+ return in_array(strtoupper($sAuth), $this->aAuthTypes);
+ }
+
+ /**
+ * @return bool
+ */
+ public function HasSupportedAuth()
+ {
+ return $this->IsAuthSupported('PLAIN') || $this->IsAuthSupported('LOGIN');
+ }
+
+ /**
+ * @return string
+ */
+ public static function EhloHelper()
+ {
+ $sEhloHost = empty($_SERVER['SERVER_NAME']) ? '' : \trim($_SERVER['SERVER_NAME']);
+ if (empty($sEhloHost))
+ {
+ $sEhloHost = empty($_SERVER['HTTP_HOST']) ? '' : \trim($_SERVER['HTTP_HOST']);
+ }
+
+ if (empty($sEhloHost))
+ {
+ $sEhloHost = \function_exists('gethostname') ? \gethostname() : 'localhost';
+ }
+
+ $sEhloHost = \trim(\preg_replace('/:\d+$/', '', \trim($sEhloHost)));
+
+ if (\preg_match('/^\d+\.\d+\.\d+\.\d+$/', $sEhloHost))
+ {
+ $sEhloHost = '['.$sEhloHost.']';
+ }
+
+ return empty($sEhloHost) ? 'localhost' : $sEhloHost;
+ }
+
+ /**
+ * @param string $sServerName
+ * @param int $iPort = 25
+ * @param string $sEhloHost = '[127.0.0.1]'
+ * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT
+ * @param bool $bVerifySsl = false
+ * @param bool $bAllowSelfSigned = true
+ *
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\ResponseException
+ */
+ public function Connect($sServerName, $iPort = 25, $sEhloHost = '[127.0.0.1]',
+ $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT,
+ $bVerifySsl = false, $bAllowSelfSigned = true)
+ {
+ $this->iRequestTime = microtime(true);
+
+ parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned);
+
+ $this->validateResponse(220);
+
+ $this->preLoginStartTLSAndEhloProcess($sEhloHost);
+
+ return $this;
+ }
+
+ /**
+ * @param string $sLogin
+ * @param string $sPassword
+ * @param boolean $bUseAuthPlainIfSupported = true
+ * @param boolean $bUseAuthCramMd5IfSupported = true
+ *
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ public function Login($sLogin, $sPassword, $bUseAuthPlainIfSupported = true, $bUseAuthCramMd5IfSupported = true)
+ {
+ $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.' '.\MailSo\Base\Utils::Hmac($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);
+ }
+ }
+ 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
+ {
+ $this->writeLogException(
+ new \MailSo\Smtp\Exceptions\LoginBadMethodException(),
+ \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sXOAuth2Token
+ *
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ public function LoginWithXOauth2($sXOAuth2Token)
+ {
+ if ($this->IsAuthSupported('XOAUTH2'))
+ {
+ try
+ {
+ $this->sendRequestWithCheck('AUTH', 235, 'XOAUTH2 '.\trim($sXOAuth2Token));
+ }
+ 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
+ {
+ $this->writeLogException(
+ new \MailSo\Smtp\Exceptions\LoginBadMethodException(),
+ \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sFrom
+ * @param string $sSizeIfSupported = ''
+ * @param bool $bDsn = false
+ *
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ public function MailFrom($sFrom, $sSizeIfSupported = '', $bDsn = false)
+ {
+ $sFrom = \MailSo\Base\Utils::IdnToAscii(
+ \MailSo\Base\Utils::Trim($sFrom), true);
+
+ $sCmd = 'FROM:<'.$sFrom.'>';
+
+ $sSizeIfSupported = (string) $sSizeIfSupported;
+ if (0 < \strlen($sSizeIfSupported) && \is_numeric($sSizeIfSupported) && $this->IsSupported('SIZE'))
+ {
+ $sCmd .= ' SIZE='.$sSizeIfSupported;
+ }
+
+ if ($bDsn && $this->IsSupported('DSN'))
+ {
+ $sCmd .= ' RET=HDRS';
+ }
+
+ $this->sendRequestWithCheck('MAIL', 250, $sCmd);
+
+ $this->bMail = true;
+ $this->bRcpt = false;
+ $this->bData = false;
+
+ return $this;
+ }
+
+ /**
+ * @param string $sTo
+ * @param bool $bDsn = false
+ *
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ public function Rcpt($sTo, $bDsn = false)
+ {
+ if (!$this->bMail)
+ {
+ $this->writeLogException(
+ new Exceptions\RuntimeException('No sender reverse path has been supplied'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $sTo = \MailSo\Base\Utils::IdnToAscii(
+ \MailSo\Base\Utils::Trim($sTo), true);
+
+ $sCmd = 'TO:<'.$sTo.'>';
+
+ if ($bDsn && $this->IsSupported('DSN'))
+ {
+ $sCmd .= ' NOTIFY=SUCCESS,FAILURE';
+ }
+
+ $this->sendRequestWithCheck(
+ 'RCPT', array(250, 251), $sCmd, false,
+ 'Failed to add recipient "'.$sTo.'"'
+ );
+
+ $this->bRcpt = true;
+
+ return $this;
+ }
+
+ /**
+ * @param string $sTo
+ *
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ public function MailTo($sTo)
+ {
+ return $this->Rcpt($sTo);
+ }
+
+ /**
+ * @param string $sData
+ *
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ public function Data($sData)
+ {
+ if (!\MailSo\Base\Validator::NotEmptyString($sData, true))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $rDataStream = \MailSo\Base\ResourceRegistry::CreateMemoryResourceFromString($sData);
+ unset($sData);
+ $this->DataWithStream($rDataStream);
+ \MailSo\Base\ResourceRegistry::CloseMemoryResource($rDataStream);
+
+ return $this;
+ }
+
+ /**
+ * @param resource $rDataStream
+ *
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ public function DataWithStream($rDataStream)
+ {
+ if (!\is_resource($rDataStream))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ if (!$this->bRcpt)
+ {
+ $this->writeLogException(
+ new Exceptions\RuntimeException('No recipient forward path has been supplied'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $this->sendRequestWithCheck('DATA', 354);
+
+ $this->writeLog('Message data.', \MailSo\Log\Enumerations\Type::NOTE);
+
+ $this->bRunningCallback = true;
+
+ while (!\feof($rDataStream))
+ {
+ $sBuffer = \fgets($rDataStream);
+ if (false !== $sBuffer)
+ {
+ if (0 === \strpos($sBuffer, '.'))
+ {
+ $sBuffer = '.'.$sBuffer;
+ }
+
+ $this->sendRaw(\rtrim($sBuffer, "\r\n"), false);
+
+ \MailSo\Base\Utils::ResetTimeLimit();
+ continue;
+ }
+ else if (!\feof($rDataStream))
+ {
+ $this->writeLogException(
+ new Exceptions\RuntimeException('Cannot read input resource'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ break;
+ }
+
+ $this->sendRequestWithCheck('.', 250);
+
+ $this->bRunningCallback = false;
+
+ $this->bData = true;
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ public function Rset()
+ {
+ $this->sendRequestWithCheck('RSET', array(250, 220));
+
+ $this->bMail = false;
+ $this->bRcpt = false;
+ $this->bData = false;
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ public function Vrfy($sUser)
+ {
+ $sUser = \MailSo\Base\Utils::IdnToAscii(
+ \MailSo\Base\Utils::Trim($sUser));
+
+ $this->sendRequestWithCheck('VRFY', array(250, 251, 252), $sUser);
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ public function Noop()
+ {
+ $this->sendRequestWithCheck('NOOP', 250);
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ public function Logout()
+ {
+ if ($this->IsConnected())
+ {
+ $this->sendRequestWithCheck('QUIT', 221);
+ }
+
+ $this->bHelo = false;
+ $this->bMail = false;
+ $this->bRcpt = false;
+ $this->bData = false;
+
+ return $this;
+ }
+
+ /**
+ * @param string $sEhloHost
+ *
+ * @return void
+ */
+ private function preLoginStartTLSAndEhloProcess($sEhloHost)
+ {
+ if ($this->bHelo)
+ {
+ $this->writeLogException(
+ new Exceptions\RuntimeException('Cannot issue EHLO/HELO to existing session'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $this->ehloOrHelo($sEhloHost);
+
+ if (\MailSo\Net\Enumerations\ConnectionSecurityType::UseStartTLS(
+ $this->IsSupported('STARTTLS'), $this->iSecurityType, $this->HasSupportedAuth()))
+ {
+ $this->sendRequestWithCheck('STARTTLS', 220);
+ $this->EnableCrypto();
+
+ $this->ehloOrHelo($sEhloHost);
+ }
+ else if (\MailSo\Net\Enumerations\ConnectionSecurityType::STARTTLS === $this->iSecurityType)
+ {
+ $this->writeLogException(
+ new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('STARTTLS is not supported'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $this->bHelo = true;
+ }
+
+ /**
+ * @param string $sCommand
+ * @param string $sAddToCommand = ''
+ * @param bool $bSecureLog = false
+ *
+ * @return void
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ private function sendRequest($sCommand, $sAddToCommand = '', $bSecureLog = false)
+ {
+ if (!\MailSo\Base\Validator::NotEmptyString($sCommand, true))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $this->IsConnected(true);
+
+ $sCommand = \trim($sCommand);
+ $sRealCommand = $sCommand.(0 === \strlen($sAddToCommand) ? '' : ' '.$sAddToCommand);
+
+ $sFakeCommand = ($bSecureLog) ? '********' : '';
+
+ $this->iRequestTime = \microtime(true);
+ $this->sendRaw($sRealCommand, true, $sFakeCommand);
+
+ return $this;
+ }
+
+ /**
+ * @param string $sCommand
+ * @param int|array $mExpectCode
+ * @param string $sAddToCommand = ''
+ * @param bool $bSecureLog = false
+ * @param string $sErrorPrefix = ''
+ *
+ * @return void
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ private function sendRequestWithCheck($sCommand, $mExpectCode, $sAddToCommand = '', $bSecureLog = false, $sErrorPrefix = '')
+ {
+ $this->sendRequest($sCommand, $sAddToCommand, $bSecureLog);
+ $this->validateResponse($mExpectCode, $sErrorPrefix);
+ }
+
+ /**
+ * @param string $sHost
+ *
+ * @return void
+ */
+ private function ehloOrHelo($sHost)
+ {
+ try
+ {
+ $this->ehlo($sHost);
+ }
+ catch (\Exception $oException)
+ {
+ try
+ {
+ $this->helo($sHost);
+ }
+ catch (\Exception $oException)
+ {
+ throw $oException;
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sHost
+ *
+ * @return void
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ private function ehlo($sHost)
+ {
+ $this->sendRequestWithCheck('EHLO', 250, $sHost);
+
+ foreach ($this->aResults as $sLine)
+ {
+ $aMatch = array();
+ if (\preg_match('/[\d]+[ \-](.+)$/', $sLine, $aMatch) && isset($aMatch[1]) && 0 < \strlen($aMatch[1]))
+ {
+ $sLine = \trim($aMatch[1]);
+ $aLine = \preg_split('/[ =]/', $sLine, 2);
+ if (\is_array($aLine) && 0 < \count($aLine) && !empty($aLine[0]))
+ {
+ $sCapa = \strtoupper($aLine[0]);
+ if (('AUTH' === $sCapa || 'SIZE' === $sCapa) && !empty($aLine[1]))
+ {
+ $sSubLine = \trim(\strtoupper($aLine[1]));
+ if (0 < \strlen($sSubLine))
+ {
+ if ('AUTH' === $sCapa)
+ {
+ $this->aAuthTypes = \explode(' ', $sSubLine);
+ }
+ else if ('SIZE' === $sCapa && \is_numeric($sSubLine))
+ {
+ $this->iSizeCapaValue = (int) $sSubLine;
+ }
+ }
+ }
+
+ $this->aCapa[] = $sCapa;
+ }
+ }
+ }
+ }
+
+ /**
+ * @param string $sHost
+ *
+ * @return void
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ private function helo($sHost)
+ {
+ $this->sendRequestWithCheck('HELO', 250, $sHost);
+ $this->aAuthTypes = array();
+ $this->iSizeCapaValue = 0;
+ $this->aCapa = array();
+ }
+
+ /**
+ * @param int|array $mExpectCode
+ * @param string $sErrorPrefix = ''
+ *
+ * @return void
+ *
+ * @throws \MailSo\Smtp\Exceptions\ResponseException
+ */
+ private function validateResponse($mExpectCode, $sErrorPrefix = '')
+ {
+ if (!\is_array($mExpectCode))
+ {
+ $mExpectCode = array((int) $mExpectCode);
+ }
+ else
+ {
+ $mExpectCode = \array_map('intval', $mExpectCode);
+ }
+
+ $aParts = array('', '', '');
+ $this->aResults = array();
+ do
+ {
+ $this->getNextBuffer();
+ $aParts = \preg_split('/([\s\-]+)/', $this->sResponseBuffer, 2, PREG_SPLIT_DELIM_CAPTURE);
+
+ if (\is_array($aParts) && 3 === \count($aParts) && \is_numeric($aParts[0]))
+ {
+ if ('-' !== \substr($aParts[1], 0, 1) && !\in_array((int) $aParts[0], $mExpectCode))
+ {
+ $this->writeLogException(
+ new Exceptions\NegativeResponseException($this->aResults,
+ ('' === $sErrorPrefix ? '' : $sErrorPrefix.': ').\trim(
+ (0 < \count($this->aResults) ? \implode("\r\n", $this->aResults)."\r\n" : '').
+ $this->sResponseBuffer)), \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+ }
+ else
+ {
+ $this->writeLogException(
+ new Exceptions\ResponseException($this->aResults,
+ ('' === $sErrorPrefix ? '' : $sErrorPrefix.': ').\trim(
+ (0 < \count($this->aResults) ? \implode("\r\n", $this->aResults)."\r\n" : '').
+ $this->sResponseBuffer)), \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $this->aResults[] = $this->sResponseBuffer;
+ }
+ while ('-' === \substr($aParts[1], 0, 1));
+
+ $this->writeLog((microtime(true) - $this->iRequestTime),
+ \MailSo\Log\Enumerations\Type::TIME);
+ }
+
+ /**
+ * @return string
+ */
+ protected function getLogName()
+ {
+ return 'SMTP';
+ }
+
+ /**
+ * @param \MailSo\Log\Logger $oLogger
+ *
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function SetLogger($oLogger)
+ {
+ parent::SetLogger($oLogger);
+
+ return $this;
+ }
+}
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Vendors/Net/IDNA2.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Vendors/Net/IDNA2.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Vendors/Net/IDNA2.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Vendors/Net/IDNA2.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Vendors/Net/IDNA2CustomExceptions.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Vendors/Net/IDNA2CustomExceptions.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Vendors/Net/IDNA2CustomExceptions.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Vendors/Net/IDNA2CustomExceptions.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Version.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Version.php
similarity index 93%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Version.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Version.php
index f17b2871a11ecb6e6902055ba453159c76008e83..fd79b51d2dc5e4380a4bd9baffd49411f18db0c6 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/libraries/MailSo/Version.php
+++ b/rainloop/app/rainloop/v/1.12.1/app/libraries/MailSo/Version.php
@@ -1,59 +1,59 @@
-getSignature();
- }
-
- return $sSignature;
- }
-}
+getSignature();
+ }
+
+ return $sSignature;
+ }
+}
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Mobile_Detect/LICENSE.txt b/rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/LICENSE.txt
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Mobile_Detect/LICENSE.txt
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/LICENSE.txt
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Mobile_Detect/Mobile_Detect.json b/rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/Mobile_Detect.json
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Mobile_Detect/Mobile_Detect.json
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/Mobile_Detect.json
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Mobile_Detect/Mobile_Detect.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/Mobile_Detect.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Mobile_Detect/Mobile_Detect.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/Mobile_Detect.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Mobile_Detect/README.md b/rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/README.md
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Mobile_Detect/README.md
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/README.md
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Mobile_Detect/composer.json b/rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/composer.json
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Mobile_Detect/composer.json
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/composer.json
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Mobile_Detect/namespaced/Detection/MobileDetect.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/namespaced/Detection/MobileDetect.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Mobile_Detect/namespaced/Detection/MobileDetect.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/namespaced/Detection/MobileDetect.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Mobile_Detect/ruleset.xml b/rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/ruleset.xml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Mobile_Detect/ruleset.xml
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Mobile_Detect/ruleset.xml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/PHP-OAuth2/Client.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/Client.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/PHP-OAuth2/Client.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/Client.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/PHP-OAuth2/GrantType/AuthorizationCode.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/GrantType/AuthorizationCode.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/PHP-OAuth2/GrantType/AuthorizationCode.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/GrantType/AuthorizationCode.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/PHP-OAuth2/GrantType/ClientCredentials.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/GrantType/ClientCredentials.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/PHP-OAuth2/GrantType/ClientCredentials.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/GrantType/ClientCredentials.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/PHP-OAuth2/GrantType/IGrantType.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/GrantType/IGrantType.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/PHP-OAuth2/GrantType/IGrantType.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/GrantType/IGrantType.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/PHP-OAuth2/GrantType/Password.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/GrantType/Password.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/PHP-OAuth2/GrantType/Password.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/GrantType/Password.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/PHP-OAuth2/GrantType/RefreshToken.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/GrantType/RefreshToken.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/PHP-OAuth2/GrantType/RefreshToken.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/GrantType/RefreshToken.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/PHP-OAuth2/README b/rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/README
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/PHP-OAuth2/README
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/PHP-OAuth2/README
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/PHPGangsta/GoogleAuthenticator.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/PHPGangsta/GoogleAuthenticator.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/PHPGangsta/GoogleAuthenticator.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/PHPGangsta/GoogleAuthenticator.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/PHPThumb/GD.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/PHPThumb/GD.php
similarity index 97%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/PHPThumb/GD.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/PHPThumb/GD.php
index 53469eda3a8e72fc2e2bd033188ccd7b80d0e021..733fe476c0cd74d1414fc68b1b353e403025b226 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/libraries/PHPThumb/GD.php
+++ b/rainloop/app/rainloop/v/1.12.1/app/libraries/PHPThumb/GD.php
@@ -1,1417 +1,1417 @@
-
- * 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);
- }
- }
-}
+
+ * 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/rainloop/app/rainloop/v/1.12.0/app/libraries/PHPThumb/PHPThumb.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/PHPThumb/PHPThumb.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/PHPThumb/PHPThumb.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/PHPThumb/PHPThumb.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/PHPThumb/PluginInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/PHPThumb/PluginInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/PHPThumb/PluginInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/PHPThumb/PluginInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/PHPThumb/Plugins/Reflection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/PHPThumb/Plugins/Reflection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/PHPThumb/Plugins/Reflection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/PHPThumb/Plugins/Reflection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Autoloader.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Autoloader.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Autoloader.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Autoloader.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Client.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Client.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Client.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Client.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/ClientContextInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/ClientContextInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/ClientContextInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/ClientContextInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/ClientException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/ClientException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/ClientException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/ClientException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/ClientInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/ClientInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/ClientInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/ClientInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Cluster/ClusterStrategy.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/ClusterStrategy.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Cluster/ClusterStrategy.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/ClusterStrategy.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Cluster/Distributor/DistributorInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Distributor/DistributorInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Cluster/Distributor/DistributorInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Distributor/DistributorInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Cluster/Distributor/EmptyRingException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Distributor/EmptyRingException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Cluster/Distributor/EmptyRingException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Distributor/EmptyRingException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Cluster/Distributor/HashRing.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Distributor/HashRing.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Cluster/Distributor/HashRing.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Distributor/HashRing.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Cluster/Distributor/KetamaRing.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Distributor/KetamaRing.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Cluster/Distributor/KetamaRing.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Distributor/KetamaRing.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Cluster/Hash/CRC16.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Hash/CRC16.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Cluster/Hash/CRC16.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Hash/CRC16.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Cluster/Hash/HashGeneratorInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Hash/HashGeneratorInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Cluster/Hash/HashGeneratorInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/Hash/HashGeneratorInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Cluster/PredisStrategy.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/PredisStrategy.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Cluster/PredisStrategy.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/PredisStrategy.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Cluster/RedisStrategy.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/RedisStrategy.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Cluster/RedisStrategy.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/RedisStrategy.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Cluster/StrategyInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/StrategyInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Cluster/StrategyInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Cluster/StrategyInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Collection/Iterator/CursorBasedIterator.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/CursorBasedIterator.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Collection/Iterator/CursorBasedIterator.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/CursorBasedIterator.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Collection/Iterator/HashKey.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/HashKey.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Collection/Iterator/HashKey.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/HashKey.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Collection/Iterator/Keyspace.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/Keyspace.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Collection/Iterator/Keyspace.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/Keyspace.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Collection/Iterator/ListKey.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/ListKey.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Collection/Iterator/ListKey.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/ListKey.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Collection/Iterator/SetKey.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/SetKey.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Collection/Iterator/SetKey.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/SetKey.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Collection/Iterator/SortedSetKey.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/SortedSetKey.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Collection/Iterator/SortedSetKey.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Collection/Iterator/SortedSetKey.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/Command.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/Command.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/Command.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/Command.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/CommandInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/CommandInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/CommandInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/CommandInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ConnectionAuth.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ConnectionAuth.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ConnectionAuth.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ConnectionAuth.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ConnectionEcho.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ConnectionEcho.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ConnectionEcho.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ConnectionEcho.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ConnectionPing.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ConnectionPing.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ConnectionPing.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ConnectionPing.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ConnectionQuit.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ConnectionQuit.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ConnectionQuit.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ConnectionQuit.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ConnectionSelect.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ConnectionSelect.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ConnectionSelect.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ConnectionSelect.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashDelete.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashDelete.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashDelete.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashDelete.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashExists.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashExists.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashExists.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashExists.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashGet.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashGet.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashGet.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashGet.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashGetAll.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashGetAll.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashGetAll.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashGetAll.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashGetMultiple.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashGetMultiple.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashGetMultiple.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashGetMultiple.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashIncrementBy.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashIncrementBy.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashIncrementBy.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashIncrementBy.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashIncrementByFloat.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashIncrementByFloat.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashIncrementByFloat.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashIncrementByFloat.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashKeys.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashKeys.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashKeys.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashKeys.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashLength.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashLength.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashLength.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashLength.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashScan.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashScan.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashScan.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashScan.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashSet.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashSet.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashSet.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashSet.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashSetMultiple.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashSetMultiple.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashSetMultiple.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashSetMultiple.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashSetPreserve.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashSetPreserve.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashSetPreserve.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashSetPreserve.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashStringLength.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashStringLength.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashStringLength.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashStringLength.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashValues.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashValues.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HashValues.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HashValues.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HyperLogLogAdd.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HyperLogLogAdd.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HyperLogLogAdd.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HyperLogLogAdd.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HyperLogLogCount.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HyperLogLogCount.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HyperLogLogCount.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HyperLogLogCount.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HyperLogLogMerge.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HyperLogLogMerge.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/HyperLogLogMerge.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/HyperLogLogMerge.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyDelete.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyDelete.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyDelete.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyDelete.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyDump.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyDump.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyDump.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyDump.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyExists.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyExists.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyExists.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyExists.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyExpire.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyExpire.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyExpire.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyExpire.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyExpireAt.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyExpireAt.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyExpireAt.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyExpireAt.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyKeys.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyKeys.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyKeys.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyKeys.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyMigrate.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyMigrate.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyMigrate.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyMigrate.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyMove.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyMove.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyMove.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyMove.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyPersist.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyPersist.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyPersist.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyPersist.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyPreciseExpire.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyPreciseExpire.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyPreciseExpire.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyPreciseExpire.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyPreciseExpireAt.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyPreciseExpireAt.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyPreciseExpireAt.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyPreciseExpireAt.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyPreciseTimeToLive.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyPreciseTimeToLive.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyPreciseTimeToLive.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyPreciseTimeToLive.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyRandom.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyRandom.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyRandom.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyRandom.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyRename.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyRename.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyRename.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyRename.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyRenamePreserve.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyRenamePreserve.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyRenamePreserve.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyRenamePreserve.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyRestore.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyRestore.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyRestore.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyRestore.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyScan.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyScan.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyScan.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyScan.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeySort.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeySort.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeySort.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeySort.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyTimeToLive.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyTimeToLive.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyTimeToLive.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyTimeToLive.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyType.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyType.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/KeyType.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/KeyType.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListIndex.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListIndex.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListIndex.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListIndex.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListInsert.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListInsert.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListInsert.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListInsert.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListLength.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListLength.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListLength.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListLength.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListPopFirst.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopFirst.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListPopFirst.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopFirst.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListPopFirstBlocking.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopFirstBlocking.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListPopFirstBlocking.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopFirstBlocking.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListPopLast.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopLast.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListPopLast.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopLast.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListPopLastBlocking.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopLastBlocking.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListPopLastBlocking.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopLastBlocking.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListPopLastPushHead.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopLastPushHead.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListPopLastPushHead.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopLastPushHead.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListPopLastPushHeadBlocking.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopLastPushHeadBlocking.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListPopLastPushHeadBlocking.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPopLastPushHeadBlocking.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListPushHead.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPushHead.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListPushHead.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPushHead.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListPushHeadX.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPushHeadX.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListPushHeadX.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPushHeadX.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListPushTail.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPushTail.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListPushTail.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPushTail.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListPushTailX.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPushTailX.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListPushTailX.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListPushTailX.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListRange.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListRange.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListRange.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListRange.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListRemove.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListRemove.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListRemove.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListRemove.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListSet.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListSet.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListSet.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListSet.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListTrim.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListTrim.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ListTrim.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ListTrim.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/PrefixableCommandInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PrefixableCommandInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/PrefixableCommandInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PrefixableCommandInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/Processor/KeyPrefixProcessor.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/Processor/KeyPrefixProcessor.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/Processor/KeyPrefixProcessor.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/Processor/KeyPrefixProcessor.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/Processor/ProcessorChain.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/Processor/ProcessorChain.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/Processor/ProcessorChain.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/Processor/ProcessorChain.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/Processor/ProcessorInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/Processor/ProcessorInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/Processor/ProcessorInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/Processor/ProcessorInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/PubSubPublish.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubPublish.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/PubSubPublish.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubPublish.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/PubSubPubsub.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubPubsub.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/PubSubPubsub.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubPubsub.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/PubSubSubscribe.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubSubscribe.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/PubSubSubscribe.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubSubscribe.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/PubSubSubscribeByPattern.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubSubscribeByPattern.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/PubSubSubscribeByPattern.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubSubscribeByPattern.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/PubSubUnsubscribe.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubUnsubscribe.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/PubSubUnsubscribe.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubUnsubscribe.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/PubSubUnsubscribeByPattern.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubUnsubscribeByPattern.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/PubSubUnsubscribeByPattern.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/PubSubUnsubscribeByPattern.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/RawCommand.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/RawCommand.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/RawCommand.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/RawCommand.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ScriptCommand.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ScriptCommand.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ScriptCommand.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ScriptCommand.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerBackgroundRewriteAOF.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerBackgroundRewriteAOF.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerBackgroundRewriteAOF.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerBackgroundRewriteAOF.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerBackgroundSave.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerBackgroundSave.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerBackgroundSave.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerBackgroundSave.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerClient.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerClient.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerClient.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerClient.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerCommand.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerCommand.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerCommand.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerCommand.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerConfig.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerConfig.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerConfig.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerConfig.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerDatabaseSize.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerDatabaseSize.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerDatabaseSize.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerDatabaseSize.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerEval.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerEval.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerEval.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerEval.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerEvalSHA.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerEvalSHA.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerEvalSHA.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerEvalSHA.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerFlushAll.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerFlushAll.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerFlushAll.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerFlushAll.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerFlushDatabase.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerFlushDatabase.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerFlushDatabase.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerFlushDatabase.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerInfo.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerInfo.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerInfo.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerInfo.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerInfoV26x.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerInfoV26x.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerInfoV26x.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerInfoV26x.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerLastSave.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerLastSave.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerLastSave.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerLastSave.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerMonitor.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerMonitor.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerMonitor.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerMonitor.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerObject.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerObject.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerObject.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerObject.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerSave.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerSave.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerSave.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerSave.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerScript.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerScript.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerScript.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerScript.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerSentinel.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerSentinel.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerSentinel.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerSentinel.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerShutdown.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerShutdown.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerShutdown.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerShutdown.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerSlaveOf.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerSlaveOf.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerSlaveOf.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerSlaveOf.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerSlowlog.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerSlowlog.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerSlowlog.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerSlowlog.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerTime.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerTime.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ServerTime.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ServerTime.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetAdd.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetAdd.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetAdd.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetAdd.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetCardinality.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetCardinality.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetCardinality.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetCardinality.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetDifference.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetDifference.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetDifference.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetDifference.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetDifferenceStore.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetDifferenceStore.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetDifferenceStore.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetDifferenceStore.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetIntersection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetIntersection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetIntersection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetIntersection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetIntersectionStore.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetIntersectionStore.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetIntersectionStore.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetIntersectionStore.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetIsMember.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetIsMember.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetIsMember.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetIsMember.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetMembers.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetMembers.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetMembers.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetMembers.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetMove.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetMove.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetMove.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetMove.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetPop.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetPop.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetPop.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetPop.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetRandomMember.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetRandomMember.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetRandomMember.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetRandomMember.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetRemove.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetRemove.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetRemove.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetRemove.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetScan.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetScan.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetScan.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetScan.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetUnion.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetUnion.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetUnion.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetUnion.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetUnionStore.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetUnionStore.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/SetUnionStore.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/SetUnionStore.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringAppend.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringAppend.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringAppend.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringAppend.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringBitCount.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringBitCount.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringBitCount.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringBitCount.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringBitOp.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringBitOp.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringBitOp.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringBitOp.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringBitPos.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringBitPos.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringBitPos.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringBitPos.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringDecrement.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringDecrement.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringDecrement.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringDecrement.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringDecrementBy.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringDecrementBy.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringDecrementBy.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringDecrementBy.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringGet.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringGet.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringGet.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringGet.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringGetBit.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringGetBit.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringGetBit.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringGetBit.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringGetMultiple.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringGetMultiple.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringGetMultiple.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringGetMultiple.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringGetRange.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringGetRange.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringGetRange.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringGetRange.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringGetSet.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringGetSet.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringGetSet.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringGetSet.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringIncrement.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringIncrement.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringIncrement.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringIncrement.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringIncrementBy.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringIncrementBy.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringIncrementBy.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringIncrementBy.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringIncrementByFloat.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringIncrementByFloat.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringIncrementByFloat.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringIncrementByFloat.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringPreciseSetExpire.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringPreciseSetExpire.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringPreciseSetExpire.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringPreciseSetExpire.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringSet.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSet.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringSet.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSet.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringSetBit.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetBit.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringSetBit.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetBit.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringSetExpire.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetExpire.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringSetExpire.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetExpire.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringSetMultiple.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetMultiple.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringSetMultiple.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetMultiple.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringSetMultiplePreserve.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetMultiplePreserve.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringSetMultiplePreserve.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetMultiplePreserve.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringSetPreserve.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetPreserve.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringSetPreserve.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetPreserve.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringSetRange.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetRange.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringSetRange.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSetRange.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringStrlen.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringStrlen.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringStrlen.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringStrlen.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringSubstr.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSubstr.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/StringSubstr.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/StringSubstr.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/TransactionDiscard.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/TransactionDiscard.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/TransactionDiscard.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/TransactionDiscard.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/TransactionExec.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/TransactionExec.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/TransactionExec.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/TransactionExec.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/TransactionMulti.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/TransactionMulti.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/TransactionMulti.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/TransactionMulti.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/TransactionUnwatch.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/TransactionUnwatch.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/TransactionUnwatch.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/TransactionUnwatch.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/TransactionWatch.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/TransactionWatch.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/TransactionWatch.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/TransactionWatch.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetAdd.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetAdd.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetAdd.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetAdd.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetCardinality.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetCardinality.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetCardinality.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetCardinality.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetCount.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetCount.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetCount.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetCount.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetIncrementBy.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetIncrementBy.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetIncrementBy.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetIncrementBy.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetIntersectionStore.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetIntersectionStore.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetIntersectionStore.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetIntersectionStore.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetLexCount.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetLexCount.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetLexCount.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetLexCount.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetRange.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRange.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetRange.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRange.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetRangeByLex.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRangeByLex.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetRangeByLex.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRangeByLex.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetRangeByScore.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRangeByScore.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetRangeByScore.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRangeByScore.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetRank.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRank.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetRank.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRank.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetRemove.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRemove.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetRemove.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRemove.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetRemoveRangeByLex.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRemoveRangeByLex.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetRemoveRangeByLex.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRemoveRangeByLex.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetRemoveRangeByRank.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRemoveRangeByRank.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetRemoveRangeByRank.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRemoveRangeByRank.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetRemoveRangeByScore.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRemoveRangeByScore.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetRemoveRangeByScore.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetRemoveRangeByScore.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetReverseRange.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetReverseRange.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetReverseRange.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetReverseRange.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetReverseRangeByLex.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetReverseRangeByLex.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetReverseRangeByLex.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetReverseRangeByLex.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetReverseRangeByScore.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetReverseRangeByScore.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetReverseRangeByScore.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetReverseRangeByScore.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetReverseRank.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetReverseRank.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetReverseRank.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetReverseRank.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetScan.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetScan.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetScan.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetScan.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetScore.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetScore.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetScore.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetScore.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetUnionStore.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetUnionStore.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Command/ZSetUnionStore.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Command/ZSetUnionStore.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/CommunicationException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/CommunicationException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/CommunicationException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/CommunicationException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Configuration/ClusterOption.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/ClusterOption.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Configuration/ClusterOption.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/ClusterOption.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Configuration/ConnectionFactoryOption.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/ConnectionFactoryOption.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Configuration/ConnectionFactoryOption.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/ConnectionFactoryOption.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Configuration/ExceptionsOption.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/ExceptionsOption.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Configuration/ExceptionsOption.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/ExceptionsOption.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Configuration/OptionInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/OptionInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Configuration/OptionInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/OptionInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Configuration/Options.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/Options.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Configuration/Options.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/Options.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Configuration/OptionsInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/OptionsInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Configuration/OptionsInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/OptionsInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Configuration/PrefixOption.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/PrefixOption.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Configuration/PrefixOption.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/PrefixOption.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Configuration/ProfileOption.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/ProfileOption.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Configuration/ProfileOption.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/ProfileOption.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Configuration/ReplicationOption.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/ReplicationOption.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Configuration/ReplicationOption.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Configuration/ReplicationOption.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/AbstractConnection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/AbstractConnection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/AbstractConnection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/AbstractConnection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/Aggregate/ClusterInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Aggregate/ClusterInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/Aggregate/ClusterInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Aggregate/ClusterInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/Aggregate/MasterSlaveReplication.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Aggregate/MasterSlaveReplication.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/Aggregate/MasterSlaveReplication.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Aggregate/MasterSlaveReplication.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/Aggregate/PredisCluster.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Aggregate/PredisCluster.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/Aggregate/PredisCluster.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Aggregate/PredisCluster.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/Aggregate/RedisCluster.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Aggregate/RedisCluster.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/Aggregate/RedisCluster.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Aggregate/RedisCluster.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/Aggregate/ReplicationInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Aggregate/ReplicationInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/Aggregate/ReplicationInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Aggregate/ReplicationInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/AggregateConnectionInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/AggregateConnectionInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/AggregateConnectionInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/AggregateConnectionInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/CompositeConnectionInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/CompositeConnectionInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/CompositeConnectionInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/CompositeConnectionInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/CompositeStreamConnection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/CompositeStreamConnection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/CompositeStreamConnection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/CompositeStreamConnection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/ConnectionException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/ConnectionException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/ConnectionException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/ConnectionException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/ConnectionInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/ConnectionInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/ConnectionInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/ConnectionInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/Factory.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Factory.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/Factory.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Factory.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/FactoryInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/FactoryInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/FactoryInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/FactoryInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/NodeConnectionInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/NodeConnectionInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/NodeConnectionInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/NodeConnectionInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/Parameters.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Parameters.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/Parameters.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/Parameters.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/ParametersInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/ParametersInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/ParametersInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/ParametersInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/PhpiredisSocketConnection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/PhpiredisSocketConnection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/PhpiredisSocketConnection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/PhpiredisSocketConnection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/PhpiredisStreamConnection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/PhpiredisStreamConnection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/PhpiredisStreamConnection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/PhpiredisStreamConnection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/StreamConnection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/StreamConnection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/StreamConnection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/StreamConnection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/WebdisConnection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/WebdisConnection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Connection/WebdisConnection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Connection/WebdisConnection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Monitor/Consumer.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Monitor/Consumer.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Monitor/Consumer.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Monitor/Consumer.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/NotSupportedException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/NotSupportedException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/NotSupportedException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/NotSupportedException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Pipeline/Atomic.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Pipeline/Atomic.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Pipeline/Atomic.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Pipeline/Atomic.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Pipeline/ConnectionErrorProof.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Pipeline/ConnectionErrorProof.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Pipeline/ConnectionErrorProof.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Pipeline/ConnectionErrorProof.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Pipeline/FireAndForget.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Pipeline/FireAndForget.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Pipeline/FireAndForget.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Pipeline/FireAndForget.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Pipeline/Pipeline.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Pipeline/Pipeline.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Pipeline/Pipeline.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Pipeline/Pipeline.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/PredisException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/PredisException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/PredisException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/PredisException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Profile/Factory.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/Factory.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Profile/Factory.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/Factory.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Profile/ProfileInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/ProfileInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Profile/ProfileInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/ProfileInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Profile/RedisProfile.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisProfile.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Profile/RedisProfile.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisProfile.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Profile/RedisUnstable.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisUnstable.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Profile/RedisUnstable.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisUnstable.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Profile/RedisVersion200.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion200.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Profile/RedisVersion200.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion200.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Profile/RedisVersion220.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion220.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Profile/RedisVersion220.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion220.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Profile/RedisVersion240.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion240.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Profile/RedisVersion240.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion240.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Profile/RedisVersion260.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion260.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Profile/RedisVersion260.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion260.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Profile/RedisVersion280.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion280.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Profile/RedisVersion280.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion280.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Profile/RedisVersion300.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion300.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Profile/RedisVersion300.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Profile/RedisVersion300.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/ProtocolException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/ProtocolException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/ProtocolException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/ProtocolException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/ProtocolProcessorInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/ProtocolProcessorInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/ProtocolProcessorInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/ProtocolProcessorInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/RequestSerializerInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/RequestSerializerInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/RequestSerializerInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/RequestSerializerInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/ResponseReaderInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/ResponseReaderInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/ResponseReaderInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/ResponseReaderInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/Text/CompositeProtocolProcessor.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/CompositeProtocolProcessor.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/Text/CompositeProtocolProcessor.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/CompositeProtocolProcessor.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/Text/Handler/BulkResponse.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/BulkResponse.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/Text/Handler/BulkResponse.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/BulkResponse.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/Text/Handler/ErrorResponse.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/ErrorResponse.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/Text/Handler/ErrorResponse.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/ErrorResponse.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/Text/Handler/IntegerResponse.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/IntegerResponse.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/Text/Handler/IntegerResponse.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/IntegerResponse.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/Text/Handler/MultiBulkResponse.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/MultiBulkResponse.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/Text/Handler/MultiBulkResponse.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/MultiBulkResponse.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/Text/Handler/ResponseHandlerInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/ResponseHandlerInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/Text/Handler/ResponseHandlerInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/ResponseHandlerInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/Text/Handler/StatusResponse.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/StatusResponse.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/Text/Handler/StatusResponse.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/StatusResponse.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/Text/Handler/StreamableMultiBulkResponse.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/StreamableMultiBulkResponse.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/Text/Handler/StreamableMultiBulkResponse.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/Handler/StreamableMultiBulkResponse.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/Text/ProtocolProcessor.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/ProtocolProcessor.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/Text/ProtocolProcessor.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/ProtocolProcessor.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/Text/RequestSerializer.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/RequestSerializer.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/Text/RequestSerializer.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/RequestSerializer.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/Text/ResponseReader.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/ResponseReader.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Protocol/Text/ResponseReader.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Protocol/Text/ResponseReader.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/PubSub/AbstractConsumer.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/PubSub/AbstractConsumer.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/PubSub/AbstractConsumer.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/PubSub/AbstractConsumer.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/PubSub/Consumer.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/PubSub/Consumer.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/PubSub/Consumer.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/PubSub/Consumer.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/PubSub/DispatcherLoop.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/PubSub/DispatcherLoop.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/PubSub/DispatcherLoop.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/PubSub/DispatcherLoop.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Replication/ReplicationStrategy.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Replication/ReplicationStrategy.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Replication/ReplicationStrategy.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Replication/ReplicationStrategy.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Response/Error.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/Error.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Response/Error.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/Error.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Response/ErrorInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/ErrorInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Response/ErrorInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/ErrorInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Response/Iterator/MultiBulk.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/Iterator/MultiBulk.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Response/Iterator/MultiBulk.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/Iterator/MultiBulk.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Response/Iterator/MultiBulkIterator.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/Iterator/MultiBulkIterator.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Response/Iterator/MultiBulkIterator.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/Iterator/MultiBulkIterator.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Response/Iterator/MultiBulkTuple.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/Iterator/MultiBulkTuple.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Response/Iterator/MultiBulkTuple.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/Iterator/MultiBulkTuple.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Response/ResponseInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/ResponseInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Response/ResponseInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/ResponseInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Response/ServerException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/ServerException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Response/ServerException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/ServerException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Response/Status.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/Status.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Response/Status.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Response/Status.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Session/Handler.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Session/Handler.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Session/Handler.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Session/Handler.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Transaction/AbortedMultiExecException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Transaction/AbortedMultiExecException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Transaction/AbortedMultiExecException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Transaction/AbortedMultiExecException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Transaction/MultiExec.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Transaction/MultiExec.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Transaction/MultiExec.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Transaction/MultiExec.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Transaction/MultiExecState.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Transaction/MultiExecState.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/Predis/Transaction/MultiExecState.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/Predis/Transaction/MultiExecState.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/RainLoop/Actions.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Actions.php
similarity index 96%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/RainLoop/Actions.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Actions.php
index 2ae8e10de884f648d3ddf563bfd180812284b14b..001026720680fc3774299f7c876f2a3d1312efd6 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/libraries/RainLoop/Actions.php
+++ b/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Actions.php
@@ -1,10269 +1,10269 @@
-aCurrentActionParams = array();
-
- $this->oHttp = null;
- $this->oLogger = null;
- $this->oPlugins = null;
- $this->oMailClient = null;
- $this->oSocial = null;
- $this->oConfig = null;
- $this->aCachers = array();
-
- $this->oStorageProvider = null;
- $this->oLocalStorageProvider = null;
- $this->oSettingsProvider = null;
- $this->oLocalSettingsProvider = null;
- $this->oFilesProvider = null;
- $this->oFiltersProvider = null;
- $this->oDomainProvider = null;
- $this->oAddressBookProvider = null;
- $this->oSuggestionsProvider = null;
- $this->oChangePasswordProvider = null;
- $this->oTwoFactorAuthProvider = null;
- $this->oPremProvider = null;
-
- $this->sSpecAuthToken = '';
-
- $oConfig = $this->Config();
- $this->Plugins()->RunHook('filter.application-config', array(&$oConfig));
-
- $this->Logger()->Ping();
- }
-
- /**
- * @return \RainLoop\Actions
- */
- public static function NewInstance()
- {
- return new self();
- }
-
- /**
- * @param string $sSpecAuthToken
- *
- * @return \RainLoop\Application
- */
- public function SetSpecAuthToken($sSpecAuthToken)
- {
- $this->sSpecAuthToken = $sSpecAuthToken;
-
- return $this;
- }
-
- /**
- * @return string
- */
- public function GetSpecAuthToken()
- {
- return $this->sSpecAuthToken;
- }
-
- /**
- * @return string
- */
- public function GetShortLifeSpecAuthToken($iLife = 60)
- {
- $aAccountHash = \RainLoop\Utils::DecodeKeyValues($this->getLocalAuthToken());
- if (!empty($aAccountHash[0]) && 'token' === $aAccountHash[0] && \is_array($aAccountHash))
- {
- $aAccountHash[10] = \time() + $iLife;
- return \RainLoop\Utils::EncodeKeyValues($aAccountHash);
- }
-
- return '';
- }
-
- /**
- * @return \RainLoop\Application
- */
- public function Config()
- {
- if (null === $this->oConfig)
- {
- $this->oConfig = new \RainLoop\Config\Application();
- if (!$this->oConfig->Load())
- {
- usleep(10000);
- $this->oConfig->Load();
- }
-
-// if (!$bLoaded && !$this->oConfig->IsFileExists())
-// {
-// $bSave = true;
-// }
-//
-// if ($bLoaded && !$bSave)
-// {
-// $bSave = APP_VERSION !== $this->oConfig->Get('version', 'current');
-// }
-//
-// if ($bSave)
-// {
-// $this->oConfig->Save();
-// }
- }
-
- return $this->oConfig;
- }
-
- /**
- * @param string $sName
- * @param \RainLoop\Model\Account $oAccount = null
- *
- * @return mixed
- */
- private function fabrica($sName, $oAccount = null)
- {
- $mResult = null;
- $this->Plugins()
- ->RunHook('main.fabrica', array($sName, &$mResult), false)
- ->RunHook('main.fabrica[2]', array($sName, &$mResult, $oAccount), false)
- ;
-
- if (null === $mResult)
- {
- switch ($sName)
- {
- case 'files':
- // RainLoop\Providers\Files\IFiles
- $mResult = new \RainLoop\Providers\Files\FileStorage(APP_PRIVATE_DATA.'storage/files');
- break;
- case 'storage':
- case 'storage-local':
- // RainLoop\Providers\Storage\IStorage
- $mResult = new \RainLoop\Providers\Storage\FileStorage(
- APP_PRIVATE_DATA.'storage', 'storage-local' === $sName);
- break;
- case 'settings':
- case 'settings-local':
- // RainLoop\Providers\Settings\ISettings
- $mResult = new \RainLoop\Providers\Settings\DefaultSettings(
- $this->StorageProvider('settings-local' === $sName));
- break;
- case 'login':
- // \RainLoop\Providers\Login\LoginInterface
- $mResult = new \RainLoop\Providers\Login\DefaultLogin();
- break;
- case 'domain':
- // \RainLoop\Providers\Domain\DomainAdminInterface
- $mResult = new \RainLoop\Providers\Domain\DefaultDomain(APP_PRIVATE_DATA.'domains', $this->Cacher());
- break;
- case 'filters':
- // \RainLoop\Providers\Filters\FiltersInterface
- $mResult = new \RainLoop\Providers\Filters\SieveStorage(
- $this->Plugins(), $this->Config()
- );
- break;
- case 'address-book':
- // \RainLoop\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 \RainLoop\Providers\AddressBook\PdoAddressBook(
- 'sqlite:'.APP_PRIVATE_DATA.'AddressBook.sqlite', '', '', 'sqlite');
- }
- else
- {
- $mResult = new \RainLoop\Providers\AddressBook\PdoAddressBook($sDsn, $sUser, $sPassword, $sDsnType);
- }
- break;
- case 'suggestions':
-
- if (null === $mResult)
- {
- $mResult = array();
- }
-
- if (\is_array($mResult) && \RainLoop\Utils::IsOwnCloud() && $this->Config()->Get('labs', 'owncloud_suggestions', true))
- {
- // \RainLoop\Providers\Suggestions\ISuggestions
- $mResult[] = new \RainLoop\Providers\Suggestions\OwnCloudSuggestions();
- }
-
- break;
- case 'change-password':
- // \RainLoop\Providers\ChangePassword\ChangePasswordInterface
- break;
- case 'two-factor-auth':
- // \RainLoop\Providers\TwoFactorAuth\TwoFactorAuthInterface
- $mResult = new \RainLoop\Providers\TwoFactorAuth\GoogleTwoFactorAuth();
- break;
- }
- }
-
- foreach (\is_array($mResult) ? $mResult : array($mResult) as $oItem)
- {
- if ($oItem && \method_exists($oItem, 'SetLogger'))
- {
- $oItem->SetLogger($this->Logger());
- }
- }
-
- $this->Plugins()->RunHook('filter.fabrica', array($sName, &$mResult, $oAccount), false);
-
- return $mResult;
- }
-
- /**
- * @return void
- */
- public function BootStart()
- {
- if (defined('APP_INSTALLED_START') && defined('APP_INSTALLED_VERSION') &&
- APP_INSTALLED_START && !APP_INSTALLED_VERSION)
- {
- try
- {
- $this->KeenIO('Install');
- }
- catch (\Exception $oException) { unset($oException); }
- }
- }
-
- /**
- * @return void
- */
- public function BootEnd()
- {
- try
- {
- if ($this->MailClient()->IsLoggined())
- {
- $this->MailClient()->LogoutAndDisconnect();
- }
- }
- catch (\Exception $oException) { unset($oException); }
- }
-
- /**
- * @return string
- */
- public function ParseQueryAuthString()
- {
- $sQuery = \trim($this->Http()->GetQueryString());
-
- $iPos = \strpos($sQuery, '&');
- if (0 < $iPos)
- {
- $sQuery = \substr($sQuery, 0, $iPos);
- }
-
- $sQuery = \trim(\trim($sQuery), ' /');
-
- $aSubQuery = $this->Http()->GetQuery('q', null);
- if (\is_array($aSubQuery))
- {
- $aSubQuery = \array_map(function ($sS) {
- return \trim(\trim($sS), ' /');
- }, $aSubQuery);
-
- if (0 < \count($aSubQuery))
- {
- $sQuery .= '/'.\implode('/', $aSubQuery);
- }
- }
-
- if ('' === $this->GetSpecAuthToken())
- {
- $aPaths = \explode('/', $sQuery);
- if (!empty($aPaths[0]) && !empty($aPaths[1]) && '_' === substr($aPaths[1], 0, 1))
- {
- $this->SetSpecAuthToken($aPaths[1]);
- }
- }
-
- return $sQuery;
- }
-
- /**
- * @param string $sLine
- * @param \RainLoop\Model\Account $oAccount = null
- * @param bool $bUrlEncode = false
- * @param array $aAdditionalParams = array()
- *
- * @return string
- */
- private function compileLogParams($sLine, $oAccount = null, $bUrlEncode = false, $aAdditionalParams = array())
- {
- $aClear = array();
-
- if (false !== \strpos($sLine, '{date:'))
- {
- $sTimeOffset = (string) $this->Config()->Get('logs', 'time_offset', '0');
- $sLine = \preg_replace_callback('/\{date:([^}]+)\}/', function ($aMatch) use ($sTimeOffset, $bUrlEncode) {
- return \RainLoop\Utils::UrlEncode(\MailSo\Log\Logger::DateHelper($aMatch[1], $sTimeOffset), $bUrlEncode);
- }, $sLine);
-
- $aClear['/\{date:([^}]*)\}/'] = 'date';
- }
-
- if (false !== \strpos($sLine, '{imap:') || false !== \strpos($sLine, '{smtp:'))
- {
- if (!$oAccount)
- {
- $this->ParseQueryAuthString();
- $oAccount = $this->getAccountFromToken(false);
- }
-
- if ($oAccount)
- {
- $sLine = \str_replace('{imap:login}', \RainLoop\Utils::UrlEncode($oAccount->IncLogin(), $bUrlEncode), $sLine);
- $sLine = \str_replace('{imap:host}', \RainLoop\Utils::UrlEncode($oAccount->DomainIncHost(), $bUrlEncode), $sLine);
- $sLine = \str_replace('{imap:port}', \RainLoop\Utils::UrlEncode($oAccount->DomainIncPort(), $bUrlEncode), $sLine);
-
- $sLine = \str_replace('{smtp:login}', \RainLoop\Utils::UrlEncode($oAccount->OutLogin(), $bUrlEncode), $sLine);
- $sLine = \str_replace('{smtp:host}', \RainLoop\Utils::UrlEncode($oAccount->DomainOutHost(), $bUrlEncode), $sLine);
- $sLine = \str_replace('{smtp:port}', \RainLoop\Utils::UrlEncode($oAccount->DomainOutPort(), $bUrlEncode), $sLine);
- }
-
- $aClear['/\{imap:([^}]*)\}/i'] = 'imap';
- $aClear['/\{smtp:([^}]*)\}/i'] = 'smtp';
- }
-
- if (false !== \strpos($sLine, '{request:'))
- {
- if (false !== \strpos($sLine, '{request:ip}'))
- {
- $sLine = \str_replace('{request:ip}', \RainLoop\Utils::UrlEncode($this->Http()->GetClientIp(
- $this->Config()->Get('labs', 'http_client_ip_check_proxy', false)), $bUrlEncode), $sLine);
- }
-
- if (false !== \strpos($sLine, '{request:domain}'))
- {
- $sLine = \str_replace('{request:domain}',
- \RainLoop\Utils::UrlEncode($this->Http()->GetHost(false, true, true), $bUrlEncode), $sLine);
- }
-
- if (false !== \strpos($sLine, '{request:domain-clear}'))
- {
- $sLine = \str_replace('{request:domain-clear}',
- \RainLoop\Utils::UrlEncode(
- \MailSo\Base\Utils::GetClearDomainName($this->Http()->GetHost(false, true, true)), $bUrlEncode), $sLine);
- }
-
- $aClear['/\{request:([^}]*)\}/i'] = 'request';
- }
-
- if (false !== \strpos($sLine, '{user:'))
- {
- if (false !== \strpos($sLine, '{user:uid}'))
- {
- $sLine = \str_replace('{user:uid}',
- \RainLoop\Utils::UrlEncode(\base_convert(\sprintf('%u',
- \crc32(\md5(\RainLoop\Utils::GetConnectionToken()))), 10, 32), $bUrlEncode),
- $sLine
- );
- }
-
- if (false !== \strpos($sLine, '{user:ip}'))
- {
- $sLine = \str_replace('{user:ip}', \RainLoop\Utils::UrlEncode($this->Http()->GetClientIp(
- $this->Config()->Get('labs', 'http_client_ip_check_proxy', false)), $bUrlEncode), $sLine);
- }
-
- if (\preg_match('/\{user:(email|login|domain)\}/i', $sLine))
- {
- if (!$oAccount)
- {
- $this->ParseQueryAuthString();
- $oAccount = $this->getAccountFromToken(false);
- }
-
- if ($oAccount)
- {
- $sEmail = $oAccount->Email();
-
- $sLine = \str_replace('{user:email}', \RainLoop\Utils::UrlEncode($sEmail, $bUrlEncode), $sLine);
- $sLine = \str_replace('{user:login}', \RainLoop\Utils::UrlEncode(
- \MailSo\Base\Utils::GetAccountNameFromEmail($sEmail), $bUrlEncode), $sLine);
- $sLine = \str_replace('{user:domain}', \RainLoop\Utils::UrlEncode(
- \MailSo\Base\Utils::GetDomainFromEmail($sEmail), $bUrlEncode), $sLine);
- $sLine = \str_replace('{user:domain-clear}', \RainLoop\Utils::UrlEncode(
- \MailSo\Base\Utils::GetClearDomainName(
- \MailSo\Base\Utils::GetDomainFromEmail($sEmail)), $bUrlEncode), $sLine);
- }
- }
-
- $aClear['/\{user:([^}]*)\}/i'] = 'unknown';
- }
-
- if (false !== \strpos($sLine, '{labs:'))
- {
- $sLine = \preg_replace_callback('/\{labs:rand:([1-9])\}/', function ($aMatch) {
- return \rand(\pow(10, $aMatch[1] - 1), \pow(10, $aMatch[1]) - 1);
- }, $sLine);
-
- $aClear['/\{labs:([^}]*)\}/'] = 'labs';
- }
-
- if (\is_array($aAdditionalParams) && 0 < \count($aAdditionalParams))
- {
- foreach ($aAdditionalParams as $sKey => $sValue)
- {
- $sLine = \str_replace($sKey, $sValue, $sLine);
- }
- }
-
- if (0 < \count($aClear))
- {
- foreach ($aClear as $sKey => $sValue)
- {
- $sLine = \preg_replace($sKey, $sValue, $sLine);
- }
- }
-
- return $sLine;
- }
-
- /**
- * @param string $sFileName
- *
- * @return string
- */
- private function compileLogFileName($sFileName)
- {
- $sFileName = \trim($sFileName);
-
- if (0 !== \strlen($sFileName))
- {
- $sFileName = $this->compileLogParams($sFileName);
-
- $sFileName = \preg_replace('/[\/]+/', '/', \preg_replace('/[.]+/', '.', $sFileName));
- $sFileName = \preg_replace('/[^a-zA-Z0-9@_+=\-\.\/!()\[\]]/', '', $sFileName);
- }
-
- if (0 === \strlen($sFileName))
- {
- $sFileName = 'rainloop-log.txt';
- }
-
- return $sFileName;
- }
-
- /**
- * @return void
- */
- public function SetAuthLogoutToken()
- {
- @\header('X-RainLoop-Action: Logout');
- \RainLoop\Utils::SetCookie(self::AUTH_SPEC_LOGOUT_TOKEN_KEY, \md5(APP_START_TIME), 0);
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount
- *
- * @return void
- */
- public function SetAuthToken($oAccount)
- {
- if ($oAccount)
- {
- $sSpecAuthToken = '_'.$oAccount->GetAuthTokenQ();
-
- $this->SetSpecAuthToken($sSpecAuthToken);
- \RainLoop\Utils::SetCookie(self::AUTH_SPEC_TOKEN_KEY, $sSpecAuthToken, 0);
-
- if ($oAccount->SignMe() && 0 < \strlen($oAccount->SignMeToken()))
- {
- \RainLoop\Utils::SetCookie(self::AUTH_SIGN_ME_TOKEN_KEY,
- \RainLoop\Utils::EncodeKeyValuesQ(array(
- 'e' => $oAccount->Email(),
- 't' => $oAccount->SignMeToken()
- )),
- \time() + 60 * 60 * 24 * 30);
-
- $this->StorageProvider()->Put($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'sign_me',
- \RainLoop\Utils::EncodeKeyValuesQ(array(
- 'Time' => \time(),
- 'AuthToken' => $oAccount->GetAuthTokenQ(),
- 'SignMetToken' => $oAccount->SignMeToken()
- ))
- );
- }
- }
- }
-
- /**
- * @return string
- */
- public function GetSpecAuthTokenWithDeletion()
- {
- $sResult = \RainLoop\Utils::GetCookie(self::AUTH_SPEC_TOKEN_KEY, '');
- if (0 < strlen($sResult))
- {
- \RainLoop\Utils::ClearCookie(self::AUTH_SPEC_TOKEN_KEY);
- }
-
- return $sResult;
- }
-
- /**
- * @return string
- */
- public function GetSpecAuthLogoutTokenWithDeletion()
- {
- $sResult = \RainLoop\Utils::GetCookie(self::AUTH_SPEC_LOGOUT_TOKEN_KEY, '');
- if (0 < strlen($sResult))
- {
- \RainLoop\Utils::ClearCookie(self::AUTH_SPEC_LOGOUT_TOKEN_KEY);
- }
-
- return $sResult;
- }
-
- /**
- * @return string
- */
- public function GetSpecLogoutCustomMgsWithDeletion()
- {
- $sResult = \RainLoop\Utils::GetCookie(self::AUTH_SPEC_LOGOUT_CUSTOM_MSG_KEY, '');
- if (0 < strlen($sResult))
- {
- \RainLoop\Utils::ClearCookie(self::AUTH_SPEC_LOGOUT_CUSTOM_MSG_KEY);
- }
-
- return $sResult;
- }
-
- /**
- * @return string
- */
- public function SetSpecLogoutCustomMgsWithDeletion($sMessage)
- {
- \RainLoop\Utils::SetCookie(self::AUTH_SPEC_LOGOUT_CUSTOM_MSG_KEY, $sMessage, 0);
- }
-
- /**
- * @return void
- */
- private function setAdminAuthToken($sToken)
- {
- \RainLoop\Utils::SetCookie(self::AUTH_ADMIN_TOKEN_KEY, $sToken, 0);
- }
-
- /**
- * @return string
- */
- private function getLocalAuthToken()
- {
- $sToken = $this->GetSpecAuthToken();
- return !empty($sToken) && '_' === \substr($sToken, 0, 1) ? \substr($sToken, 1) : '';
- }
-
- /**
- * @return string
- */
- private function getAdminAuthToken()
- {
- return \RainLoop\Utils::GetCookie(self::AUTH_ADMIN_TOKEN_KEY, '');
- }
-
- /**
- * @return void
- */
- public function ClearAdminAuthToken()
- {
- $aAdminHash = \RainLoop\Utils::DecodeKeyValuesQ($this->getAdminAuthToken());
- if (
- !empty($aAdminHash[0]) && !empty($aAdminHash[1]) && !empty($aAdminHash[2]) &&
- 'token' === $aAdminHash[0] && \md5(APP_SALT) === $aAdminHash[1]
- )
- {
- $this->Cacher(null, true)->Delete(\RainLoop\KeyPathHelper::SessionAdminKey($aAdminHash[2]));
- }
-
- \RainLoop\Utils::ClearCookie(self::AUTH_ADMIN_TOKEN_KEY);
- }
-
- /**
- * @param bool $bThrowExceptionOnFalse = false
- *
- * @return \RainLoop\Model\Account|bool
- * @throws \RainLoop\Exceptions\ClientException
- */
- public function GetAccount($bThrowExceptionOnFalse = false)
- {
- return $this->getAccountFromToken($bThrowExceptionOnFalse);
- }
-
- /**
- * @return \MailSo\Base\Http
- */
- public function Http()
- {
- if (null === $this->oHttp)
- {
- $this->oHttp = \MailSo\Base\Http::SingletonInstance();
- }
-
- return $this->oHttp;
- }
-
- /**
- * @return \RainLoop\Social
- */
- public function Social()
- {
- if (null === $this->oSocial)
- {
- $this->oSocial = new \RainLoop\Social($this->Http(), $this);
- }
-
- return $this->oSocial;
- }
-
- /**
- * @return \MailSo\Mail\MailClient
- */
- public function MailClient()
- {
- if (null === $this->oMailClient)
- {
- $this->oMailClient = \MailSo\Mail\MailClient::NewInstance();
- $this->oMailClient->SetLogger($this->Logger());
- }
-
- return $this->oMailClient;
- }
-
- /**
- * @return \RainLoop\Providers\Filters
- */
- public function FiltersProvider()
- {
- if (null === $this->oFiltersProvider)
- {
- $this->oFiltersProvider = new \RainLoop\Providers\Filters(
- $this->fabrica('filters'));
- }
-
- return $this->oFiltersProvider;
- }
-
- /**
- * @return \RainLoop\Providers\ChangePassword
- */
- public function ChangePasswordProvider()
- {
- if (null === $this->oChangePasswordProvider)
- {
- $this->oChangePasswordProvider = new \RainLoop\Providers\ChangePassword(
- $this, $this->fabrica('change-password'), !!$this->Config()->Get('labs', 'check_new_password_strength', true)
- );
- }
-
- return $this->oChangePasswordProvider;
- }
-
- /**
- * @return \RainLoop\Providers\TwoFactorAuth
- */
- public function TwoFactorAuthProvider()
- {
- if (null === $this->oTwoFactorAuthProvider)
- {
- $this->oTwoFactorAuthProvider = new \RainLoop\Providers\TwoFactorAuth(
- $this->Config()->Get('security', 'allow_two_factor_auth', false) ? $this->fabrica('two-factor-auth') : null
- );
- }
-
- return $this->oTwoFactorAuthProvider;
- }
-
- /**
- * @return \RainLoop\Providers\Prem
- */
- public function PremProvider()
- {
- if (null === $this->oPremProvider)
- {
- if (\file_exists(APP_VERSION_ROOT_PATH.'app/libraries/RainLoop/Providers/Prem.php'))
- {
- $this->oPremProvider = new \RainLoop\Providers\Prem(
- $this->Config(), $this->Logger(), $this->Cacher(null, true)
- );
- }
- else
- {
- $this->oPremProvider = false;
- }
- }
-
- return $this->oPremProvider;
- }
-
- /**
- * @param bool $bLocal = false
- *
- * @return \RainLoop\Providers\Storage
- */
- public function StorageProvider($bLocal = false)
- {
- if ($bLocal)
- {
- if (null === $this->oLocalStorageProvider)
- {
- $this->oLocalStorageProvider = new \RainLoop\Providers\Storage(
- $this->fabrica('storage-local'));
- }
-
- return $this->oLocalStorageProvider;
- }
- else
- {
- if (null === $this->oStorageProvider)
- {
- $this->oStorageProvider = new \RainLoop\Providers\Storage(
- $this->fabrica('storage'));
- }
-
- return $this->oStorageProvider;
- }
-
- return null;
- }
-
- /**
- * @return \RainLoop\Providers\Settings
- */
- public function SettingsProvider($bLocal = false)
- {
- if ($bLocal)
- {
- if (null === $this->oLocalSettingsProvider)
- {
- $this->oLocalSettingsProvider = new \RainLoop\Providers\Settings(
- $this->fabrica('settings-local'));
- }
-
- return $this->oLocalSettingsProvider;
- }
- else
- {
- if (null === $this->oSettingsProvider)
- {
- $this->oSettingsProvider = new \RainLoop\Providers\Settings(
- $this->fabrica('settings'));
- }
-
- return $this->oSettingsProvider;
- }
-
- return null;
- }
-
- /**
- * @return \RainLoop\Providers\Files
- */
- public function FilesProvider()
- {
- if (null === $this->oFilesProvider)
- {
- $this->oFilesProvider = new \RainLoop\Providers\Files(
- $this->fabrica('files'));
- }
-
- return $this->oFilesProvider;
- }
-
- /**
- * @return \RainLoop\Providers\Domain
- */
- public function DomainProvider()
- {
- if (null === $this->oDomainProvider)
- {
- $this->oDomainProvider = new \RainLoop\Providers\Domain(
- $this->fabrica('domain'), $this->Plugins());
- }
-
- return $this->oDomainProvider;
- }
-
- /**
- * @return \RainLoop\Providers\Suggestions
- */
- public function SuggestionsProvider()
- {
- if (null === $this->oSuggestionsProvider)
- {
- $this->oSuggestionsProvider = new \RainLoop\Providers\Suggestions(
- $this->fabrica('suggestions'));
- }
-
- return $this->oSuggestionsProvider;
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount = null
- * @param bool $bForceEnable = false
- *
- * @return \RainLoop\Providers\AddressBook
- */
- public function AddressBookProvider($oAccount = null, $bForceEnable = false)
- {
- if (null === $this->oAddressBookProvider)
- {
- $oDriver = null;
- if ($this->GetCapa(false, false, \RainLoop\Enumerations\Capa::CONTACTS, $oAccount))
- {
- if ($this->Config()->Get('contacts', 'enable', false) || $bForceEnable)
- {
- $oDriver = $this->fabrica('address-book', $oAccount);
- }
- }
-
- $this->oAddressBookProvider = new \RainLoop\Providers\AddressBook($oDriver);
- $this->oAddressBookProvider->SetLogger($this->Logger());
- }
-
- return $this->oAddressBookProvider;
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount = null
- * @param bool $bForceFile = false
- *
- * @return \MailSo\Cache\CacheClient
- */
- public function Cacher($oAccount = null, $bForceFile = false)
- {
- $sKey = '';
- if ($oAccount)
- {
- $sKey = $oAccount->ParentEmailHelper();
- }
-
- $sIndexKey = empty($sKey) ? '_default_' : $sKey;
- if ($bForceFile)
- {
- $sIndexKey .= '/_files_';
- }
-
- if (!isset($this->aCachers[$sIndexKey]))
- {
- $this->aCachers[$sIndexKey] = \MailSo\Cache\CacheClient::NewInstance();
-
- $oDriver = null;
- $sDriver = \strtoupper(\trim($this->Config()->Get('cache', 'fast_cache_driver', 'files')));
-
- switch (true)
- {
- default:
- case $bForceFile:
- $oDriver = \MailSo\Cache\Drivers\File::NewInstance(APP_PRIVATE_DATA.'cache', $sKey);
- break;
-
- case ('APC' === $sDriver || 'APCU' === $sDriver) &&
- \MailSo\Base\Utils::FunctionExistsAndEnabled(array(
- 'apc_store', 'apc_fetch', 'apc_delete', 'apc_clear_cache')):
-
- $oDriver = \MailSo\Cache\Drivers\APC::NewInstance($sKey);
- break;
-
- case ('MEMCACHE' === $sDriver || 'MEMCACHED' === $sDriver) &&
- \MailSo\Base\Utils::FunctionExistsAndEnabled('memcache_connect'):
-
- $oDriver = \MailSo\Cache\Drivers\Memcache::NewInstance(
- $this->Config()->Get('labs', 'fast_cache_memcache_host', '127.0.0.1'),
- (int) $this->Config()->Get('labs', 'fast_cache_memcache_port', 11211),
- 43200,
- $sKey
- );
- break;
-
- case 'REDIS' === $sDriver && \class_exists('Predis\Client'):
- $oDriver = \MailSo\Cache\Drivers\Redis::NewInstance(
- $this->Config()->Get('labs', 'fast_cache_redis_host', '127.0.0.1'),
- (int) $this->Config()->Get('labs', 'fast_cache_redis_port', 6379),
- 43200,
- $sKey
- );
- break;
- }
-
- if ($oDriver)
- {
- $this->aCachers[$sIndexKey]->SetDriver($oDriver);
- }
-
- $this->aCachers[$sIndexKey]->SetCacheIndex($this->Config()->Get('cache', 'fast_cache_index', ''));
- }
-
- return $this->aCachers[$sIndexKey];
- }
-
- /**
- * @return \RainLoop\Plugins\Manager
- */
- public function Plugins()
- {
- if (null === $this->oPlugins)
- {
- $this->oPlugins = new \RainLoop\Plugins\Manager($this);
- $this->oPlugins->SetLogger($this->Logger());
- }
-
- return $this->oPlugins;
- }
-
- /**
- * @return \MailSo\Log\Logger
- */
- public function Logger()
- {
- if (null === $this->oLogger)
- {
- $this->oLogger = \MailSo\Log\Logger::SingletonInstance();
-
- if (!!$this->Config()->Get('logs', 'enable', false))
- {
- $sSessionFilter = (string) $this->Config()->Get('logs', 'session_filter', '');
- if (!empty($sSessionFilter))
- {
- $aSessionParts = \explode(':', $sSessionFilter, 2);
-
- if (empty($aSessionParts[0]) || empty($aSessionParts[1]) ||
- (string) $aSessionParts[1] !== (string) \RainLoop\Utils::GetCookie($aSessionParts[0], ''))
- {
- return $this->oLogger;
- }
- }
-
- $sTimeOffset = (string) $this->Config()->Get('logs', 'time_offset', '0');
-
- $this->oLogger->SetShowSecter(!$this->Config()->Get('logs', 'hide_passwords', true));
-
- $sLogFileName = $this->Config()->Get('logs', 'filename', '');
-
- $oDriver = null;
- if ('syslog' === $sLogFileName)
- {
- $oDriver = \MailSo\Log\Drivers\Syslog::NewInstance();
- }
- else
- {
- $sLogFileFullPath = \APP_PRIVATE_DATA.'logs/'.$this->compileLogFileName($sLogFileName);
- $sLogFileDir = \dirname($sLogFileFullPath);
-
- if (!@is_dir($sLogFileDir))
- {
- @mkdir($sLogFileDir, 0755, true);
- }
-
- $oDriver = \MailSo\Log\Drivers\File::NewInstance($sLogFileFullPath);
- }
-
- $this->oLogger->Add($oDriver
- ->WriteOnErrorOnly($this->Config()->Get('logs', 'write_on_error_only', false))
- ->WriteOnPhpErrorOnly($this->Config()->Get('logs', 'write_on_php_error_only', false))
- ->WriteOnTimeoutOnly($this->Config()->Get('logs', 'write_on_timeout_only', 0))
- ->SetTimeOffset($sTimeOffset)
- );
-
- if (!$this->Config()->Get('debug', 'enable', false))
- {
- $this->oLogger->AddForbiddenType(\MailSo\Log\Enumerations\Type::TIME);
- }
-
- $this->oLogger->WriteEmptyLine();
-
- $oHttp = $this->Http();
-
- $this->oLogger->Write('[DATE:'.\MailSo\Log\Logger::DateHelper('d.m.y', $sTimeOffset).
- (0 !== $sTimeOffset ? '][OFFSET:'.(0 < $sTimeOffset ? '+' : '-').
- \str_pad((string) \abs($sTimeOffset), 2, '0', STR_PAD_LEFT) : '').
- '][RL:'.APP_VERSION.'][PHP:'.PHP_VERSION.'][IP:'.
- $oHttp->GetClientIp($this->Config()->Get('labs', 'http_client_ip_check_proxy', false)).'][PID:'.
- (\MailSo\Base\Utils::FunctionExistsAndEnabled('getmypid') ? \getmypid() : 'unknown').']['.
- $oHttp->GetServer('SERVER_SOFTWARE', '~').']['.
- (\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('['.
- 'Suhosin:'.(\extension_loaded('suhosin') || @\ini_get('suhosin.get.max_value_length') ? 'on' : 'off').
- '][APC:'.(\MailSo\Base\Utils::FunctionExistsAndEnabled('apc_fetch') ? 'on' : 'off').
- '][MB:'.(\MailSo\Base\Utils::FunctionExistsAndEnabled('mb_convert_encoding') ? 'on' : 'off').
- '][PDO:'.$sPdo.
- (\RainLoop\Utils::IsOwnCloud() ? '][cloud:true' : '').
- '][Streams:'.\implode(',', \stream_get_transports()).
- ']');
-
- $this->oLogger->Write(
- '['.$oHttp->GetMethod().'] '.$oHttp->GetScheme().'://'.$oHttp->GetHost(false, false).$oHttp->GetServer('REQUEST_URI', ''),
- \MailSo\Log\Enumerations\Type::NOTE, 'REQUEST');
- }
- }
-
- return $this->oLogger;
- }
-
- /**
- * @return \MailSo\Log\Logger
- */
- public function LoggerAuth()
- {
- if (null === $this->oLoggerAuth)
- {
- $this->oLoggerAuth = \MailSo\Log\Logger::NewInstance(false);
-
- if (!!$this->Config()->Get('logs', 'auth_logging', false))
- {
- $sAuthLogFileFullPath = \APP_PRIVATE_DATA.'logs/'.$this->compileLogFileName(
- $this->Config()->Get('logs', 'auth_logging_filename', ''));
-
- $sLogFileDir = \dirname($sAuthLogFileFullPath);
-
- if (!@is_dir($sLogFileDir))
- {
- @mkdir($sLogFileDir, 0755, true);
- }
-
- $this->oLoggerAuth->AddForbiddenType(\MailSo\Log\Enumerations\Type::MEMORY);
- $this->oLoggerAuth->AddForbiddenType(\MailSo\Log\Enumerations\Type::TIME);
- $this->oLoggerAuth->AddForbiddenType(\MailSo\Log\Enumerations\Type::TIME_DELTA);
-
- $oDriver = \MailSo\Log\Drivers\File::NewInstance($sAuthLogFileFullPath);
-
- $oDriver->DisableTimePrefix();
- $oDriver->DisableGuidPrefix();
- $oDriver->DisableTypedPrefix();
-
- $this->oLoggerAuth->Add($oDriver);
- }
- }
-
- return $this->oLoggerAuth;
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount = null
- * @param array $aAdditionalParams = array()
- */
- public function LoggerAuthHelper($oAccount = null, $aAdditionalParams = array())
- {
- $sLine = $this->Config()->Get('logs', 'auth_logging_format', '');
- if (!empty($sLine))
- {
- $this->LoggerAuth()->Write($this->compileLogParams($sLine, $oAccount, false, $aAdditionalParams));
- }
- }
-
- /**
- * @return string
- */
- private function getAdminToken()
- {
- $sRand = \MailSo\Base\Utils::Md5Rand();
- if (!$this->Cacher(null, true)->Set(\RainLoop\KeyPathHelper::SessionAdminKey($sRand), \time()))
- {
- $this->oLogger->Write('Cannot store an admin token',
- \MailSo\Log\Enumerations\Type::WARNING);
-
- $sRand = '';
- }
-
- return '' === $sRand ? '' : \RainLoop\Utils::EncodeKeyValuesQ(array('token', \md5(APP_SALT), $sRand));
- }
-
- /**
- * @param bool $bThrowExceptionOnFalse = true
- *
- * @return bool
- */
- public function IsAdminLoggined($bThrowExceptionOnFalse = true)
- {
- $bResult = false;
- if ($this->Config()->Get('security', 'allow_admin_panel', true))
- {
- $aAdminHash = \RainLoop\Utils::DecodeKeyValuesQ($this->getAdminAuthToken());
- if (!empty($aAdminHash[0]) && !empty($aAdminHash[1]) && !empty($aAdminHash[2]) &&
- 'token' === $aAdminHash[0] && \md5(APP_SALT) === $aAdminHash[1] &&
- '' !== $this->Cacher(null, true)->Get(\RainLoop\KeyPathHelper::SessionAdminKey($aAdminHash[2]), '')
- )
- {
- $bResult = true;
- }
- }
-
- if (!$bResult && $bThrowExceptionOnFalse)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError);
- }
-
- return $bResult;
- }
-
- /**
- * @param string $sTo
- */
- public function SetMailtoRequest($sTo)
- {
- if (!empty($sTo))
- {
- \RainLoop\Utils::SetCookie(self::AUTH_MAILTO_TOKEN_KEY,
- \RainLoop\Utils::EncodeKeyValuesQ(array(
- 'Time' => \microtime(true),
- 'MailTo' => 'MailTo',
- 'To' => $sTo
- )), 0);
- }
- }
-
- /**
- * @param string $sEmail
- * @param string $sLogin
- * @param string $sPassword
- * @param string $sSignMeToken = ''
- * @param bool $bThrowProvideException = false
- *
- * @return \RainLoop\Model\Account|null
- */
- public function LoginProvide($sEmail, $sLogin, $sPassword, $sSignMeToken = '', $bThrowProvideException = false)
- {
- $oAccount = null;
- if (0 < \strlen($sEmail) && 0 < \strlen($sLogin) && 0 < \strlen($sPassword))
- {
- $oDomain = $this->DomainProvider()->Load(\MailSo\Base\Utils::GetDomainFromEmail($sEmail), true);
- if ($oDomain instanceof \RainLoop\Model\Domain)
- {
- if ($oDomain->ValidateWhiteList($sEmail, $sLogin))
- {
- $oAccount = \RainLoop\Model\Account::NewInstance($sEmail, $sLogin, $sPassword, $oDomain, $sSignMeToken);
- $this->Plugins()->RunHook('filter.account', array(&$oAccount));
-
- if ($bThrowProvideException && !($oAccount instanceof \RainLoop\Model\Account))
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError);
- }
- }
- else if ($bThrowProvideException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AccountNotAllowed);
- }
- }
- else if ($bThrowProvideException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::DomainNotAllowed);
- }
- }
-
- return $oAccount;
- }
-
- /**
- * @param string $sToken
- * @param bool $bThrowExceptionOnFalse = true
- * @param bool $bValidateShortToken = true
- * @param bool $bQ = false
- *
- * @return \RainLoop\Model\Account|bool
- * @throws \RainLoop\Exceptions\ClientException
- */
- public function GetAccountFromCustomToken($sToken, $bThrowExceptionOnFalse = true, $bValidateShortToken = true, $bQ = false)
- {
- $oResult = false;
- if (!empty($sToken))
- {
- $aAccountHash = $bQ ? \RainLoop\Utils::DecodeKeyValuesQ($sToken) : \RainLoop\Utils::DecodeKeyValues($sToken);
- if (!empty($aAccountHash[0]) && 'token' === $aAccountHash[0] && // simple token validation
- 8 <= \count($aAccountHash) && // length checking
- !empty($aAccountHash[7]) && // does short token exist
- (!$bValidateShortToken || \RainLoop\Utils::GetShortToken() === $aAccountHash[7] || // check short token if needed
- (isset($aAccountHash[10]) && 0 < $aAccountHash[10] && \time() < $aAccountHash[10]))
- )
- {
- $oAccount = $this->LoginProvide($aAccountHash[1], $aAccountHash[2], $aAccountHash[3],
- empty($aAccountHash[5]) ? '' : $aAccountHash[5], $bThrowExceptionOnFalse);
-
- if ($oAccount instanceof \RainLoop\Model\Account)
- {
- if (!empty($aAccountHash[8]) && !empty($aAccountHash[9])) // init proxy user/password
- {
- $oAccount->SetProxyAuthUser($aAccountHash[8]);
- $oAccount->SetProxyAuthPassword($aAccountHash[9]);
- }
-
- $this->Logger()->AddSecret($oAccount->Password());
- $this->Logger()->AddSecret($oAccount->ProxyAuthPassword());
-
- $oAccount->SetParentEmail($aAccountHash[6]);
- $oResult = $oAccount;
- }
- }
- else if ($bThrowExceptionOnFalse)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError);
- }
- }
-
- if ($bThrowExceptionOnFalse && !($oResult instanceof \RainLoop\Model\Account))
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError);
- }
-
- return $oResult;
- }
-
- /**
- * @return \RainLoop\Model\Account|bool
- */
- public function GetAccountFromSignMeToken()
- {
- $oAccount = false;
-
- $sSignMeToken = \RainLoop\Utils::GetCookie(\RainLoop\Actions::AUTH_SIGN_ME_TOKEN_KEY, '');
- if (!empty($sSignMeToken))
- {
- $aTokenData = \RainLoop\Utils::DecodeKeyValuesQ($sSignMeToken);
- if (\is_array($aTokenData) && !empty($aTokenData['e']) && !empty($aTokenData['t']))
- {
- $sTokenSettings = $this->StorageProvider()->Get($aTokenData['e'],
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'sign_me'
- );
-
- if (!empty($sTokenSettings))
- {
- $aSignMeData = \RainLoop\Utils::DecodeKeyValuesQ($sTokenSettings);
- if (\is_array($aSignMeData) &&
- !empty($aSignMeData['AuthToken']) &&
- !empty($aSignMeData['SignMetToken']) &&
- $aSignMeData['SignMetToken'] === $aTokenData['t'])
- {
- $oAccount = $this->GetAccountFromCustomToken($aSignMeData['AuthToken'], false, false, true);
- }
- }
- }
- }
- else
- {
- \RainLoop\Utils::ClearCookie(\RainLoop\Actions::AUTH_SIGN_ME_TOKEN_KEY);
- }
-
- return $oAccount;
- }
-
- /**
- * @param bool $bThrowExceptionOnFalse = true
- *
- * @return \RainLoop\Model\Account|bool
- * @throws \RainLoop\Exceptions\ClientException
- */
- public function getAccountFromToken($bThrowExceptionOnFalse = true)
- {
- return $this->GetAccountFromCustomToken($this->getLocalAuthToken(), $bThrowExceptionOnFalse, true, true);
- }
-
- /**
- * @return bool
- */
- public function IsOpen()
- {
- return !$this->PremProvider();
- }
-
- /**
- * @param bool $bAdmin = false
- * @param bool $bMobile = false
- * @param bool $bMobileDevice = false
- *
- * @return array
- */
- public function AppDataSystem($bAdmin = false, $bMobile = false, $bMobileDevice = false)
- {
- $oConfig = $this->Config();
-
- $aAttachmentsActions = array();
- if ($this->GetCapa(false, $bMobile, \RainLoop\Enumerations\Capa::ATTACHMENTS_ACTIONS))
- {
- if (!!\class_exists('ZipArchive'))
- {
- $aAttachmentsActions[] = 'zip';
- }
-
- if (\RainLoop\Utils::IsOwnCloudLoggedIn() && \class_exists('OCP\Files'))
- {
- $aAttachmentsActions[] = 'owncloud';
- }
-
- if ($oConfig->Get('social', 'dropbox_enable', false) && 0 < \strlen(\trim($oConfig->Get('social', 'dropbox_api_key', ''))))
- {
- $aAttachmentsActions[] = 'dropbox';
- }
- }
-
- return \array_merge(array(
- 'version' => APP_VERSION,
- 'admin' => $bAdmin,
- 'mobile' => $bMobile,
- 'mobileDevice' => $bMobileDevice,
- 'webPath' => \RainLoop\Utils::WebPath(),
- 'webVersionPath' => \RainLoop\Utils::WebVersionPath(),
- 'token' => $oConfig->Get('security', 'csrf_protection', false) ? \RainLoop\Utils::GetCsrfToken() : '',
- 'inIframe' => (bool) $oConfig->Get('labs', 'in_iframe', false),
- 'allowHtmlEditorSourceButton' => (bool) $oConfig->Get('labs', 'allow_html_editor_source_button', false),
- 'allowHtmlEditorBitiButtons' => (bool) $oConfig->Get('labs', 'allow_html_editor_biti_buttons', false),
- 'allowCtrlEnterOnCompose' => (bool) $oConfig->Get('labs', 'allow_ctrl_enter_on_compose', false),
- 'customLoginLink' => $oConfig->Get('labs', 'custom_login_link', ''),
- 'customLogoutLink' => $oConfig->Get('labs', 'custom_logout_link', ''),
- 'forgotPasswordLinkUrl' => \trim($oConfig->Get('login', 'forgot_password_link_url', '')),
- 'registrationLinkUrl' => \trim($oConfig->Get('login', 'registration_link_url', '')),
- 'hideSubmitButton' => (bool) $oConfig->Get('login', 'hide_submit_button', true),
- 'jsHash' => \md5(\RainLoop\Utils::GetConnectionToken()),
- 'useImapThread' => (bool) $oConfig->Get('labs', 'use_imap_thread', false),
- 'useImapSubscribe' => (bool) $oConfig->Get('labs', 'use_imap_list_subscribe', true),
- 'allowAppendMessage' => (bool) $oConfig->Get('labs', 'allow_message_append', false),
- 'materialDesign' => (bool) $oConfig->Get('labs', 'use_material_design', true),
- 'folderSpecLimit' => (int) $oConfig->Get('labs', 'folders_spec_limit', 50),
- 'faviconStatus' => (bool) $oConfig->Get('labs', 'favicon_status', true),
- 'allowCmdInterface' => (bool) $oConfig->Get('labs', 'allow_cmd', false),
- 'useNativeScrollbars' => (bool) $oConfig->Get('interface', 'use_native_scrollbars', false),
- 'listPermanentFiltered' => '' !== \trim(\RainLoop\Api::Config()->Get('labs', 'imap_message_list_permanent_filter', '')),
- 'themes' => $this->GetThemes($bMobile, false),
- 'languages' => $this->GetLanguages(false),
- 'languagesAdmin' => $this->GetLanguages(true),
- 'appVersionType' => APP_VERSION_TYPE,
- 'attachmentsActions' => $aAttachmentsActions
- ), $bAdmin ? array(
- 'adminHostUse' => '' !== $oConfig->Get('security', 'admin_panel_host', ''),
- 'adminPath' => \strtolower($oConfig->Get('security', 'admin_panel_key', 'admin')),
- 'allowAdminPanel' => (bool) $oConfig->Get('security', 'allow_admin_panel', true),
- ) : array());
- }
-
- /**
- * @param bool $bAdmin
- * @param bool $bMobile = false
- * @param string $sAuthAccountHash = ''
- *
- * @return array
- */
- public function AppData($bAdmin, $bMobile = false, $bMobileDevice = false, $sAuthAccountHash = '')
- {
- if (0 < \strlen($sAuthAccountHash) && \preg_match('/[^_\-\.a-zA-Z0-9]/', $sAuthAccountHash))
- {
- $sAuthAccountHash = '';
- }
-
- $oAccount = null;
- $oConfig = $this->Config();
-
-/*
-required by Index.html and rl.js:
-NewThemeLink IncludeCss LoadingDescriptionEsc TemplatesLink LangLink IncludeBackground PluginsLink AuthAccountHash
-*/
-
- $aResult = array(
- 'Auth' => false,
- 'AccountHash' => '',
- 'AccountSignMe' => false,
- 'AuthAccountHash' => '',
- 'MailToEmail' => '',
- 'Email' => '',
- 'DevEmail' => '',
- 'DevPassword' => '',
- 'Title' => $oConfig->Get('webmail', 'title', 'RainLoop Webmail'),
- 'LoadingDescription' => $oConfig->Get('webmail', 'loading_description', 'RainLoop'),
- 'LoadingDescriptionEsc' => 'RainLoop',
- 'FaviconUrl' => $oConfig->Get('webmail', 'favicon_url', ''),
- 'LoginDescription' => '',
- 'LoginPowered' => true,
- 'LoginLogo' => '',
- 'LoginBackground' => '',
- 'LoginCss' => '',
- 'UserLogo' => '',
- 'UserLogoTitle' => '',
- 'UserLogoMessage' => '',
- 'UserCss' => '',
- 'WelcomePageUrl' => '',
- 'WelcomePageDisplay' => 'none',
- 'IncludeCss' => '',
- 'IncludeBackground' => '',
- 'LoginDefaultDomain' => $oConfig->Get('login', 'default_domain', ''),
- 'DetermineUserLanguage' => (bool) $oConfig->Get('login', 'determine_user_language', true),
- 'DetermineUserDomain' => (bool) $oConfig->Get('login', 'determine_user_domain', false),
- 'UseLoginWelcomePage' => (bool) $oConfig->Get('login', 'welcome_page', false),
- 'StartupUrl' => \trim(\ltrim(\trim($oConfig->Get('labs', 'startup_url', '')), '#/')),
- 'SieveAllowFileintoInbox' => (bool) $oConfig->Get('labs', 'sieve_allow_fileinto_inbox', false),
- 'ContactsIsAllowed' => false,
- 'ChangePasswordIsAllowed' => false,
- 'RequireTwoFactor' => false,
- 'Community' => true,
- 'PremType' => false,
- 'Admin' => array(),
- 'Capa' => array(),
- 'Plugins' => array(),
- 'System' => $this->AppDataSystem($bAdmin, $bMobile, $bMobileDevice)
- );
-
- if (0 < \strlen($sAuthAccountHash))
- {
- $aResult['AuthAccountHash'] = $sAuthAccountHash;
- }
-
- $oPremProvider = $this->PremProvider();
- if ($oPremProvider)
- {
- $oPremProvider->PopulateAppData($aResult);
- }
-
- if ('' !== $aResult['LoadingDescription'] && 'RainLoop' !== $aResult['LoadingDescription'])
- {
- $aResult['LoadingDescriptionEsc'] = @\htmlspecialchars($aResult['LoadingDescription'], ENT_QUOTES|ENT_IGNORE, 'UTF-8');
- }
-
- $oSettings = null;
-
- if (!$bAdmin)
- {
- $oAccount = $this->getAccountFromToken(false);
- if ($oAccount instanceof \RainLoop\Model\Account)
- {
- $aResult['IncludeCss'] = $aResult['UserCss'];
-
- $oAddressBookProvider = $this->AddressBookProvider($oAccount);
-
- $aResult['Auth'] = true;
- $aResult['Email'] = $oAccount->Email();
- $aResult['IncLogin'] = $oAccount->IncLogin();
- $aResult['OutLogin'] = $oAccount->OutLogin();
- $aResult['AccountHash'] = $oAccount->Hash();
- $aResult['AccountSignMe'] = $oAccount->SignMe();
- $aResult['ChangePasswordIsAllowed'] = $this->ChangePasswordProvider()->PasswordChangePossibility($oAccount);
- $aResult['ContactsIsAllowed'] = $oAddressBookProvider->IsActive();
- $aResult['ContactsSyncIsAllowed'] = (bool) $oConfig->Get('contacts', 'allow_sync', false);
- $aResult['ContactsSyncInterval'] = (int) $oConfig->Get('contacts', 'sync_interval', 20);
-
- $aResult['EnableContactsSync'] = false;
- $aResult['ContactsSyncUrl'] = '';
- $aResult['ContactsSyncUser'] = '';
- $aResult['ContactsSyncPassword'] = '';
-
- if ($aResult['ContactsIsAllowed'] && $aResult['ContactsSyncIsAllowed'])
- {
- $mData = $this->getContactsSyncData($oAccount);
- if (\is_array($mData))
- {
- $aResult['EnableContactsSync'] = isset($mData['Enable']) ? !!$mData['Enable'] : false;
- $aResult['ContactsSyncUrl'] = isset($mData['Url']) ? \trim($mData['Url']) : '';
- $aResult['ContactsSyncUser'] = isset($mData['User']) ? \trim($mData['User']) : '';
- $aResult['ContactsSyncPassword'] = APP_DUMMY;
- }
- }
-
- if ($aResult['AccountSignMe'])
- {
- $sToken = \RainLoop\Utils::GetCookie(self::AUTH_MAILTO_TOKEN_KEY, null);
- if (null !== $sToken)
- {
- \RainLoop\Utils::ClearCookie(self::AUTH_MAILTO_TOKEN_KEY);
-
- $mMailToData = \RainLoop\Utils::DecodeKeyValuesQ($sToken);
- if (\is_array($mMailToData) && !empty($mMailToData['MailTo']) &&
- 'MailTo' === $mMailToData['MailTo'] && !empty($mMailToData['To']))
- {
- $aResult['MailToEmail'] = $mMailToData['To'];
- }
- }
- }
-
- $oSettings = $this->SettingsProvider()->Load($oAccount);
-
- if (!$oAccount->IsAdditionalAccount() && !empty($aResult['WelcomePageUrl']) &&
- ('once' === $aResult['WelcomePageDisplay'] || 'always' === $aResult['WelcomePageDisplay']))
- {
- if ('once' === $aResult['WelcomePageDisplay'])
- {
- if ($aResult['WelcomePageUrl'] === $oSettings->GetConf('LastWelcomePage', ''))
- {
- $aResult['WelcomePageUrl'] = '';
- $aResult['WelcomePageDisplay'] = '';
- }
- }
- }
- else
- {
- $aResult['WelcomePageUrl'] = '';
- $aResult['WelcomePageDisplay'] = '';
- }
-
- if (!empty($aResult['StartupUrl']))
- {
- $aResult['StartupUrl'] = $this->compileLogParams($aResult['StartupUrl'], $oAccount, true);
- }
-
- if (!empty($aResult['UserIframeMessage']))
- {
- $aResult['UserIframeMessage'] = $this->compileLogParams($aResult['UserIframeMessage'], $oAccount, true);
- }
- }
- else
- {
- $oAccount = null;
-
- $aResult['IncludeBackground'] = $aResult['LoginBackground'];
- $aResult['IncludeCss'] = $aResult['LoginCss'];
-
- $aResult['DevEmail'] = $oConfig->Get('labs', 'dev_email', '');
- $aResult['DevPassword'] = $oConfig->Get('labs', 'dev_password', '');
-
- $aResult['WelcomePageUrl'] = '';
- $aResult['WelcomePageDisplay'] = '';
-
- $aResult['StartupUrl'] = '';
-
- if (empty($aResult['AdditionalLoginError']))
- {
- $aResult['AdditionalLoginError'] = $this->GetSpecLogoutCustomMgsWithDeletion();
- }
- }
-
- $aResult['AllowGoogleSocial'] = (bool) $oConfig->Get('social', 'google_enable', false);
- $aResult['AllowGoogleSocialAuth'] = (bool) $oConfig->Get('social', 'google_enable_auth', true);
- $aResult['AllowGoogleSocialAuthFast'] = (bool) $oConfig->Get('social', 'google_enable_auth_fast', true);
- $aResult['AllowGoogleSocialDrive'] = (bool) $oConfig->Get('social', 'google_enable_drive', true);
- $aResult['AllowGoogleSocialPreview'] = (bool) $oConfig->Get('social', 'google_enable_preview', true);
-
- $aResult['GoogleClientID'] = \trim($oConfig->Get('social', 'google_client_id', ''));
- $aResult['GoogleApiKey'] = \trim($oConfig->Get('social', 'google_api_key', ''));
-
- if (!$aResult['AllowGoogleSocial'] || ($aResult['AllowGoogleSocial'] && (
- '' === \trim($oConfig->Get('social', 'google_client_id', '')) || '' === \trim($oConfig->Get('social', 'google_client_secret', '')))))
- {
- $aResult['AllowGoogleSocialAuth'] = false;
- $aResult['AllowGoogleSocialAuthFast'] = false;
- $aResult['AllowGoogleSocialDrive'] = false;
- $aResult['GoogleClientID'] = '';
- $aResult['GoogleApiKey'] = '';
- }
-
- if (!$aResult['AllowGoogleSocial'])
- {
- $aResult['AllowGoogleSocialPreview'] = false;
- }
-
- if ($aResult['AllowGoogleSocial'] &&
- !$aResult['AllowGoogleSocialAuth'] && !$aResult['AllowGoogleSocialAuthFast'] &&
- !$aResult['AllowGoogleSocialDrive'] && !$aResult['AllowGoogleSocialPreview'])
- {
- $aResult['AllowGoogleSocial'] = false;
- }
-
- $aResult['AllowFacebookSocial'] = (bool) $oConfig->Get('social', 'fb_enable', false);
- if ($aResult['AllowFacebookSocial'] && (
- '' === \trim($oConfig->Get('social', 'fb_app_id', '')) || '' === \trim($oConfig->Get('social', 'fb_app_secret', ''))))
- {
- $aResult['AllowFacebookSocial'] = false;
- }
-
- $aResult['AllowTwitterSocial'] = (bool) $oConfig->Get('social', 'twitter_enable', false);
- if ($aResult['AllowTwitterSocial'] && (
- '' === \trim($oConfig->Get('social', 'twitter_consumer_key', '')) || '' === \trim($oConfig->Get('social', 'twitter_consumer_secret', ''))))
- {
- $aResult['AllowTwitterSocial'] = false;
- }
-
- $aResult['AllowDropboxSocial'] = (bool) $oConfig->Get('social', 'dropbox_enable', false);
- $aResult['DropboxApiKey'] = \trim($oConfig->Get('social', 'dropbox_api_key', ''));
-
- if (!$aResult['AllowDropboxSocial'])
- {
- $aResult['DropboxApiKey'] = '';
- }
- else if (0 === strlen($aResult['DropboxApiKey']))
- {
- $aResult['AllowDropboxSocial'] = false;
- }
-
- $aResult['Capa'] = $this->Capa(false, $bMobile, $oAccount);
-
- if ($aResult['Auth'] && !$aResult['RequireTwoFactor'])
- {
- if ($this->GetCapa(false, $bMobile, \RainLoop\Enumerations\Capa::TWO_FACTOR, $oAccount) &&
- $this->GetCapa(false, $bMobile, \RainLoop\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'])
- {
- $aResult['AdminDomain'] = APP_SITE;
- $aResult['AdminLogin'] = (string) $oConfig->Get('security', 'admin_login', '');
- $aResult['UseTokenProtection'] = (bool) $oConfig->Get('security', 'csrf_protection', true);
- $aResult['EnabledPlugins'] = (bool) $oConfig->Get('plugins', 'enable', false);
-
- $aResult['VerifySslCertificate'] = (bool) $oConfig->Get('ssl', 'verify_certificate', false);
- $aResult['AllowSelfSigned'] = (bool) $oConfig->Get('ssl', 'allow_self_signed', true);
-
- $aDrivers = \class_exists('PDO') ? \PDO::getAvailableDrivers() : null;
- $aResult['MySqlIsSupported'] = \is_array($aDrivers) ? \in_array('mysql', $aDrivers) : false;
- $aResult['SQLiteIsSupported'] = \is_array($aDrivers) ? \in_array('sqlite', $aDrivers) : false;
- $aResult['PostgreSqlIsSupported'] = \is_array($aDrivers) ? \in_array('pgsql', $aDrivers) : false;
-
- $aResult['ContactsEnable'] = (bool) $oConfig->Get('contacts', 'enable', false);
- $aResult['ContactsSync'] = (bool) $oConfig->Get('contacts', 'allow_sync', false);
- $aResult['ContactsPdoType'] = (string) $this->ValidateContactPdoType(\trim($this->Config()->Get('contacts', 'type', 'sqlite')));
- $aResult['ContactsPdoDsn'] = (string) $oConfig->Get('contacts', 'pdo_dsn', '');
- $aResult['ContactsPdoType'] = (string) $oConfig->Get('contacts', 'type', '');
- $aResult['ContactsPdoUser'] = (string) $oConfig->Get('contacts', 'pdo_user', '');
- $aResult['ContactsPdoPassword'] = (string) APP_DUMMY;
-
- $aResult['AllowGoogleSocial'] = (bool) $oConfig->Get('social', 'google_enable', false);
- $aResult['AllowGoogleSocialAuth'] = (bool) $oConfig->Get('social', 'google_enable_auth', true);
- $aResult['AllowGoogleSocialAuthFast'] = (bool) $oConfig->Get('social', 'google_enable_auth_fast', true);
- $aResult['AllowGoogleSocialDrive'] = (bool) $oConfig->Get('social', 'google_enable_drive', true);
- $aResult['AllowGoogleSocialPreview'] = (bool) $oConfig->Get('social', 'google_enable_preview', true);
-
- $aResult['GoogleClientID'] = (string) $oConfig->Get('social', 'google_client_id', '');
- $aResult['GoogleClientSecret'] = (string) $oConfig->Get('social', 'google_client_secret', '');
- $aResult['GoogleApiKey'] = (string) $oConfig->Get('social', 'google_api_key', '');
-
- $aResult['AllowFacebookSocial'] = (bool) $oConfig->Get('social', 'fb_enable', false);
- $aResult['FacebookAppID'] = (string) $oConfig->Get('social', 'fb_app_id', '');
- $aResult['FacebookAppSecret'] = (string) $oConfig->Get('social', 'fb_app_secret', '');
-
- $aResult['AllowTwitterSocial'] = (bool) $oConfig->Get('social', 'twitter_enable', false);
- $aResult['TwitterConsumerKey'] = (string) $oConfig->Get('social', 'twitter_consumer_key', '');
- $aResult['TwitterConsumerSecret'] = (string) $oConfig->Get('social', 'twitter_consumer_secret', '');
-
- $aResult['AllowDropboxSocial'] = (bool) $oConfig->Get('social', 'dropbox_enable', false);
- $aResult['DropboxApiKey'] = (string) $oConfig->Get('social', 'dropbox_api_key', '');
-
- $aResult['SubscriptionEnabled'] = (bool) \MailSo\Base\Utils::ValidateDomain($aResult['AdminDomain'], true);
-// || \MailSo\Base\Utils::ValidateIP($aResult['AdminDomain']);
-
- $aResult['WeakPassword'] = (bool) $oConfig->ValidatePassword('12345');
- $aResult['CoreAccess'] = (bool) $this->rainLoopCoreAccess();
-
- $aResult['PhpUploadSizes'] = array(
- 'upload_max_filesize' => \ini_get('upload_max_filesize'),
- 'post_max_size' => \ini_get('post_max_size')
- );
- }
-
- $aResult['Capa'] = $this->Capa(true, $bMobile);
- }
-
- $aResult['SupportedFacebookSocial'] = (bool) \version_compare(PHP_VERSION, '5.4.0', '>=');
- if (!$aResult['SupportedFacebookSocial'])
- {
- $aResult['AllowFacebookSocial'] = false;
- $aResult['FacebookAppID'] = '';
- $aResult['FacebookAppSecret'] = '';
- }
-
- $aResult['ProjectHash'] = \md5($aResult['AccountHash'].APP_VERSION.$this->Plugins()->Hash());
-
- $sLanguage = $oConfig->Get('webmail', 'language', 'en');
- $sLanguageAdmin = $oConfig->Get('webmail', 'language_admin', 'en');
- $sTheme = $oConfig->Get('webmail', 'theme', 'Default');
-
- $aResult['NewMoveToFolder'] = (bool) $oConfig->Get('interface', 'new_move_to_folder_button', true);
- $aResult['AllowLanguagesOnSettings'] = (bool) $oConfig->Get('webmail', 'allow_languages_on_settings', true);
- $aResult['AllowLanguagesOnLogin'] = (bool) $oConfig->Get('login', 'allow_languages_on_login', true);
- $aResult['AttachmentLimit'] = ((int) $oConfig->Get('webmail', 'attachment_size_limit', 10)) * 1024 * 1024;
- $aResult['SignMe'] = (string) $oConfig->Get('login', 'sign_me_auto', \RainLoop\Enumerations\SignMeType::DEFAILT_OFF);
- $aResult['UseLocalProxyForExternalImages'] = (bool) $oConfig->Get('labs', 'use_local_proxy_for_external_images', false);
-
- // user
- $aResult['ShowImages'] = (bool) $oConfig->Get('defaults', 'show_images', false);
- $aResult['MPP'] = (int) $oConfig->Get('webmail', 'messages_per_page', 25);
- $aResult['SoundNotification'] = false;
- $aResult['DesktopNotifications'] = false;
- $aResult['Layout'] = (int) $oConfig->Get('defaults', 'view_layout', \RainLoop\Enumerations\Layout::SIDE_PREVIEW);
- $aResult['EditorDefaultType'] = (string) $oConfig->Get('defaults', 'view_editor_type', '');
- $aResult['UseCheckboxesInList'] = (bool) $oConfig->Get('defaults', 'view_use_checkboxes', true);
- $aResult['AutoLogout'] = (int) $oConfig->Get('defaults', 'autologout', 30);
- $aResult['UseThreads'] = (bool) $oConfig->Get('defaults', 'mail_use_threads', false);
- $aResult['AllowDraftAutosave'] = (bool) $oConfig->Get('defaults', 'allow_draft_autosave', true);
- $aResult['ReplySameFolder'] = (bool) $oConfig->Get('defaults', 'mail_reply_same_folder', false);
- $aResult['ContactsAutosave'] = (bool) $oConfig->Get('defaults', 'contacts_autosave', true);
- $aResult['EnableTwoFactor'] = false;
- $aResult['ParentEmail'] = '';
- $aResult['InterfaceAnimation'] = true;
- $aResult['UserBackgroundName'] = '';
- $aResult['UserBackgroundHash'] = '';
-
- if (!$bAdmin && $oAccount instanceof \RainLoop\Model\Account)
- {
- $aResult['ParentEmail'] = $oAccount->ParentEmail();
-
- $oSettingsLocal = $this->SettingsProvider(true)->Load($oAccount);
-
- if ($oSettingsLocal instanceof \RainLoop\Settings)
- {
-// if ($this->GetCapa(false, $bMobile, \RainLoop\Enumerations\Capa::FOLDERS, $oAccount))
-
- $aResult['SentFolder'] = (string) $oSettingsLocal->GetConf('SentFolder', '');
- $aResult['DraftFolder'] = (string) $oSettingsLocal->GetConf('DraftFolder', '');
- $aResult['SpamFolder'] = (string) $oSettingsLocal->GetConf('SpamFolder', '');
- $aResult['TrashFolder'] = (string) $oSettingsLocal->GetConf('TrashFolder', '');
- $aResult['ArchiveFolder'] = (string) $oSettingsLocal->GetConf('ArchiveFolder', '');
- $aResult['NullFolder'] = (string) $oSettingsLocal->GetConf('NullFolder', '');
- }
-
- if ($this->GetCapa(false, $bMobile, \RainLoop\Enumerations\Capa::SETTINGS, $oAccount))
- {
- if ($oSettings instanceof \RainLoop\Settings)
- {
- if ($oConfig->Get('webmail', 'allow_languages_on_settings', true))
- {
- $sLanguage = (string) $oSettings->GetConf('Language', $sLanguage);
- }
-
- $aResult['EditorDefaultType'] = (string) $oSettings->GetConf('EditorDefaultType', $aResult['EditorDefaultType']);
- $aResult['ShowImages'] = (bool) $oSettings->GetConf('ShowImages', $aResult['ShowImages']);
- $aResult['ContactsAutosave'] = (bool) $oSettings->GetConf('ContactsAutosave', $aResult['ContactsAutosave']);
- $aResult['MPP'] = (int) $oSettings->GetConf('MPP', $aResult['MPP']);
- $aResult['SoundNotification'] = (bool) $oSettings->GetConf('SoundNotification', $aResult['SoundNotification']);
- $aResult['DesktopNotifications'] = (bool) $oSettings->GetConf('DesktopNotifications', $aResult['DesktopNotifications']);
- $aResult['UseCheckboxesInList'] = (bool) $oSettings->GetConf('UseCheckboxesInList', $aResult['UseCheckboxesInList']);
- $aResult['AllowDraftAutosave'] = (bool) $oSettings->GetConf('AllowDraftAutosave', $aResult['AllowDraftAutosave']);
- $aResult['AutoLogout'] = (int) $oSettings->GetConf('AutoLogout', $aResult['AutoLogout']);
- $aResult['Layout'] = (int) $oSettings->GetConf('Layout', $aResult['Layout']);
-
- if (!$this->GetCapa(false, $bMobile, \RainLoop\Enumerations\Capa::AUTOLOGOUT, $oAccount))
- {
- $aResult['AutoLogout'] = 0;
- }
-
- if ($this->GetCapa(false, $bMobile, \RainLoop\Enumerations\Capa::USER_BACKGROUND, $oAccount))
- {
- $aResult['UserBackgroundName'] = (string) $oSettings->GetConf('UserBackgroundName', $aResult['UserBackgroundName']);
- $aResult['UserBackgroundHash'] = (string) $oSettings->GetConf('UserBackgroundHash', $aResult['UserBackgroundHash']);
-// if (!empty($aResult['UserBackgroundName']) && !empty($aResult['UserBackgroundHash']))
-// {
-// $aResult['IncludeBackground'] = './?/Raw/&q[]=/{{USER}}/UserBackground/&q[]=/'.
-// $aResult['UserBackgroundHash'].'/';
-// }
- }
-
- $aResult['EnableTwoFactor'] = (bool) $oSettings->GetConf('EnableTwoFactor', $aResult['EnableTwoFactor']);
- }
-
- if ($oSettingsLocal instanceof \RainLoop\Settings)
- {
- $aResult['UseThreads'] = (bool) $oSettingsLocal->GetConf('UseThreads', $aResult['UseThreads']);
- $aResult['ReplySameFolder'] = (bool) $oSettingsLocal->GetConf('ReplySameFolder', $aResult['ReplySameFolder']);
-
- if ($this->GetCapa(false, $bMobile, \RainLoop\Enumerations\Capa::THEMES, $oAccount))
- {
- $sTheme = (string) $oSettingsLocal->GetConf('Theme', $sTheme);
- }
- }
- }
- }
-
- if (!$aResult['Auth'])
- {
- if (!$bAdmin)
- {
- if ($oConfig->Get('login', 'allow_languages_on_login', true) &&
- $oConfig->Get('login', 'determine_user_language', true))
- {
- $sLanguage = $this->ValidateLanguage(
- $this->detectUserLanguage($bAdmin), $sLanguage, false);
- }
- }
- }
-
- $sTheme = $this->ValidateTheme($sTheme, $bMobile);
- $sStaticCache = $this->StaticCache();
-
- $aResult['Theme'] = $sTheme;
- $aResult['NewThemeLink'] = $this->ThemeLink($sTheme, $bAdmin);
-
- $aResult['Language'] = $this->ValidateLanguage($sLanguage, '', false);
- $aResult['LanguageAdmin'] = $this->ValidateLanguage($sLanguageAdmin, '', true);
-
- $aResult['UserLanguageRaw'] = $this->detectUserLanguage($bAdmin);
-
- $aResult['UserLanguage'] = $this->ValidateLanguage($aResult['UserLanguageRaw'], '', false, true);
- $aResult['UserLanguageAdmin'] = $this->ValidateLanguage($aResult['UserLanguageRaw'], '', true, true);
-
- $aResult['PluginsLink'] = '';
- if (0 < $this->Plugins()->Count() && $this->Plugins()->HaveJs($bAdmin))
- {
- $aResult['PluginsLink'] = './?/Plugins/0/'.($bAdmin ? 'Admin' : 'User').'/'.$sStaticCache.'/';
- }
-
- $aResult['LangLink'] = './?/Lang/0/'.($bAdmin ? 'Admin' : 'App').'/'.
- ($bAdmin ? $aResult['LanguageAdmin'] : $aResult['Language']).'/'.$sStaticCache.'/';
-
- $aResult['TemplatesLink'] = './?/Templates/0/'.($bAdmin ? 'Admin' : 'App').'/'.$sStaticCache.'/';
-
- $bAppJsDebug = !!$this->Config()->Get('labs', 'use_app_debug_js', false);
-
- $aResult['StaticLibJsLink'] = $this->StaticPath('js/'.($bAppJsDebug ? '' : 'min/').
- 'libs'.($bAppJsDebug ? '' : '.min').'.js');
- $aResult['StaticAppJsLink'] = $this->StaticPath('js/'.($bAppJsDebug ? '' : 'min/').
- ($bAdmin ? 'admin' : 'app').($bAppJsDebug ? '' : '.min').'.js');
-
- $aResult['StaticAppJsNextLink'] = $this->StaticPath('js/'.($bAdmin ? 'admin' : 'app').'.next.js');
- $aResult['StaticEditorJsLink'] = $this->StaticPath('ckeditor/ckeditor.js');
-
- $aResult['EditorDefaultType'] = \in_array($aResult['EditorDefaultType'], array('Plain', 'Html', 'HtmlForced', 'PlainForced')) ?
- $aResult['EditorDefaultType'] : 'Plain';
-
- // IDN
- $aResult['Email'] = \MailSo\Base\Utils::IdnToUtf8($aResult['Email']);
- $aResult['ParentEmail'] = \MailSo\Base\Utils::IdnToUtf8($aResult['ParentEmail']);
- $aResult['MailToEmail'] = \MailSo\Base\Utils::IdnToUtf8($aResult['MailToEmail']);
- $aResult['DevEmail'] = \MailSo\Base\Utils::IdnToUtf8($aResult['DevEmail']);
-
- // Mobile override
- if ($bMobile)
- {
- $aResult['Layout'] = \RainLoop\Enumerations\Layout::NO_PREVIW;
-
- $aResult['SoundNotification'] = false;
- $aResult['DesktopNotifications'] = false;
- $aResult['UseCheckboxesInList'] = true;
-
- $aResult['UserBackgroundName'] = '';
- $aResult['UserBackgroundHash'] = '';
- }
-
- $this->Plugins()->InitAppData($bAdmin, $aResult, $oAccount);
-
- return $aResult;
- }
-
- /**
- * @return array
- */
- private function getUserLanguagesFromHeader()
- {
- $aResult = $aList = array();
- $sAcceptLang = \strtolower($this->Http()->GetServer('HTTP_ACCEPT_LANGUAGE', 'en'));
- if (!empty($sAcceptLang) && \preg_match_all('/([a-z]{1,8}(?:-[a-z]{1,8})?)(?:;q=([0-9.]+))?/', $sAcceptLang, $aList))
- {
- $aResult = \array_combine($aList[1], $aList[2]);
- foreach ($aResult as $n => $v)
- {
- $aResult[$n] = $v ? $v : 1;
- }
-
- \arsort($aResult, SORT_NUMERIC);
- }
-
- return $aResult;
- }
-
- /**
- * @return string
- */
- public function detectUserLanguage($bAdmin = false)
- {
- $sResult = '';
- $aLangs = $this->getUserLanguagesFromHeader();
-
- foreach (\array_keys($aLangs) as $sLang)
- {
- $sLang = $this->ValidateLanguage($sLang, '', $bAdmin, true);
- if (!empty($sLang))
- {
- $sResult = $sLang;
- break;
- }
- }
-
- return $sResult;
- }
-
- /**
- * @param int $iWait = 1
- * @param int $iDelay = 1
- */
- private function requestSleep($iWait = 1, $iDelay = 1)
- {
- if (0 < $iDelay && 0 < $iWait)
- {
- if ($iWait > \time() - APP_START_TIME)
- {
- \sleep($iDelay);
- }
- }
- }
-
- private function loginErrorDelay()
- {
- $iDelay = (int) $this->Config()->Get('labs', 'login_fault_delay', 0);
- if (0 < $iDelay)
- {
- $this->requestSleep(1, $iDelay);
- }
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount
- */
- public function AuthToken($oAccount)
- {
- if ($oAccount instanceof \RainLoop\Model\Account)
- {
- $this->SetAuthToken($oAccount);
-
- $aAccounts = $this->GetAccounts($oAccount);
- if (\is_array($aAccounts) && isset($aAccounts[$oAccount->Email()]))
- {
- $aAccounts[$oAccount->Email()] = $oAccount->GetAuthToken();
- $this->SetAccounts($oAccount, $aAccounts);
- }
- }
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount
- * @param bool $bAuthLog = false
- *
- * @throws \RainLoop\Exceptions\ClientException
- */
- public function CheckMailConnection($oAccount, $bAuthLog = false)
- {
- try
- {
- $oAccount->IncConnectAndLoginHelper($this->Plugins(), $this->MailClient(), $this->Config());
- }
- catch (\RainLoop\Exceptions\ClientException $oException)
- {
- throw $oException;
- }
- catch (\MailSo\Net\Exceptions\ConnectionException $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::ConnectionError, $oException);
- }
- catch (\MailSo\Imap\Exceptions\LoginBadCredentialsException $oException)
- {
- if ($bAuthLog)
- {
- $this->LoggerAuthHelper($oAccount);
- }
-
- if ($this->Config()->Get('labs', 'imap_show_login_alert', true))
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError,
- $oException, $oException->getAlertFromStatus());
- }
- else
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError, $oException);
- }
- }
- catch (\Exception $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError, $oException);
- }
- }
-
- /**
- * @param string $sLogin
- * @param bool $bAdmin = false
- * @return array
- */
- private function getAdditionalLogParamsByUserLogin($sLogin, $bAdmin = false)
- {
- $sHost = $bAdmin ? $this->Http()->GetHost(false, true, true) : \MailSo\Base\Utils::GetDomainFromEmail($sLogin);
- return array(
- '{imap:login}' => $sLogin,
- '{imap:host}' => $sHost,
- '{smtp:login}' => $sLogin,
- '{smtp:host}' => $sHost,
- '{user:email}' => $sLogin,
- '{user:login}' => \MailSo\Base\Utils::GetAccountNameFromEmail($sLogin),
- '{user:domain}' => $sHost,
- );
- }
-
- /**
- * @param string $sEmail
- * @param string $sPassword
- * @param string $sSignMeToken = ''
- * @param string $sAdditionalCode = ''
- * @param string $bAdditionalCodeSignMe = false
- * @param string $bSkipTwoFactorAuth = false
- *
- * @return \RainLoop\Model\Account
- * @throws \RainLoop\Exceptions\ClientException
- */
- public function LoginProcess(&$sEmail, &$sPassword, $sSignMeToken = '',
- $sAdditionalCode = '', $bAdditionalCodeSignMe = false, $bSkipTwoFactorAuth = false)
- {
- $sInputEmail = $sEmail;
-
- $this->Plugins()->RunHook('filter.login-credentials.step-1', array(&$sEmail, &$sPassword));
-
- $sEmail = \MailSo\Base\Utils::Trim($sEmail);
- if ($this->Config()->Get('login', 'login_lowercase', true))
- {
- $sEmail = \MailSo\Base\Utils::StrToLowerIfAscii($sEmail);
- }
-
- if (false === \strpos($sEmail, '@'))
- {
- $this->Logger()->Write('The email address "'.$sEmail.'" is not complete', \MailSo\Log\Enumerations\Type::INFO, 'LOGIN');
-
- if (false === \strpos($sEmail, '@') && !!$this->Config()->Get('login', 'determine_user_domain', false))
- {
- $sUserHost = \trim($this->Http()->GetHost(false, true, true));
- $this->Logger()->Write('Determined user domain: '.$sUserHost, \MailSo\Log\Enumerations\Type::INFO, 'LOGIN');
-
- $bAdded = false;
-
- $iLimit = 14;
- $aDomainParts = \explode('.', $sUserHost);
-
- $oDomainProvider = $this->DomainProvider();
- while (0 < \count($aDomainParts) && 0 < $iLimit)
- {
- $sLine = \trim(\implode('.', $aDomainParts), '. ');
-
- $oDomain = $oDomainProvider->Load($sLine, false);
- if ($oDomain && $oDomain instanceof \RainLoop\Model\Domain)
- {
- $bAdded = true;
- $this->Logger()->Write('Check "'.$sLine.'": OK ('.$sEmail.' > '.$sEmail.'@'.$sLine.')',
- \MailSo\Log\Enumerations\Type::INFO, 'LOGIN');
-
- $sEmail = $sEmail.'@'.$sLine;
- break;
- }
- else
- {
- $this->Logger()->Write('Check "'.$sLine.'": NO', \MailSo\Log\Enumerations\Type::INFO, 'LOGIN');
- }
-
- \array_shift($aDomainParts);
- $iLimit--;
- }
-
- if (!$bAdded)
- {
- $sLine = $sUserHost;
- $oDomain = $oDomainProvider->Load($sLine, true);
- if ($oDomain && $oDomain instanceof \RainLoop\Model\Domain)
- {
- $bAdded = true;
- $this->Logger()->Write('Check "'.$sLine.'" with wildcard: OK ('.$sEmail.' > '.$sEmail.'@'.$sLine.')',
- \MailSo\Log\Enumerations\Type::INFO, 'LOGIN');
-
- $sEmail = $sEmail.'@'.$sLine;
- }
- else
- {
- $this->Logger()->Write('Check "'.$sLine.'" with wildcard: NO', \MailSo\Log\Enumerations\Type::INFO, 'LOGIN');
- }
- }
-
- if (!$bAdded)
- {
- $this->Logger()->Write('Domain was not found!', \MailSo\Log\Enumerations\Type::INFO, 'LOGIN');
- }
- }
-
- $sDefDomain = \trim($this->Config()->Get('login', 'default_domain', ''));
- if (false === \strpos($sEmail, '@') && 0 < \strlen($sDefDomain))
- {
- $this->Logger()->Write('Default domain "'.$sDefDomain.'" was used. ('.$sEmail.' > '.$sEmail.'@'.$sDefDomain.')',
- \MailSo\Log\Enumerations\Type::INFO, 'LOGIN');
-
- $sEmail = $sEmail.'@'.$sDefDomain;
- }
- }
-
- $this->Plugins()->RunHook('filter.login-credentials.step-2', array(&$sEmail, &$sPassword));
-
- if (false === \strpos($sEmail, '@') || 0 === \strlen($sPassword))
- {
- $this->loginErrorDelay();
-
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::InvalidInputArgument);
- }
-
- $this->Logger()->AddSecret($sPassword);
-
- $sLogin = $sEmail;
- if ($this->Config()->Get('login', 'login_lowercase', true))
- {
- $sLogin = \MailSo\Base\Utils::StrToLowerIfAscii($sLogin);
- }
-
- $this->Plugins()->RunHook('filter.login-credentials', array(&$sEmail, &$sLogin, &$sPassword));
-
- $this->Logger()->AddSecret($sPassword);
-
- $this->Plugins()->RunHook('event.login-pre-login-provide', array());
-
- $oAccount = null;
-
- try
- {
- $oAccount = $this->LoginProvide($sEmail, $sLogin, $sPassword, $sSignMeToken, true);
-
- if (!($oAccount instanceof \RainLoop\Model\Account))
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError);
- }
-
- $this->Plugins()->RunHook('event.login-post-login-provide', array(&$oAccount));
-
- if (!($oAccount instanceof \RainLoop\Model\Account))
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError);
- }
- }
- catch (\Exception $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'].\RainLoop\Utils::Fingerprint());
- $sSecretCookieHash = \RainLoop\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 \RainLoop\Exceptions\ClientException(\RainLoop\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 \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AccountTwoFactorAuthError);
- }
-
- if ($bAdditionalCodeSignMe)
- {
- \RainLoop\Utils::SetCookie(self::AUTH_TFA_SIGN_ME_TOKEN_KEY, $sSecretHash,
- \time() + 60 * 60 * 24 * 14);
- }
- }
- }
- }
- }
-
- try
- {
- $this->CheckMailConnection($oAccount, true);
- }
- catch (\Exception $oException)
- {
- $this->loginErrorDelay();
-
- throw $oException;
- }
-
- return $oAccount;
- }
-
- /**
- * @param string $sEmail
- *
- * @return string
- */
- private function generateSignMeToken($sEmail)
- {
- return \MailSo\Base\Utils::Md5Rand(APP_SALT.$sEmail);
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoLogin()
- {
- $sEmail = \MailSo\Base\Utils::Trim($this->GetActionParam('Email', ''));
- $sPassword = $this->GetActionParam('Password', '');
- $sLanguage = $this->GetActionParam('Language', '');
- $bSignMe = '1' === (string) $this->GetActionParam('SignMe', '0');
-
- $sAdditionalCode = $this->GetActionParam('AdditionalCode', '');
- $bAdditionalCodeSignMe = '1' === (string) $this->GetActionParam('AdditionalCodeSignMe', '0');
-
- $oAccount = null;
-
- $this->Logger()->AddSecret($sPassword);
-
- if ('sleep@sleep.dev' === $sEmail && 0 < \strlen($sPassword) &&
- \is_numeric($sPassword) && $this->Config()->Get('debug', 'enable', false) &&
- 0 < (int) $sPassword && 30 > (int) $sPassword
- )
- {
- \sleep((int) $sPassword);
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError);
- }
-
- try
- {
- $oAccount = $this->LoginProcess($sEmail, $sPassword,
- $bSignMe ? $this->generateSignMeToken($sEmail) : '',
- $sAdditionalCode, $bAdditionalCodeSignMe);
- }
- catch (\RainLoop\Exceptions\ClientException $oException)
- {
- if ($oException &&
- \RainLoop\Notifications::AccountTwoFactorAuthRequired === $oException->getCode())
- {
- return $this->DefaultResponse(__FUNCTION__, true, array(
- 'TwoFactorAuth' => true
- ));
- }
- else
- {
- throw $oException;
- }
- }
-
- $this->AuthToken($oAccount);
-
- if ($oAccount && 0 < \strlen($sLanguage))
- {
- $oSettings = $this->SettingsProvider()->Load($oAccount);
- if ($oSettings)
- {
- $sLanguage = $this->ValidateLanguage($sLanguage);
- $sCurrentLanguage = $oSettings->GetConf('Language', '');
-
- if ($sCurrentLanguage !== $sLanguage)
- {
- $oSettings->SetConf('Language', $sLanguage);
- $this->SettingsProvider()->Save($oAccount, $oSettings);
- }
- }
- }
-
- return $this->TrueResponse(__FUNCTION__);
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount
- *
- * @return array
- */
- public function GetAccounts($oAccount)
- {
- if ($this->GetCapa(false, false, \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS, $oAccount))
- {
- $sAccounts = $this->StorageProvider()->Get($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'accounts'
- );
-
- $aAccounts = array();
- if ('' !== $sAccounts && '{' === \substr($sAccounts, 0, 1))
- {
- $aAccounts = @\json_decode($sAccounts, true);
- }
-
- if (\is_array($aAccounts) && 0 < \count($aAccounts))
- {
- if (1 === \count($aAccounts))
- {
- $this->SetAccounts($oAccount, array());
-
- }
- else if (1 < \count($aAccounts))
- {
- $sOrder = $this->StorageProvider()->Get($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'accounts_identities_order'
- );
-
- $aOrder = empty($sOrder) ? array() : @\json_decode($sOrder, true);
- if (isset($aOrder['Accounts']) && \is_array($aOrder['Accounts']) &&
- 1 < \count($aOrder['Accounts']))
- {
- $aAccounts = \array_merge(\array_flip($aOrder['Accounts']), $aAccounts);
-
- $aAccounts = \array_filter($aAccounts, function ($sHash) {
- return 5 < \strlen($sHash);
- });
- }
- }
-
- return $aAccounts;
- }
- }
-
- $aAccounts = array();
- if (!$oAccount->IsAdditionalAccount())
- {
- $aAccounts[$oAccount->Email()] = $oAccount->GetAuthToken();
- }
-
- return $aAccounts;
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount
- *
- * @return array
- */
- public function GetTemplates($oAccount)
- {
- $aTemplates = array();
- if ($oAccount)
- {
- $aData = array();
-
- $sData = $this->StorageProvider(true)->Get($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'templates'
- );
-
- if ('' !== $sData && '[' === \substr($sData, 0, 1))
- {
- $aData = @\json_decode($sData, true);
- }
-
- if (\is_array($aData) && 0 < \count($aData))
- {
- foreach ($aData as $aItem)
- {
- $oItem = \RainLoop\Model\Template::NewInstance();
- $oItem->FromJSON($aItem);
-
- if ($oItem && $oItem->Validate())
- {
- \array_push($aTemplates, $oItem);
- }
- }
- }
-
- if (1 < \count($aTemplates))
- {
- $sOrder = $this->StorageProvider()->Get($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'templates_order'
- );
-
- $aOrder = empty($sOrder) ? array() : @\json_decode($sOrder, true);
- if (\is_array($aOrder) && 1 < \count($aOrder))
- {
- \usort($aTemplates, function ($a, $b) use ($aOrder) {
- return \array_search($a->Id(), $aOrder) < \array_search($b->Id(), $aOrder) ? -1 : 1;
- });
- }
- }
- }
-
- return $aTemplates;
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount
- * @param string $sID
- *
- * @return \RainLoop\Model\Identity
- */
- public function GetTemplateByID($oAccount, $sID)
- {
- $aTemplates = $this->GetTemplates($oAccount);
- if (\is_array($aTemplates))
- {
- foreach ($aTemplates as $oIdentity)
- {
- if ($oIdentity && $sID === $oIdentity->Id())
- {
- return $oIdentity;
- }
- }
- }
-
- return isset($aTemplates[0]) ? $aTemplates[0] : null;
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount
- *
- * @return array
- */
- public function GetIdentities($oAccount)
- {
- $bAllowIdentities = $this->GetCapa(false, false,
- \RainLoop\Enumerations\Capa::IDENTITIES, $oAccount);
-
- $aIdentities = array();
- if ($oAccount)
- {
- $aSubIdentities = array();
-
- $sData = $this->StorageProvider(true)->Get($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'identities'
- );
-
- if ('' !== $sData && '[' === \substr($sData, 0, 1))
- {
- $aSubIdentities = @\json_decode($sData, true);
- }
-
- $bHasAccountIdentity = false;
-
- if (\is_array($aSubIdentities) && 0 < \count($aSubIdentities))
- {
- foreach ($aSubIdentities as $aItem)
- {
- $oItem = \RainLoop\Model\Identity::NewInstance();
- $oItem->FromJSON($aItem);
-
- if ($oItem && $oItem->Validate())
- {
- if ($oItem->IsAccountIdentities())
- {
- $oItem->SetEmail($oAccount->Email());
- $bHasAccountIdentity = true;
-
- \array_push($aIdentities, $oItem);
- }
- else if ($bAllowIdentities)
- {
- \array_push($aIdentities, $oItem);
- }
- }
- }
- }
-
- if (!$bHasAccountIdentity)
- {
- \array_unshift($aIdentities,
- \RainLoop\Model\Identity::NewInstanceFromAccount($oAccount));
- }
-
- if (1 < \count($aIdentities) && $bAllowIdentities)
- {
- $sOrder = $this->StorageProvider()->Get($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'accounts_identities_order'
- );
-
- $aOrder = empty($sOrder) ? array() : @\json_decode($sOrder, true);
- if (isset($aOrder['Identities']) && \is_array($aOrder['Identities']) &&
- 1 < \count($aOrder['Identities']))
- {
- $aList = $aOrder['Identities'];
- foreach ($aList as $iIndex => $sItem)
- {
- if ('' === $sItem)
- {
- $aList[$iIndex] = '---';
- }
- }
-
- \usort($aIdentities, function ($a, $b) use ($aList) {
- return \array_search($a->Id(true), $aList) < \array_search($b->Id(true), $aList) ? -1 : 1;
- });
- }
- }
- }
-
- return $aIdentities;
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount
- * @param string $sID
- * @param bool $bFirstOnEmpty = false
- *
- * @return \RainLoop\Model\Identity
- */
- public function GetIdentityByID($oAccount, $sID, $bFirstOnEmpty = false)
- {
- $aIdentities = $this->GetIdentities($oAccount);
-
- if (\is_array($aIdentities))
- {
- foreach ($aIdentities as $oIdentity)
- {
- if ($oIdentity && $sID === $oIdentity->Id())
- {
- return $oIdentity;
- }
- }
- }
-
- return $bFirstOnEmpty && \is_array($aIdentities) && isset($aIdentities[0]) ? $aIdentities[0] : null;
- }
- /**
- * @param \RainLoop\Model\Account $oAccount
- *
- * @return \RainLoop\Model\Identity
- */
- public function GetAccountIdentity($oAccount)
- {
- return $this->GetIdentityByID($oAccount, '', true);
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount
- * @param array $aAccounts = array()
- *
- * @return array
- */
- public function SetAccounts($oAccount, $aAccounts = array())
- {
- $sParentEmail = $oAccount->ParentEmailHelper();
- if (!\is_array($aAccounts) || 0 >= \count($aAccounts) ||
- (1 === \count($aAccounts) && !empty($aAccounts[$sParentEmail])))
- {
- $this->StorageProvider()->Clear($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'accounts'
- );
- }
- else
- {
- $this->StorageProvider()->Put($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'accounts',
- @\json_encode($aAccounts)
- );
- }
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount
- * @param array $aIdentities = array()
- *
- * @return array
- */
- public function SetIdentities($oAccount, $aIdentities = array())
- {
- $bAllowIdentities = $this->GetCapa(false, false, \RainLoop\Enumerations\Capa::IDENTITIES, $oAccount);
-
- $aResult = array();
- foreach ($aIdentities as $oItem)
- {
- if (!$bAllowIdentities && $oItem && !$oItem->IsAccountIdentities())
- {
- continue;
- }
-
- $aResult[] = $oItem->ToSimpleJSON(false);
- }
-
- return $this->StorageProvider(true)->Put($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'identities',
- @\json_encode($aResult)
- );
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount
- * @param array $aTemplates = array()
- *
- * @return array
- */
- public function SetTemplates($oAccount, $aTemplates = array())
- {
- $aResult = array();
- foreach ($aTemplates as $oItem)
- {
- $aResult[] = $oItem->ToSimpleJSON(false);
- }
-
- return $this->StorageProvider(true)->Put($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'templates',
- @\json_encode($aResult)
- );
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoFilters()
- {
- $oAccount = $this->getAccountFromToken();
-
- if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::FILTERS, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $aFakeFilters = null;
-
- $this->Plugins()
- ->RunHook('filter.filters-fake', array($oAccount, &$aFakeFilters))
- ;
-
- if ($aFakeFilters)
- {
- return $this->DefaultResponse(__FUNCTION__, $aFakeFilters);
- }
-
- return $this->DefaultResponse(__FUNCTION__,
- $this->FiltersProvider()->Load($oAccount, $oAccount->DomainSieveAllowRaw()));
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoFiltersSave()
- {
- $oAccount = $this->getAccountFromToken();
-
- if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::FILTERS, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $aIncFilters = $this->GetActionParam('Filters', array());
-
- $sRaw = $this->GetActionParam('Raw', '');
- $bRawIsActive = '1' === (string) $this->GetActionParam('RawIsActive', '0');
-
- $aFilters = array();
- foreach ($aIncFilters as $aFilter)
- {
- if ($aFilter)
- {
- $oFilter = new \RainLoop\Providers\Filters\Classes\Filter();
- if ($oFilter->FromJSON($aFilter))
- {
- $aFilters[] = $oFilter;
- }
- }
- }
-
- $this->Plugins()
- ->RunHook('filter.filters-save', array($oAccount, &$aFilters, &$sRaw, &$bRawIsActive))
- ;
-
- return $this->DefaultResponse(__FUNCTION__, $this->FiltersProvider()->Save($oAccount,
- $aFilters, $sRaw, $bRawIsActive));
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoAccountSetup()
- {
- $oAccount = $this->getAccountFromToken();
-
- if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $sParentEmail = $oAccount->ParentEmailHelper();
-
- $aAccounts = $this->GetAccounts($oAccount);
- if (!\is_array($aAccounts))
- {
- $aAccounts = array();
- }
-
- $sEmail = \trim($this->GetActionParam('Email', ''));
- $sPassword = $this->GetActionParam('Password', '');
- $bNew = '1' === (string) $this->GetActionParam('New', '1');
-
- $sEmail = \MailSo\Base\Utils::IdnToAscii($sEmail, true);
- if ($bNew && ($oAccount->Email() === $sEmail || $sParentEmail === $sEmail || isset($aAccounts[$sEmail])))
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AccountAlreadyExists);
- }
- else if (!$bNew && !isset($aAccounts[$sEmail]))
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AccountDoesNotExist);
- }
-
- $oNewAccount = $this->LoginProcess($sEmail, $sPassword, '', '', false, true);
- $oNewAccount->SetParentEmail($sParentEmail);
-
- $aAccounts[$oNewAccount->Email()] = $oNewAccount->GetAuthToken();
- if (!$oAccount->IsAdditionalAccount())
- {
- $aAccounts[$oAccount->Email()] = $oAccount->GetAuthToken();
- }
-
- $this->SetAccounts($oAccount, $aAccounts);
- return $this->TrueResponse(__FUNCTION__);
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoAccountDelete()
- {
- $oAccount = $this->getAccountFromToken();
-
- if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $sParentEmail = $oAccount->ParentEmailHelper();
- $sEmailToDelete = \trim($this->GetActionParam('EmailToDelete', ''));
- $sEmailToDelete = \MailSo\Base\Utils::IdnToAscii($sEmailToDelete, true);
-
- $aAccounts = $this->GetAccounts($oAccount);
-
- if (0 < \strlen($sEmailToDelete) && $sEmailToDelete !== $sParentEmail && \is_array($aAccounts) && isset($aAccounts[$sEmailToDelete]))
- {
- unset($aAccounts[$sEmailToDelete]);
-
- $oAccountToChange = null;
- if ($oAccount->Email() === $sEmailToDelete && !empty($aAccounts[$sParentEmail]))
- {
- $oAccountToChange = $this->GetAccountFromCustomToken($aAccounts[$sParentEmail], false, false);
- if ($oAccountToChange)
- {
- $this->AuthToken($oAccountToChange);
- }
- }
-
- $this->SetAccounts($oAccount, $aAccounts);
- return $this->TrueResponse(__FUNCTION__, array('Reload' => !!$oAccountToChange));
- }
-
- return $this->FalseResponse(__FUNCTION__);
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoAttachmentsActions()
- {
- if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::ATTACHMENTS_ACTIONS))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $oAccount = $this->initMailClientConnection();
-
- $sAction = $this->GetActionParam('Do', '');
- $aHashes = $this->GetActionParam('Hashes', null);
-
- $mResult = false;
- $bError = false;
- $aData = false;
-
- if (\is_array($aHashes) && 0 < \count($aHashes))
- {
- $aData = array();
- foreach ($aHashes as $sZipHash)
- {
- $aResult = $this->getMimeFileByHash($oAccount, $sZipHash);
- if (\is_array($aResult) && !empty($aResult['FileHash']))
- {
- $aData[] = $aResult;
- }
- else
- {
- $bError = true;
- break;
- }
- }
- }
-
- $oFilesProvider = $this->FilesProvider();
- if (!empty($sAction) && !$bError && \is_array($aData) && 0 < \count($aData) &&
- $oFilesProvider && $oFilesProvider->IsActive())
- {
- $bError = false;
- switch (\strtolower($sAction))
- {
- case 'zip':
-
- if (\class_exists('ZipArchive'))
- {
- $sZipHash = \MailSo\Base\Utils::Md5Rand();
- $sZipFileName = $oFilesProvider->GenerateLocalFullFileName($oAccount, $sZipHash);
-
- if (!empty($sZipFileName))
- {
- $oZip = new \ZipArchive();
- $oZip->open($sZipFileName, \ZIPARCHIVE::CREATE | \ZIPARCHIVE::OVERWRITE);
- $oZip->setArchiveComment('RainLoop/'.APP_VERSION);
-
- foreach ($aData as $aItem)
- {
- $sFileName = (string) (isset($aItem['FileName']) ? $aItem['FileName'] : 'file.dat');
- $sFileHash = (string) (isset($aItem['FileHash']) ? $aItem['FileHash'] : '');
-
- if (!empty($sFileHash))
- {
- $sFullFileNameHash = $oFilesProvider->GetFileName($oAccount, $sFileHash);
- if (!$oZip->addFile($sFullFileNameHash, $sFileName))
- {
- $bError = true;
- }
- }
- }
-
- if (!$bError)
- {
- $bError = !$oZip->close();
- }
- else
- {
- $oZip->close();
- }
- }
-
- foreach ($aData as $aItem)
- {
- $sFileHash = (string) (isset($aItem['FileHash']) ? $aItem['FileHash'] : '');
- if (!empty($sFileHash))
- {
- $oFilesProvider->Clear($oAccount, $sFileHash);
- }
- }
-
- if (!$bError)
- {
- $mResult = array(
- 'Files' => array(array(
- 'FileName' => 'attachments.zip',
- 'Hash' => \RainLoop\Utils::EncodeKeyValuesQ(array(
- 'V' => APP_VERSION,
- 'Account' => $oAccount ? \md5($oAccount->Hash()) : '',
- 'FileName' => 'attachments.zip',
- 'MimeType' => 'application/zip',
- 'FileHash' => $sZipHash
- ))
- ))
- );
- }
- }
- break;
-
- case 'owncloud':
-
- $mResult = false;
-
- if (\RainLoop\Utils::IsOwnCloudLoggedIn() && \class_exists('OCP\Files'))
- {
- $sSaveFolder = $this->Config()->Get('labs', 'owncloud_save_folder', '');
- if (empty($sSaveFolder))
- {
- $sSaveFolder = 'Attachments';
- }
-
- $oFiles = \OCP\Files::getStorage('files');
-
- if ($oFilesProvider && $oFiles && $oFilesProvider->IsActive() &&
- \method_exists($oFiles, 'file_put_contents'))
- {
- if (!$oFiles->is_dir($sSaveFolder))
- {
- $oFiles->mkdir($sSaveFolder);
- }
-
- $mResult = true;
- foreach ($aData as $aItem)
- {
- $sSavedFileName = isset($aItem['FileName']) ? $aItem['FileName'] : 'file.dat';
- $sSavedFileHash = !empty($aItem['FileHash']) ? $aItem['FileHash'] : '';
-
- if (!empty($sSavedFileHash))
- {
- $fFile = $oFilesProvider->GetFile($oAccount, $sSavedFileHash, 'rb');
- if (\is_resource($fFile))
- {
- $sSavedFileNameFull = \MailSo\Base\Utils::SmartFileExists($sSaveFolder.'/'.$sSavedFileName, function ($sPath) use ($oFiles) {
- return $oFiles->file_exists($sPath);
- });
-
- if (!$oFiles->file_put_contents($sSavedFileNameFull, $fFile))
- {
- $mResult = false;
- }
-
- if (\is_resource($fFile))
- {
- @\fclose($fFile);
- }
- }
- }
- }
- }
- }
-
- foreach ($aData as $aItem)
- {
- $sFileHash = (string) (isset($aItem['FileHash']) ? $aItem['FileHash'] : '');
- if (!empty($sFileHash))
- {
- $oFilesProvider->Clear($oAccount, $sFileHash);
- }
- }
-
- break;
-
- case 'dropbox':
-
- $mResult = array(
- 'ShortLife' => '_'.$this->GetShortLifeSpecAuthToken(),
- 'Url' => \preg_replace('/\?(.*)$/', '', $this->Http()->GetFullUrl()),
- 'Files' => array()
- );
-
- foreach ($aData as $aItem)
- {
- $mResult['Files'][] = array(
- 'FileName' => isset($aItem['FileName']) ? $aItem['FileName'] : 'file.dat',
- 'Hash' => \RainLoop\Utils::EncodeKeyValuesQ($aItem)
- );
- }
-
- break;
- }
- }
- else
- {
- $bError = true;
- }
-
- $this->requestSleep();
- return $this->DefaultResponse(__FUNCTION__, $bError ? false : $mResult);
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoIdentityUpdate()
- {
- $oAccount = $this->getAccountFromToken();
-
- $oIdentity = \RainLoop\Model\Identity::NewInstance();
- if (!$oIdentity->FromJSON($this->GetActionParams(), true))
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::InvalidInputArgument);
- }
-
- $aIdentities = $this->GetIdentities($oAccount);
-
- $bAdded = false;
- $aIdentitiesForSave = array();
- foreach ($aIdentities as $oItem)
- {
- if ($oItem)
- {
- if ($oItem->Id() === $oIdentity->Id())
- {
- $aIdentitiesForSave[] = $oIdentity;
- $bAdded = true;
- }
- else
- {
- $aIdentitiesForSave[] = $oItem;
- }
- }
- }
-
- if (!$bAdded)
- {
- $aIdentitiesForSave[] = $oIdentity;
- }
-
- return $this->DefaultResponse(__FUNCTION__, $this->SetIdentities($oAccount, $aIdentitiesForSave));
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoIdentityDelete()
- {
- $oAccount = $this->getAccountFromToken();
-
- if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::IDENTITIES, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $sId = \trim($this->GetActionParam('IdToDelete', ''));
- if (empty($sId))
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::UnknownError);
- }
-
- $aNew = array();
- $aIdentities = $this->GetIdentities($oAccount);
-
- foreach ($aIdentities as $oItem)
- {
- if ($oItem && $sId !== $oItem->Id())
- {
- $aNew[] = $oItem;
- }
- }
-
- return $this->DefaultResponse(__FUNCTION__, $this->SetIdentities($oAccount, $aNew));
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoTemplateSetup()
- {
- $oAccount = $this->getAccountFromToken();
-
- if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::TEMPLATES, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $oTemplate = \RainLoop\Model\Template::NewInstance();
- if (!$oTemplate->FromJSON($this->GetActionParams(), true))
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::InvalidInputArgument);
- }
-
- if ('' === $oTemplate->Id())
- {
- $oTemplate->GenerateID();
- }
-
- $aTemplatesForSave = array();
- $aTemplates = $this->GetTemplates($oAccount);
-
-
- foreach ($aTemplates as $oItem)
- {
- if ($oItem && $oItem->Id() !== $oTemplate->Id())
- {
- $aTemplatesForSave[] = $oItem;
- }
- }
-
- $aTemplatesForSave[] = $oTemplate;
-
- return $this->DefaultResponse(__FUNCTION__, $this->SetTemplates($oAccount, $aTemplatesForSave));
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoTemplateDelete()
- {
- $oAccount = $this->getAccountFromToken();
-
- if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::TEMPLATES, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $sId = \trim($this->GetActionParam('IdToDelete', ''));
- if (empty($sId))
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::UnknownError);
- }
-
- $aNew = array();
- $aTemplates = $this->GetTemplates($oAccount);
- foreach ($aTemplates as $oItem)
- {
- if ($oItem && $sId !== $oItem->Id())
- {
- $aNew[] = $oItem;
- }
- }
-
- return $this->DefaultResponse(__FUNCTION__, $this->SetTemplates($oAccount, $aNew));
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoTemplateGetByID()
- {
- $oAccount = $this->getAccountFromToken();
-
- if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::TEMPLATES, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $sId = \trim($this->GetActionParam('ID', ''));
- if (empty($sId))
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::UnknownError);
- }
-
- $oTemplate = false;
- $aTemplates = $this->GetTemplates($oAccount);
-
- foreach ($aTemplates as $oItem)
- {
- if ($oItem && $sId === $oItem->Id())
- {
- $oTemplate = $oItem;
- break;
- }
- }
-
- $oTemplate->SetPopulateAlways(true);
- return $this->DefaultResponse(__FUNCTION__, $oTemplate);
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoAccountsAndIdentitiesSortOrder()
- {
- $oAccount = $this->getAccountFromToken();
-
- $aAccounts = $this->GetActionParam('Accounts', null);
- $aIdentities = $this->GetActionParam('Identities', null);
-
- if (!\is_array($aAccounts) && !\is_array($aIdentities))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- return $this->DefaultResponse(__FUNCTION__, $this->StorageProvider()->Put($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG, 'accounts_identities_order',
- \json_encode(array(
- 'Accounts' => \is_array($aAccounts) ? $aAccounts : array(),
- 'Identities' => \is_array($aIdentities) ? $aIdentities : array()
- ))
- ));
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoAccountsAndIdentities()
- {
- $oAccount = $this->getAccountFromToken();
-
- $mAccounts = false;
-
- if ($this->GetCapa(false, false, \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS, $oAccount))
- {
- $mAccounts = $this->GetAccounts($oAccount);
- $mAccounts = \array_keys($mAccounts);
-
- foreach ($mAccounts as $iIndex => $sName)
- {
- $mAccounts[$iIndex] = \MailSo\Base\Utils::IdnToUtf8($sName);
- }
- }
-
- return $this->DefaultResponse(__FUNCTION__, array(
- 'Accounts' => $mAccounts,
- 'Identities' => $this->GetIdentities($oAccount)
- ));
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoTemplates()
- {
- $oAccount = $this->getAccountFromToken();
-
- if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::TEMPLATES, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- return $this->DefaultResponse(__FUNCTION__, array(
- 'Templates' => $this->GetTemplates($oAccount)
- ));
- }
-
- /**
- * @param string $sHash
- *
- * @return int
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function getAccountUnredCountFromHash($sHash)
- {
- $iResult = 0;
-
- $oAccount = $this->GetAccountFromCustomToken($sHash, false);
- if ($oAccount)
- {
- try
- {
- $oMailClient = \MailSo\Mail\MailClient::NewInstance();
- $oMailClient->SetLogger($this->Logger());
-
- $oAccount->IncConnectAndLoginHelper($this->Plugins(),$oMailClient, $this->Config());
-
- $iResult = $oMailClient->InboxUnreadCount();
-
- $oMailClient->LogoutAndDisconnect();
- }
- catch (\Exception $oException)
- {
- $this->Logger()->WriteException($oException);
- }
- }
-
- return $iResult;
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoAccountsCounts()
- {
- $oAccount = $this->getAccountFromToken();
-
- $bComplete = true;
- $aCounts = array();
-
- if ($this->GetCapa(false, false, \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS, $oAccount))
- {
- $iLimit = 7;
- $mAccounts = $this->GetAccounts($oAccount);
- if (\is_array($mAccounts) && 0 < \count($mAccounts))
- {
- if ($iLimit > \count($mAccounts))
- {
- $mAccounts = \array_slice($mAccounts, 0, $iLimit);
- }
- else
- {
- $bComplete = false;
- }
-
- if (0 < \count($mAccounts))
- {
- foreach ($mAccounts as $sEmail => $sHash)
- {
- $aCounts[] = array(\MailSo\Base\Utils::IdnToUtf8($sEmail),
- $oAccount->Email() === $sEmail ? 0 : $this->getAccountUnredCountFromHash($sHash));
- }
- }
- }
- }
- else
- {
- $aCounts[] = array(\MailSo\Base\Utils::IdnToUtf8($oAccount->Email()), 0);
- }
-
- return $this->DefaultResponse(__FUNCTION__, array(
- 'Complete' => $bComplete,
- 'Counts' => $aCounts
- ));
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount
- */
- public function ClearSignMeData($oAccount)
- {
- if ($oAccount)
- {
- \RainLoop\Utils::ClearCookie(\RainLoop\Actions::AUTH_SIGN_ME_TOKEN_KEY);
-
- $this->StorageProvider()->Clear($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'sign_me'
- );
- }
- }
-
- /**
- * @return array
- */
- public function DoLogout()
- {
- $oAccount = $this->getAccountFromToken(false);
- if ($oAccount)
- {
- if ($oAccount->SignMe())
- {
- $this->ClearSignMeData($oAccount);
- }
-
- if (!$oAccount->IsAdditionalAccount())
- {
- \RainLoop\Utils::ClearCookie(\RainLoop\Actions::AUTH_SPEC_TOKEN_KEY);
- }
- }
-
- return $this->TrueResponse(__FUNCTION__);
- }
-
- /**
- * @return array
- */
- public function DoAppDelayStart()
- {
- $this->Plugins()->RunHook('service.app-delay-start-begin');
-
- \RainLoop\Utils::UpdateConnectionToken();
-
- $bMainCache = false;
- $bFilesCache = false;
- $bVersionsCache = false;
-
- $iOneDay1 = 60 * 60 * 23;
- $iOneDay2 = 60 * 60 * 25;
- $iOneDay3 = 60 * 60 * 30;
-
- $sTimers = $this->StorageProvider()->Get(null,
- \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, 'Cache/Timers', '');
-
- $aTimers = \explode(',', $sTimers);
-
- $iMainCacheTime = !empty($aTimers[0]) && \is_numeric($aTimers[0]) ? (int) $aTimers[0] : 0;
- $iFilesCacheTime = !empty($aTimers[1]) && \is_numeric($aTimers[1]) ? (int) $aTimers[1] : 0;
- $iVersionsCacheTime = !empty($aTimers[2]) && \is_numeric($aTimers[2]) ? (int) $aTimers[2] : 0;
-
- if (0 === $iMainCacheTime || $iMainCacheTime + $iOneDay1 < \time())
- {
- $bMainCache = true;
- $iMainCacheTime = \time();
- }
-
- if (0 === $iFilesCacheTime || $iFilesCacheTime + $iOneDay2 < \time())
- {
- $bFilesCache = true;
- $iFilesCacheTime = \time();
- }
-
- if (0 === $iVersionsCacheTime || $iVersionsCacheTime + $iOneDay3 < \time())
- {
- $bVersionsCache = true;
- $iVersionsCacheTime = \time();
- }
-
- if ($bMainCache || $bFilesCache || $bVersionsCache)
- {
- if (!$this->StorageProvider()->Put(null,
- \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, 'Cache/Timers',
- \implode(',', array($iMainCacheTime, $iFilesCacheTime, $iVersionsCacheTime))))
- {
- $bMainCache = $bFilesCache = $bVersionsCache = false;
- }
- }
-
- if ($bMainCache)
- {
- $this->Logger()->Write('Cacher GC: Begin');
- $this->Cacher()->GC(48);
- $this->Logger()->Write('Cacher GC: End');
- }
- else if ($bFilesCache)
- {
- $this->Logger()->Write('Files GC: Begin');
- $this->FilesProvider()->GC(48);
- $this->Logger()->Write('Files GC: End');
- }
- else if ($bVersionsCache)
- {
- $oPremProvider = $this->PremProvider();
- if ($oPremProvider)
- {
- $oPremProvider->ClearOldVersion();
- }
- }
-
- $this->Plugins()->RunHook('service.app-delay-start-end');
-
- return $this->TrueResponse(__FUNCTION__);
- }
-
- /**
- * @return array
- */
- public function DoSystemFoldersUpdate()
- {
- $oAccount = $this->getAccountFromToken();
-
- $oSettingsLocal = $this->SettingsProvider(true)->Load($oAccount);
-
- $oSettingsLocal->SetConf('SentFolder', $this->GetActionParam('SentFolder', ''));
- $oSettingsLocal->SetConf('DraftFolder', $this->GetActionParam('DraftFolder', ''));
- $oSettingsLocal->SetConf('SpamFolder', $this->GetActionParam('SpamFolder', ''));
- $oSettingsLocal->SetConf('TrashFolder', $this->GetActionParam('TrashFolder', ''));
- $oSettingsLocal->SetConf('ArchiveFolder', $this->GetActionParam('ArchiveFolder', ''));
- $oSettingsLocal->SetConf('NullFolder', $this->GetActionParam('NullFolder', ''));
-
- return $this->DefaultResponse(__FUNCTION__,
- $this->SettingsProvider(true)->Save($oAccount, $oSettingsLocal));
- }
-
- /**
- * @param \RainLoop\Config\Application $oConfig
- * @param string $sParamName
- * @param string $sConfigSector
- * @param string $sConfigName
- * @param string $sType = 'string'
- * @param callable|null $mStringCallback = null
- */
- public function setConfigFromParams(&$oConfig, $sParamName, $sConfigSector, $sConfigName, $sType = 'string', $mStringCallback = null)
- {
- $sValue = $this->GetActionParam($sParamName, '');
- if ($this->HasActionParam($sParamName))
- {
- switch ($sType)
- {
- default:
- case 'string':
- $sValue = (string) $sValue;
- if ($mStringCallback && is_callable($mStringCallback))
- {
- $sValue = call_user_func($mStringCallback, $sValue);
- }
-
- $oConfig->Set($sConfigSector, $sConfigName, (string) $sValue);
- break;
-
- case 'dummy':
- $sValue = (string) $this->GetActionParam('ContactsPdoPassword', APP_DUMMY);
- if (APP_DUMMY !== $sValue)
- {
- $oConfig->Set($sConfigSector, $sConfigName, (string) $sValue);
- }
- break;
-
- case 'int':
- $iValue = (int) $sValue;
- $oConfig->Set($sConfigSector, $sConfigName, $iValue);
- break;
-
- case 'bool':
- $oConfig->Set($sConfigSector, $sConfigName, '1' === (string) $sValue);
- break;
- }
- }
- }
-
- /**
- * @param \RainLoop\Config\Application $oConfig
- * @param string $sParamName
- * @param string $sCapa
- */
- private function setCapaFromParams(&$oConfig, $sParamName, $sCapa)
- {
- switch ($sCapa)
- {
- case \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS:
- $this->setConfigFromParams($oConfig, $sParamName, 'webmail', 'allow_additional_accounts', 'bool');
- break;
- case \RainLoop\Enumerations\Capa::IDENTITIES:
- $this->setConfigFromParams($oConfig, $sParamName, 'webmail', 'allow_additional_identities', 'bool');
- break;
- case \RainLoop\Enumerations\Capa::TEMPLATES:
- $this->setConfigFromParams($oConfig, $sParamName, 'capa', 'x-templates', 'bool');
- break;
- case \RainLoop\Enumerations\Capa::TWO_FACTOR:
- $this->setConfigFromParams($oConfig, $sParamName, 'security', 'allow_two_factor_auth', 'bool');
- break;
- case \RainLoop\Enumerations\Capa::TWO_FACTOR_FORCE:
- $this->setConfigFromParams($oConfig, $sParamName, 'security', 'force_two_factor_auth', 'bool');
- break;
- case \RainLoop\Enumerations\Capa::GRAVATAR:
- $this->setConfigFromParams($oConfig, $sParamName, 'labs', 'allow_gravatar', 'bool');
- break;
- case \RainLoop\Enumerations\Capa::ATTACHMENT_THUMBNAILS:
- $this->setConfigFromParams($oConfig, $sParamName, 'interface', 'show_attachment_thumbnail', 'bool');
- break;
- case \RainLoop\Enumerations\Capa::THEMES:
- $this->setConfigFromParams($oConfig, $sParamName, 'webmail', 'allow_themes', 'bool');
- break;
- case \RainLoop\Enumerations\Capa::USER_BACKGROUND:
- $this->setConfigFromParams($oConfig, $sParamName, 'webmail', 'allow_user_background', 'bool');
- break;
- case \RainLoop\Enumerations\Capa::OPEN_PGP:
- $this->setConfigFromParams($oConfig, $sParamName, 'security', 'openpgp', 'bool');
- break;
- }
- }
-
- /**
- * @param \RainLoop\Settings $oSettings
- * @param string $sConfigName
- * @param string $sType = 'string'
- * @param callable|null $mStringCallback = null
- */
- private function setSettingsFromParams(&$oSettings, $sConfigName, $sType = 'string', $mStringCallback = null)
- {
- if ($this->HasActionParam($sConfigName))
- {
- $sValue = $this->GetActionParam($sConfigName, '');
- switch ($sType)
- {
- default:
- case 'string':
- $sValue = (string) $sValue;
- if ($mStringCallback && is_callable($mStringCallback))
- {
- $sValue = call_user_func($mStringCallback, $sValue);
- }
-
- $oSettings->SetConf($sConfigName, (string) $sValue);
- break;
-
- case 'int':
- $iValue = (int) $sValue;
- $oSettings->SetConf($sConfigName, $iValue);
- break;
-
- case 'bool':
- $oSettings->SetConf($sConfigName, '1' === (string) $sValue);
- break;
- }
- }
- }
-
- /**
- * @return array
- */
- public function DoAdminSettingsUpdate()
- {
-// sleep(3);
-// return $this->DefaultResponse(__FUNCTION__, false);
-
- $this->IsAdminLoggined();
-
- $oConfig = $this->Config();
-
- $self = $this;
-
- $this->setConfigFromParams($oConfig, 'Language', 'webmail', 'language', 'string', function ($sLanguage) use ($self) {
- return $self->ValidateLanguage($sLanguage, '', false);
- });
-
- $this->setConfigFromParams($oConfig, 'LanguageAdmin', 'webmail', 'language_admin', 'string', function ($sLanguage) use ($self) {
- return $self->ValidateLanguage($sLanguage, '', true);
- });
-
- $this->setConfigFromParams($oConfig, 'Theme', 'webmail', 'theme', 'string', function ($sTheme) use ($self) {
- return $self->ValidateTheme($sTheme);
- });
-
- $this->setConfigFromParams($oConfig, 'VerifySslCertificate', 'ssl', 'verify_certificate', 'bool');
- $this->setConfigFromParams($oConfig, 'AllowSelfSigned', 'ssl', 'allow_self_signed', 'bool');
-
- $this->setConfigFromParams($oConfig, 'UseLocalProxyForExternalImages', 'labs', 'use_local_proxy_for_external_images', 'bool');
-
- $this->setConfigFromParams($oConfig, 'NewMoveToFolder', 'interface', 'new_move_to_folder_button', 'bool');
-
- $this->setConfigFromParams($oConfig, 'AllowLanguagesOnSettings', 'webmail', 'allow_languages_on_settings', 'bool');
- $this->setConfigFromParams($oConfig, 'AllowLanguagesOnLogin', 'login', 'allow_languages_on_login', 'bool');
- $this->setConfigFromParams($oConfig, 'AttachmentLimit', 'webmail', 'attachment_size_limit', 'int');
-
- $this->setConfigFromParams($oConfig, 'LoginDefaultDomain', 'login', 'default_domain', 'string');
-
- $this->setConfigFromParams($oConfig, 'ContactsEnable', 'contacts', 'enable', 'bool');
- $this->setConfigFromParams($oConfig, 'ContactsSync', 'contacts', 'allow_sync', 'bool');
- $this->setConfigFromParams($oConfig, 'ContactsPdoDsn', 'contacts', 'pdo_dsn', 'string');
- $this->setConfigFromParams($oConfig, 'ContactsPdoUser', 'contacts', 'pdo_user', 'string');
- $this->setConfigFromParams($oConfig, 'ContactsPdoPassword', 'contacts', 'pdo_password', 'dummy');
-
- $this->setConfigFromParams($oConfig, 'ContactsPdoType', 'contacts', 'type', 'string', function ($sType) use ($self) {
- return $self->ValidateContactPdoType($sType);
- });
-
- $this->setCapaFromParams($oConfig, 'CapaAdditionalAccounts', \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS);
- $this->setCapaFromParams($oConfig, 'CapaIdentities', \RainLoop\Enumerations\Capa::IDENTITIES);
- $this->setCapaFromParams($oConfig, 'CapaTemplates', \RainLoop\Enumerations\Capa::TEMPLATES);
- $this->setCapaFromParams($oConfig, 'CapaTwoFactorAuth', \RainLoop\Enumerations\Capa::TWO_FACTOR);
- $this->setCapaFromParams($oConfig, 'CapaTwoFactorAuthForce', \RainLoop\Enumerations\Capa::TWO_FACTOR_FORCE);
- $this->setCapaFromParams($oConfig, 'CapaOpenPGP', \RainLoop\Enumerations\Capa::OPEN_PGP);
- $this->setCapaFromParams($oConfig, 'CapaGravatar', \RainLoop\Enumerations\Capa::GRAVATAR);
- $this->setCapaFromParams($oConfig, 'CapaThemes', \RainLoop\Enumerations\Capa::THEMES);
- $this->setCapaFromParams($oConfig, 'CapaUserBackground', \RainLoop\Enumerations\Capa::USER_BACKGROUND);
- $this->setCapaFromParams($oConfig, 'CapaAttachmentThumbnails', \RainLoop\Enumerations\Capa::ATTACHMENT_THUMBNAILS);
-
- $this->setConfigFromParams($oConfig, 'DetermineUserLanguage', 'login', 'determine_user_language', 'bool');
- $this->setConfigFromParams($oConfig, 'DetermineUserDomain', 'login', 'determine_user_domain', 'bool');
-
- $this->setConfigFromParams($oConfig, 'Title', 'webmail', 'title', 'string');
- $this->setConfigFromParams($oConfig, 'LoadingDescription', 'webmail', 'loading_description', 'string');
- $this->setConfigFromParams($oConfig, 'FaviconUrl', 'webmail', 'favicon_url', 'string');
-
- $this->setConfigFromParams($oConfig, 'TokenProtection', 'security', 'csrf_protection', 'bool');
- $this->setConfigFromParams($oConfig, 'EnabledPlugins', 'plugins', 'enable', 'bool');
-
- $this->setConfigFromParams($oConfig, 'GoogleEnable', 'social', 'google_enable', 'bool');
- $this->setConfigFromParams($oConfig, 'GoogleEnableAuth', 'social', 'google_enable_auth', 'bool');
- $this->setConfigFromParams($oConfig, 'GoogleEnableAuthFast', 'social', 'google_enable_auth_fast', 'bool');
- $this->setConfigFromParams($oConfig, 'GoogleEnableDrive', 'social', 'google_enable_drive', 'bool');
- $this->setConfigFromParams($oConfig, 'GoogleEnablePreview', 'social', 'google_enable_preview', 'bool');
- $this->setConfigFromParams($oConfig, 'GoogleClientID', 'social', 'google_client_id', 'string');
- $this->setConfigFromParams($oConfig, 'GoogleClientSecret', 'social', 'google_client_secret', 'string');
- $this->setConfigFromParams($oConfig, 'GoogleApiKey', 'social', 'google_api_key', 'string');
-
- $this->setConfigFromParams($oConfig, 'FacebookEnable', 'social', 'fb_enable', 'bool');
- $this->setConfigFromParams($oConfig, 'FacebookAppID', 'social', 'fb_app_id', 'string');
- $this->setConfigFromParams($oConfig, 'FacebookAppSecret', 'social', 'fb_app_secret', 'string');
-
- $this->setConfigFromParams($oConfig, 'TwitterEnable', 'social', 'twitter_enable', 'bool');
- $this->setConfigFromParams($oConfig, 'TwitterConsumerKey', 'social', 'twitter_consumer_key', 'string');
- $this->setConfigFromParams($oConfig, 'TwitterConsumerSecret', 'social', 'twitter_consumer_secret', 'string');
-
- $this->setConfigFromParams($oConfig, 'DropboxEnable', 'social', 'dropbox_enable', 'bool');
- $this->setConfigFromParams($oConfig, 'DropboxApiKey', 'social', 'dropbox_api_key', 'string');
-
- $oPremProvider = $this->PremProvider();
- if ($oPremProvider)
- {
- $oPremProvider->PremSection($this, $oConfig);
- }
-
- return $this->DefaultResponse(__FUNCTION__, $oConfig->Save());
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoAdminLogin()
- {
- $sLogin = trim($this->GetActionParam('Login', ''));
- $sPassword = $this->GetActionParam('Password', '');
-
- $this->Logger()->AddSecret($sPassword);
-
- if (0 === strlen($sLogin) || 0 === strlen($sPassword) ||
- !$this->Config()->Get('security', 'allow_admin_panel', true) ||
- $sLogin !== $this->Config()->Get('security', 'admin_login', '') ||
- !$this->Config()->ValidatePassword($sPassword))
- {
- $this->loginErrorDelay();
- $this->LoggerAuthHelper(null, $this->getAdditionalLogParamsByUserLogin($sLogin, true));
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError);
- }
-
- $sToken = $this->getAdminToken();
- $this->setAdminAuthToken($sToken);
-
- return $this->DefaultResponse(__FUNCTION__, $sToken ? true : false);
- }
-
- /**
- * @return array
- */
- public function DoAdminLogout()
- {
- $this->ClearAdminAuthToken();
- return $this->TrueResponse(__FUNCTION__);
- }
-
- /**
- * @return array
- */
- public function DoAdminPing()
- {
- $this->IsAdminLoggined();
-
- return $this->DefaultResponse(__FUNCTION__, true);
- }
-
- /**
- * @return array
- */
- public function DoAdminContactsTest()
- {
- $this->IsAdminLoggined();
-
- $oConfig = $this->Config();
-
- $this->setConfigFromParams($oConfig, 'ContactsPdoDsn', 'contacts', 'pdo_dsn', 'string');
- $this->setConfigFromParams($oConfig, 'ContactsPdoUser', 'contacts', 'pdo_user', 'string');
- $this->setConfigFromParams($oConfig, 'ContactsPdoPassword', 'contacts', 'pdo_password', 'dummy');
-
- $self = $this;
- $this->setConfigFromParams($oConfig, 'ContactsPdoType', 'contacts', 'type', 'string', function ($sType) use ($self) {
- return $self->ValidateContactPdoType($sType);
- });
-
- $sTestMessage = $this->AddressBookProvider(null, true)->Test();
- return $this->DefaultResponse(__FUNCTION__, array(
- 'Result' => '' === $sTestMessage,
- 'Message' => \MailSo\Base\Utils::Utf8Clear($sTestMessage, '?')
- ));
- }
-
- /**
- * @return array
- */
- public function DoAdminLicensing()
- {
- $this->IsAdminLoggined();
-
- $bForce = '1' === (string) $this->GetActionParam('Force', '0');
-
- $mResult = false;
- $iErrorCode = -1;
-
- $oPremProvider = $this->PremProvider();
-
- if ($oPremProvider && 2 < \strlen(APP_SITE))
- {
- $sValue = $oPremProvider->Fetcher($bForce);
-
- $this->requestSleep();
-
- $iExpired = 0;
- if ($oPremProvider->Parser($sValue, $iExpired))
- {
- $mResult = array(
- 'Banned' => false,
- 'Expired' => $iExpired,
- );
- }
- else if ($sValue === 'NO' || \preg_match('/^EXPIRED:[\d]+$/', $sValue))
- {
- $iErrorCode = -1;
- }
- else if ($sValue === 'TOO_MANY_CONNECTIONS')
- {
- $iErrorCode = -1;
- }
- else
- {
- $iErrorCode = \RainLoop\Notifications::LicensingServerIsUnavailable;
- }
- }
-
- if (0 < $iErrorCode && !$mResult)
- {
- throw new \RainLoop\Exceptions\ClientException($iErrorCode);
- }
-
- return $this->DefaultResponse(__FUNCTION__, $mResult);
- }
-
- /**
- * @return array
- */
- public function DoAdminLicensingActivate()
- {
- $this->IsAdminLoggined();
-
- $sDomain = (string) $this->GetActionParam('Domain', '');
- $sKey = (string) $this->GetActionParam('Key', '');
-
- $mResult = false;
- $iErrorCode = -1;
-
- $oPrem = $this->PremProvider();
-
- if ($oPrem && 2 < \strlen($sDomain) && 2 < \strlen($sKey) && $sDomain === APP_SITE)
- {
- $iCode = 0;
- $sValue = $oPrem->Activate($sDomain, $sKey, $iCode);
-
- $this->requestSleep();
-
- $aMatch = array();
- if ('OK' === $sValue)
- {
- $mResult = true;
- }
- else if ('TOO_MANY_CONNECTIONS' === $sValue)
- {
- $mResult = 'Too many connections. Please try again later.';
- }
- else if (\preg_match('/^ERROR:(.+)$/', $sValue, $aMatch) && !empty($aMatch[1]))
- {
- $mResult = trim($aMatch[1]);
-
- $this->Logger()->Write('Activation error for: '.$sKey.' ('.$sDomain.')', \MailSo\Log\Enumerations\Type::ERROR);
- $this->Logger()->Write($mResult, \MailSo\Log\Enumerations\Type::ERROR);
- }
- else
- {
- $iErrorCode = \RainLoop\Notifications::LicensingServerIsUnavailable;
- }
- }
-
- if (0 < $iErrorCode && !$mResult)
- {
- throw new \RainLoop\Exceptions\ClientException($iErrorCode);
- }
-
- return $this->DefaultResponse(__FUNCTION__, $mResult);
- }
-
- /**
- * @return array
- */
- public function DoAdminPasswordUpdate()
- {
- $this->IsAdminLoggined();
-
- $bResult = false;
- $oConfig = $this->Config();
-
- $sLogin = \trim($this->GetActionParam('Login', ''));
- $sPassword = $this->GetActionParam('Password', '');
- $this->Logger()->AddSecret($sPassword);
-
- $sNewPassword = $this->GetActionParam('NewPassword', '');
- if (0 < \strlen(\trim($sNewPassword)))
- {
- $this->Logger()->AddSecret($sNewPassword);
- }
-
- if ($oConfig->ValidatePassword($sPassword))
- {
- if (0 < \strlen($sLogin))
- {
- $oConfig->Set('security', 'admin_login', $sLogin);
- }
-
- if (0 < \strlen(\trim($sNewPassword)))
- {
- $oConfig->SetPassword($sNewPassword);
- }
-
- $bResult = true;
- }
-
- return $this->DefaultResponse(__FUNCTION__, $bResult ?
- ($oConfig->Save() ? array('Weak' => $oConfig->ValidatePassword('12345')) : false) : false);
- }
-
- /**
- * @return array
- */
- public function DoAdminDomainLoad()
- {
- $this->IsAdminLoggined();
-
- return $this->DefaultResponse(__FUNCTION__,
- $this->DomainProvider()->Load($this->GetActionParam('Name', ''), false, false));
- }
-
- /**
- * @return array
- */
- public function DoAdminDomainList()
- {
- $this->IsAdminLoggined();
-
- $iOffset = (int) $this->GetActionParam('Offset', 0);
- $iLimit = (int) $this->GetActionParam('Limit', 20);
- $sSearch = (string) $this->GetActionParam('Search', '');
- $bIncludeAliases = '1' === (string) $this->GetActionParam('IncludeAliases', '1');
-
- $iOffset = 0;
- $sSearch = '';
- $iLimit = $this->Config()->Get('labs', 'domain_list_limit', 99);
-
- return $this->DefaultResponse(__FUNCTION__,
- $this->DomainProvider()->GetList($iOffset, $iLimit, $sSearch, $bIncludeAliases));
- }
-
- /**
- * @return array
- */
- public function DoAdminDomainDelete()
- {
- $this->IsAdminLoggined();
-
- return $this->DefaultResponse(__FUNCTION__,
- $this->DomainProvider()->Delete((string) $this->GetActionParam('Name', '')));
- }
-
- /**
- * @return array
- */
- public function DoAdminDomainDisable()
- {
- $this->IsAdminLoggined();
-
- return $this->DefaultResponse(__FUNCTION__, $this->DomainProvider()->Disable(
- (string) $this->GetActionParam('Name', ''),
- '1' === (string) $this->GetActionParam('Disabled', '0')
- ));
- }
-
- /**
- * @return array
- */
- public function DoAdminDomainSave()
- {
- $this->IsAdminLoggined();
-
- $oDomain = $this->DomainProvider()->LoadOrCreateNewFromAction($this);
-
- return $this->DefaultResponse(__FUNCTION__,
- $oDomain instanceof \RainLoop\Model\Domain ? $this->DomainProvider()->Save($oDomain) : false);
- }
-
- /**
- * @return array
- */
- public function DoAdminDomainAliasSave()
- {
- $this->IsAdminLoggined();
-
- return $this->DefaultResponse(__FUNCTION__, $this->DomainProvider()->SaveAlias(
- (string) $this->GetActionParam('Name', ''),
- (string) $this->GetActionParam('Alias', '')
- ));
- }
-
- /**
- * @return array
- */
- public function DoAdminDomainTest()
- {
- $this->IsAdminLoggined();
-
- $bImapResult = false;
- $sImapErrorDesc = '';
- $bSmtpResult = false;
- $sSmtpErrorDesc = '';
- $bSieveResult = false;
- $sSieveErrorDesc = '';
-
- $iImapTime = 0;
- $iSmtpTime = 0;
- $iSieveTime = 0;
-
- $iConnectionTimeout = 5;
-
- $oDomain = $this->DomainProvider()->LoadOrCreateNewFromAction($this, 'domain-test-connection.de');
- if ($oDomain)
- {
- try
- {
- $oImapClient = \MailSo\Imap\ImapClient::NewInstance()->SetLogger($this->Logger());
- $oImapClient->SetTimeOuts($iConnectionTimeout);
-
- $iTime = \microtime(true);
- $oImapClient->Connect($oDomain->IncHost(), $oDomain->IncPort(), $oDomain->IncSecure(),
- !!$this->Config()->Get('ssl', 'verify_certificate', false),
- !!$this->Config()->Get('ssl', 'allow_self_signed', true)
- );
-
- $iImapTime = \microtime(true) - $iTime;
- $oImapClient->Disconnect();
- $bImapResult = true;
- }
- catch (\MailSo\Net\Exceptions\SocketCanNotConnectToHostException $oException)
- {
- $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
- $sImapErrorDesc = $oException->getSocketMessage();
- if (empty($sImapErrorDesc))
- {
- $sImapErrorDesc = $oException->getMessage();
- }
- }
- catch (\Exception $oException)
- {
- $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
- $sImapErrorDesc = $oException->getMessage();
- }
-
- if ($oDomain->OutUsePhpMail())
- {
- $bSmtpResult = \MailSo\Base\Utils::FunctionExistsAndEnabled('mail');
- if (!$bSmtpResult)
- {
- $sSmtpErrorDesc = 'PHP: mail() function is undefined';
- }
- }
- else
- {
- try
- {
- $oSmtpClient = \MailSo\Smtp\SmtpClient::NewInstance()->SetLogger($this->Logger());
- $oSmtpClient->SetTimeOuts($iConnectionTimeout);
-
- $iTime = \microtime(true);
- $oSmtpClient->Connect($oDomain->OutHost(), $oDomain->OutPort(),
- \MailSo\Smtp\SmtpClient::EhloHelper(), $oDomain->OutSecure(),
- !!$this->Config()->Get('ssl', 'verify_certificate', false),
- !!$this->Config()->Get('ssl', 'allow_self_signed', true)
- );
-
- $iSmtpTime = \microtime(true) - $iTime;
- $oSmtpClient->Disconnect();
- $bSmtpResult = true;
- }
- catch (\MailSo\Net\Exceptions\SocketCanNotConnectToHostException $oException)
- {
- $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
- $sSmtpErrorDesc = $oException->getSocketMessage();
- if (empty($sSmtpErrorDesc))
- {
- $sSmtpErrorDesc = $oException->getMessage();
- }
- }
- catch (\Exception $oException)
- {
- $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
- $sSmtpErrorDesc = $oException->getMessage();
- }
- }
-
- if ($oDomain->UseSieve())
- {
- try
- {
- $oSieveClient = \MailSo\Sieve\ManageSieveClient::NewInstance()->SetLogger($this->Logger());
- $oSieveClient->SetTimeOuts($iConnectionTimeout);
- $oSieveClient->__USE_INITIAL_AUTH_PLAIN_COMMAND = !!$this->Config()->Get('labs', 'sieve_auth_plain_initial', true);
-
- $iTime = \microtime(true);
- $oSieveClient->Connect($oDomain->SieveHost(), $oDomain->SievePort(), $oDomain->SieveSecure(),
- !!$this->Config()->Get('ssl', 'verify_certificate', false),
- !!$this->Config()->Get('ssl', 'allow_self_signed', true)
- );
-
- $iSieveTime = \microtime(true) - $iTime;
- $oSieveClient->Disconnect();
- $bSieveResult = true;
- }
- catch (\MailSo\Net\Exceptions\SocketCanNotConnectToHostException $oException)
- {
- $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
- $sSieveErrorDesc = $oException->getSocketMessage();
- if (empty($sSieveErrorDesc))
- {
- $sSieveErrorDesc = $oException->getMessage();
- }
- }
- catch (\Exception $oException)
- {
- $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
- $sSieveErrorDesc = $oException->getMessage();
- }
- }
- else
- {
- $bSieveResult = true;
- }
- }
-
- return $this->DefaultResponse(__FUNCTION__, array(
- 'Imap' => $bImapResult ? true : $sImapErrorDesc,
- 'Smtp' => $bSmtpResult ? true : $sSmtpErrorDesc,
- 'Sieve' => $bSieveResult ? true : $sSieveErrorDesc
- ));
- }
-
- /**
- * @return string
- */
- private function rainLoopRepo()
- {
- $sUrl = APP_REPOSITORY_PATH;
- if ('' !== $sUrl)
- {
- $sUrl = rtrim($sUrl, '\\/').'/';
- }
-
- return $sUrl;
- }
-
- private function rainLoopUpdatable()
- {
- return @file_exists(APP_INDEX_ROOT_PATH.'index.php') &&
- @is_writable(APP_INDEX_ROOT_PATH.'index.php') &&
- @is_writable(APP_INDEX_ROOT_PATH.'rainloop/') &&
- APP_VERSION !== APP_DEV_VERSION
- ;
- }
-
- private function rainLoopCoreAccess()
- {
- $sCoreAccess = \strtolower(\preg_replace('/[\s,;]+/', ' ',
- $this->Config()->Get('security', 'core_install_access_domain', '')));
-
- return '' === $sCoreAccess || '*' === $sCoreAccess || APP_SITE === $sCoreAccess;
- }
-
- /**
- * @param string $sRepo
- * @param bool $bReal = false
- *
- * @return array
- */
- private function getRepositoryDataByUrl($sRepo, &$bReal = false)
- {
- $bReal = false;
- $aRep = null;
-
- $sRep = '';
- $sRepoFile = 'repository.json';
- $iRepTime = 0;
-
- $oHttp = \MailSo\Base\Http::SingletonInstance();
-
- $sCacheKey = \RainLoop\KeyPathHelper::RepositoryCacheFile($sRepo, $sRepoFile);
- $sRep = $this->Cacher()->Get($sCacheKey);
- if ('' !== $sRep)
- {
- $iRepTime = $this->Cacher()->GetTimer($sCacheKey);
- }
-
- if ('' === $sRep || 0 === $iRepTime || time() - 3600 > $iRepTime)
- {
- $iCode = 0;
- $sContentType = '';
-
- $sRepPath = $sRepo.$sRepoFile;
- $sRep = '' !== $sRepo ? $oHttp->GetUrlAsString($sRepPath, 'RainLoop', $sContentType, $iCode, $this->Logger(), 10,
- $this->Config()->Get('labs', 'curl_proxy', ''), $this->Config()->Get('labs', 'curl_proxy_auth', '')) : false;
-
- if (false !== $sRep)
- {
- $aRep = @\json_decode($sRep);
- $bReal = \is_array($aRep) && 0 < \count($aRep);
-
- if ($bReal)
- {
- $this->Cacher()->Set($sCacheKey, $sRep);
- $this->Cacher()->SetTimer($sCacheKey);
- }
- }
- else
- {
- $this->Logger()->Write('Cannot read remote repository file: '.$sRepPath, \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER');
- }
- }
- else if ('' !== $sRep)
- {
- $aRep = @\json_decode($sRep, false, 10);
- $bReal = \is_array($aRep) && 0 < \count($aRep);
- }
-
- $aResult = array();
- if (\is_array($aRep))
- {
- foreach ($aRep as $oItem)
- {
- if ($oItem && isset($oItem->type, $oItem->id, $oItem->name,
- $oItem->version, $oItem->release, $oItem->file, $oItem->description))
- {
- if (!empty($oItem->required) && APP_DEV_VERSION !== APP_VERSION && version_compare(APP_VERSION, $oItem->required, '<'))
- {
- continue;
- }
-
- if (!empty($oItem->depricated) && APP_DEV_VERSION !== APP_VERSION && version_compare(APP_VERSION, $oItem->depricated, '>='))
- {
- continue;
- }
-
- if ('plugin' === $oItem->type)
- {
- $aResult[] = array(
- 'type' => $oItem->type,
- 'id' => $oItem->id,
- 'name' => $oItem->name,
- 'installed' => '',
- 'version' => $oItem->version,
- 'file' => $oItem->file,
- 'release' => $oItem->release,
- 'desc' => $oItem->description
- );
- }
- }
- }
- }
-
- return $aResult;
- }
-
- /**
- * @return string
- */
- private function getCoreChannel()
- {
- $sChannel = \trim(\strtolower($this->Config()->Get('labs', 'update_channel', 'stable')));
- if (empty($sChannel) || !\in_array($sChannel, array('stable', 'beta')))
- {
- $sChannel = 'stable';
- }
-
- return $sChannel;
- }
-
- private function getCoreData(&$bReal)
- {
- $bReal = false;
-
- $sChannel = $this->getCoreChannel();
-
- $sRepo = \str_replace('{{channel}}', $sChannel, APP_REPO_CORE_FILE);
-
- $oHttp = \MailSo\Base\Http::SingletonInstance();
-
- $sCacheKey = \RainLoop\KeyPathHelper::RepositoryCacheCore($sRepo);
- $sRep = $this->Cacher()->Get($sCacheKey);
- if ('' !== $sRep)
- {
- $iRepTime = $this->Cacher()->GetTimer($sCacheKey);
- }
-
- if ('' === $sRep || 0 === $iRepTime || time() - 3600 > $iRepTime)
- {
- $iCode = 0;
- $sContentType = '';
-
- $sRep = '' !== $sRepo ? $oHttp->GetUrlAsString($sRepo, 'RainLoop', $sContentType, $iCode, $this->Logger(), 10,
- $this->Config()->Get('labs', 'curl_proxy', ''), $this->Config()->Get('labs', 'curl_proxy_auth', '')) : false;
-
- if (false !== $sRep)
- {
- $aRep = @\json_decode($sRep, true, 10);
- $bReal = \is_array($aRep) && 0 < \count($aRep) && isset($aRep['id']) && 'rainloop' === $aRep['id'];
-
- if ($bReal)
- {
- $this->Cacher()->Set($sCacheKey, $sRep);
- $this->Cacher()->SetTimer($sCacheKey);
- }
- }
- else
- {
- $this->Logger()->Write('Cannot read remote repository file: '.$sRepo, \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER');
- }
- }
- else if ('' !== $sRep)
- {
- $aRep = @\json_decode($sRep, true, 10);
- $bReal = \is_array($aRep) && 0 < \count($aRep) && isset($aRep['id']) && 'rainloop' === $aRep['id'];
- }
-
- return $bReal ? $aRep : false;
- }
-
- private function getRepositoryData(&$bReal, &$bRainLoopUpdatable)
- {
- $bRainLoopUpdatable = $this->rainLoopUpdatable();
-
- $aResult = $this->getRepositoryDataByUrl($this->rainLoopRepo(), $bReal);
-
- $aSub = array();
- if (\is_array($aResult))
- {
- foreach ($aResult as $aItem)
- {
- if ('plugin' === $aItem['type'])
- {
- $aSub[] = $aItem;
- }
- }
-
- $aResult = $aSub;
- unset($aSub);
- }
-
- $aInstalled = $this->Plugins()->InstalledPlugins();
- if (\is_array($aInstalled))
- {
- foreach ($aResult as &$aItem)
- {
- if ('plugin' === $aItem['type'])
- {
- foreach ($aInstalled as &$aSubItem)
- {
- if (\is_array($aSubItem) && isset($aSubItem[0]) && $aSubItem[0] === $aItem['id'])
- {
- $aSubItem[2] = true;
- $aItem['installed'] = $aSubItem[1];
- }
- }
- }
- }
-
- foreach ($aInstalled as $aSubItemSec)
- {
- if ($aSubItemSec && !isset($aSubItemSec[2]))
- {
- \array_push($aResult, array(
- 'type' => 'plugin',
- 'id' => $aSubItemSec[0],
- 'name' => $aSubItemSec[0],
- 'installed' => $aSubItemSec[1],
- 'version' => '',
- 'file' => '',
- 'release' => '',
- 'desc' => ''
- ));
- }
- }
- }
-
- foreach ($aResult as &$aItem)
- {
- $aItem['compare'] = \version_compare($aItem['installed'], $aItem['version'], '<');
- $aItem['canBeDeleted'] = '' !== $aItem['installed'] && 'plugin' === $aItem['type'];
- $aItem['canBeUpdated'] = $aItem['compare'];
- $aItem['canBeInstalled'] = true;
- }
-
- return $aResult;
- }
-
- /**
- * @return array
- */
- public function DoAdminPackagesList()
- {
- $this->IsAdminLoggined();
-
- $bReal = false;
- $bRainLoopUpdatable = false;
- $aList = $this->getRepositoryData($bReal, $bRainLoopUpdatable);
-
- return $this->DefaultResponse(__FUNCTION__, array(
- 'Real' => $bReal,
- 'MainUpdatable' => $bRainLoopUpdatable,
- 'List' => $aList
- ));
- }
-
- /**
- * @return array
- */
- public function DoAdminCoreData()
- {
- $this->IsAdminLoggined();
-
- $bReal = false;
- $aData = array();
-
- $bRainLoopUpdatable = $this->rainLoopUpdatable();
- $bRainLoopAccess = $this->rainLoopCoreAccess();
-
- if ($bRainLoopAccess)
- {
- $aData = $this->getCoreData($bReal);
- }
-
- $sVersion = empty($aData['version']) ? '' : $aData['version'];
- $sType = empty($aData['channel']) ? 'stable' : $aData['channel'];
-
- $sWarnings = empty($aData['warnings']) ? '' : $aData['warnings'];
- $aWarnings = $sWarnings ? explode('|', $sWarnings) : array();
-
- $sCurrentVersion = APP_VERSION;
-
- $bShowWarning = false;
- if ($sCurrentVersion !== APP_DEV_VERSION)
- {
- foreach ($aWarnings as $sWarningVersion)
- {
- $sWarningVersion = \trim($sWarningVersion);
-
- if (\version_compare($sCurrentVersion, $sWarningVersion, '<') &&
- \version_compare($sVersion, $sWarningVersion, '>='))
- {
- $bShowWarning = true;
- break;
- }
- }
- }
-
- return $this->DefaultResponse(__FUNCTION__, array(
- 'Real' => $bReal,
- 'Access' => $bRainLoopAccess,
- 'Updatable' => $bRainLoopUpdatable,
- 'Warning' => $bShowWarning,
- 'Channel' => $this->getCoreChannel(),
- 'Type' => $sType,
- 'Version' => $sCurrentVersion,
- 'RemoteVersion' => $sVersion,
- 'RemoteRelease' => empty($aData['release']) ? '' : $aData['release'],
- 'VersionCompare' => \version_compare($sCurrentVersion, $sVersion)
- ));
- }
-
- /**
- * @return array
- */
- public function DoAdminUpdateCoreData()
- {
- $this->IsAdminLoggined();
-
- $bReal = false;
-
- $bRainLoopUpdatable = $this->rainLoopUpdatable();
- $bRainLoopAccess = $this->rainLoopCoreAccess();
- $oPremProvider = $this->PremProvider();
-
- $aData = array();
- if ($bRainLoopUpdatable && $bRainLoopAccess)
- {
- $aData = $this->getCoreData($bReal);
- }
-
- $bResult = false;
- if ($bReal && $oPremProvider && !empty($aData['file']))
- {
- $bResult = $oPremProvider->UpdateCore($this, $aData['file']);
- }
-
- return $this->DefaultResponse(__FUNCTION__, $bResult);
- }
-
- /**
- * @return array
- */
- public function DoAdminPackageDelete()
- {
- $this->IsAdminLoggined();
-
- $sId = $this->GetActionParam('Id', '');
-
- $bReal = false;
- $bRainLoopUpdatable = false;
- $aList = $this->getRepositoryData($bReal, $bRainLoopUpdatable);
-
- $sResultId = '';
- foreach ($aList as $oItem)
- {
- if ($oItem && 'plugin' === $oItem['type'] && $sId === $oItem['id'])
- {
- $sResultId = $sId;
- break;
- }
- }
-
- $bResult = false;
- if ('' !== $sResultId)
- {
- $bResult = \MailSo\Base\Utils::RecRmDir(APP_PLUGINS_PATH.$sResultId);
- if ($bResult)
- {
- $this->pluginEnable($sResultId, false);
- }
- }
-
- return $this->DefaultResponse(__FUNCTION__, $bResult);
- }
-
- /**
- * @param string $sUrl
- *
- * @return string
- */
- public function downloadRemotePackageByUrl($sUrl)
- {
- $bResult = false;
- $sTmp = APP_PRIVATE_DATA.\md5(\microtime(true).$sUrl).'.zip';
- $pDest = @\fopen($sTmp, 'w+b');
- if ($pDest)
- {
- $iCode = 0;
- $sContentType = '';
-
- @\set_time_limit(120);
-
- $oHttp = \MailSo\Base\Http::SingletonInstance();
- $bResult = $oHttp->SaveUrlToFile($sUrl, $pDest, $sTmp, $sContentType, $iCode, $this->Logger(), 60,
- $this->Config()->Get('labs', 'curl_proxy', ''), $this->Config()->Get('labs', 'curl_proxy_auth', ''));
-
- if (!$bResult)
- {
- $this->Logger()->Write('Cannot save url to temp file: ', \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER');
- $this->Logger()->Write($sUrl.' -> '.$sTmp, \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER');
- }
-
- @\fclose($pDest);
- }
- else
- {
- $this->Logger()->Write('Cannot create temp file: '.$sTmp, \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER');
- }
-
- return $bResult ? $sTmp : '';
- }
-
- /**
- * @return array
- */
- public function DoAdminPackageInstall()
- {
- $this->IsAdminLoggined();
-
- $sType = $this->GetActionParam('Type', '');
- $sId = $this->GetActionParam('Id', '');
- $sFile = $this->GetActionParam('File', '');
-
- $this->Logger()->Write('Start package install: '.$sFile.' ('.$sType.')', \MailSo\Log\Enumerations\Type::INFO, 'INSTALLER');
-
- $sRealFile = '';
-
- $bReal = false;
- $bRainLoopUpdatable = false;
- $aList = $this->getRepositoryData($bReal, $bRainLoopUpdatable);
-
- if ('plugin' === $sType)
- {
- foreach ($aList as $oItem)
- {
- if ($oItem && $sFile === $oItem['file'] && $sId === $oItem['id'])
- {
- $sRealFile = $sFile;
- break;
- }
- }
- }
-
- $sTmp = '';
- $bResult = false;
- if ('' !== $sRealFile)
- {
- $sUrl = $this->rainLoopRepo().$sRealFile;
- $sTmp = $this->downloadRemotePackageByUrl($sUrl);
- }
-
- if ('' !== $sTmp)
- {
- include_once APP_VERSION_ROOT_PATH.'app/libraries/pclzip/pclzip.lib.php';
-
- $oArchive = new \PclZip($sTmp);
- if ('plugin' === $sType)
- {
- $bResult = true;
- if (\is_dir(APP_PLUGINS_PATH.$sId))
- {
- $bResult = \MailSo\Base\Utils::RecRmDir(APP_PLUGINS_PATH.$sId);
- if (!$bResult)
- {
- $this->Logger()->Write('Cannot remove previous plugin folder: '.$sId, \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER');
- }
- }
-
- if ($bResult)
- {
- $bResult = 0 !== $oArchive->extract(PCLZIP_OPT_PATH, APP_PLUGINS_PATH);
- if (!$bResult)
- {
- $this->Logger()->Write('Cannot extract package files: '.$oArchive->errorInfo(), \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER');
- }
- }
- }
-
- @\unlink($sTmp);
- }
-
- return $this->DefaultResponse(__FUNCTION__, $bResult ?
- ('plugin' !== $sType ? array('Reload' => true) : true) : false);
- }
-
- /**
- * @return array
- */
- public function DoAdminPluginList()
- {
- $this->IsAdminLoggined();
-
- $aResult = array();
-
- $sEnabledPlugins = $this->Config()->Get('plugins', 'enabled_list', '');
- $aEnabledPlugins = \explode(',', \strtolower($sEnabledPlugins));
- $aEnabledPlugins = \array_map('trim', $aEnabledPlugins);
-
- $aList = $this->Plugins()->InstalledPlugins();
- foreach ($aList as $aItem)
- {
- $aResult[] = array(
- 'Name' => $aItem[0],
- 'Enabled' => \in_array(\strtolower($aItem[0]), $aEnabledPlugins),
- 'Configured' => false
- );
- }
-
- return $this->DefaultResponse(__FUNCTION__, $aResult);
- }
-
- /**
- * @param string $sName
- * @param bool $bEnable = true
- * @return bool
- */
- private function pluginEnable($sName, $bEnable = true)
- {
- if (0 === \strlen($sName))
- {
- return false;
- }
-
- $oConfig = $this->Config();
-
- $sEnabledPlugins = $oConfig->Get('plugins', 'enabled_list', '');
- $aEnabledPlugins = \explode(',', \strtolower($sEnabledPlugins));
- $aEnabledPlugins = \array_map('trim', $aEnabledPlugins);
-
- $aNewEnabledPlugins = array();
- if ($bEnable)
- {
- $aNewEnabledPlugins = $aEnabledPlugins;
- $aNewEnabledPlugins[] = $sName;
- }
- else
- {
- foreach ($aEnabledPlugins as $sPlugin)
- {
- if ($sName !== $sPlugin && 0 < \strlen($sPlugin))
- {
- $aNewEnabledPlugins[] = $sPlugin;
- }
- }
- }
-
- $aNewEnabledPlugins = \array_unique($aNewEnabledPlugins);
- $oConfig->Set('plugins', 'enabled_list', \trim(\implode(',', $aNewEnabledPlugins), ' ,'));
-
- return $oConfig->Save();
- }
-
- /**
- * @return array
- */
- public function DoAdminPluginDisable()
- {
- $this->IsAdminLoggined();
-
- $sName = (string) $this->GetActionParam('Name', '');
- $bDisable = '1' === (string) $this->GetActionParam('Disabled', '1');
-
- if (!$bDisable)
- {
- $oPlugin = $this->Plugins()->CreatePluginByName($sName);
- if ($oPlugin && ($oPlugin instanceof \RainLoop\Plugins\AbstractPlugin))
- {
- $sValue = $oPlugin->Supported();
- if (0 < \strlen($sValue))
- {
- return $this->FalseResponse(__FUNCTION__, \RainLoop\Notifications::UnsupportedPluginPackage, $sValue);
- }
- }
- else
- {
- return $this->FalseResponse(__FUNCTION__, \RainLoop\Notifications::InvalidPluginPackage);
- }
- }
-
- return $this->DefaultResponse(__FUNCTION__, $this->pluginEnable($sName, !$bDisable));
- }
-
- /**
- * @return array
- */
- public function DoAdminPluginLoad()
- {
- $this->IsAdminLoggined();
-
- $mResult = false;
- $sName = (string) $this->GetActionParam('Name', '');
-
- if (!empty($sName))
- {
- $oPlugin = $this->Plugins()->CreatePluginByName($sName);
- if ($oPlugin)
- {
- $mResult = array(
- 'Name' => $sName,
- 'Readme' => file_exists($oPlugin->Path().'/README') ? file_get_contents($oPlugin->Path().'/README') : '',
- 'Config' => array()
- );
-
- $aMap = $oPlugin->ConfigMap();
- $oConfig = $oPlugin->Config();
- if (is_array($aMap) && 0 < count($aMap))
- {
- foreach ($aMap as $oItem)
- {
- if ($oItem && ($oItem instanceof \RainLoop\Plugins\Property))
- {
- $aItem = $oItem->ToArray();
- $aItem[0] = $oConfig->Get('plugin', $oItem->Name(), '');
- if (\RainLoop\Enumerations\PluginPropertyType::PASSWORD === $oItem->Type())
- {
- $aItem[0] = APP_DUMMY;
- }
-
- $mResult['Config'][] = $aItem;
- }
- }
- }
- }
- }
-
- return $this->DefaultResponse(__FUNCTION__, $mResult);
- }
-
- /**
- * @return array
- */
- public function DoAdminPluginSettingsUpdate()
- {
- $this->IsAdminLoggined();
-
- $mResult = false;
- $sName = (string) $this->GetActionParam('Name', '');
-
- if (!empty($sName))
- {
- $oPlugin = $this->Plugins()->CreatePluginByName($sName);
- if ($oPlugin)
- {
- $oConfig = $oPlugin->Config();
- $aMap = $oPlugin->ConfigMap();
- if (is_array($aMap) && 0 < count($aMap))
- {
- foreach ($aMap as $oItem)
- {
- $sValue = $this->GetActionParam('_'.$oItem->Name(), $oConfig->Get('plugin', $oItem->Name()));
- if (\RainLoop\Enumerations\PluginPropertyType::PASSWORD !== $oItem->Type() || APP_DUMMY !== $sValue)
- {
- $mResultValue = null;
- switch ($oItem->Type()) {
- case \RainLoop\Enumerations\PluginPropertyType::INT:
- $mResultValue = (int) $sValue;
- break;
- case \RainLoop\Enumerations\PluginPropertyType::BOOL:
- $mResultValue = '1' === (string) $sValue;
- break;
- case \RainLoop\Enumerations\PluginPropertyType::SELECTION:
- if (is_array($oItem->DefaultValue()) && in_array($sValue, $oItem->DefaultValue()))
- {
- $mResultValue = (string) $sValue;
- }
- break;
- case \RainLoop\Enumerations\PluginPropertyType::PASSWORD:
- case \RainLoop\Enumerations\PluginPropertyType::STRING:
- case \RainLoop\Enumerations\PluginPropertyType::STRING_TEXT:
- $mResultValue = (string) $sValue;
- break;
- }
-
- if (null !== $mResultValue)
- {
- $oConfig->Set('plugin', $oItem->Name(), $mResultValue);
- }
- }
- }
- }
-
- $mResult = $oConfig->Save();
- }
- }
-
- if (!$mResult)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantSavePluginSettings);
- }
-
- return $this->DefaultResponse(__FUNCTION__, true);
- }
-
- /**
- * @return array
- */
- public function DoSettingsUpdate()
- {
- $oAccount = $this->getAccountFromToken();
- if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::SETTINGS, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $self = $this;
- $oConfig = $this->Config();
-
- $oSettings = $this->SettingsProvider()->Load($oAccount);
- $oSettingsLocal = $this->SettingsProvider(true)->Load($oAccount);
-
- if ($oConfig->Get('webmail', 'allow_languages_on_settings', true))
- {
- $this->setSettingsFromParams($oSettings, 'Language', 'string', function ($sLanguage) use ($self) {
- return $self->ValidateLanguage($sLanguage);
- });
- }
- else
- {
- $oSettings->SetConf('Language', $this->ValidateLanguage($oConfig->Get('webmail', 'language', 'en')));
- }
-
- if ($this->GetCapa(false, false, \RainLoop\Enumerations\Capa::THEMES, $oAccount))
- {
- $this->setSettingsFromParams($oSettingsLocal, 'Theme', 'string', function ($sTheme) use ($self) {
- return $self->ValidateTheme($sTheme);
- });
- }
- else
- {
- $oSettingsLocal->SetConf('Theme', $this->ValidateTheme($oConfig->Get('webmail', 'theme', 'Default')));
- }
-
- $this->setSettingsFromParams($oSettings, 'MPP', 'int', function ($iValue) {
- return (int) (\in_array($iValue, array(10, 20, 30, 50, 100, 150, 200, 300)) ? $iValue : 20);
- });
-
- $this->setSettingsFromParams($oSettings, 'Layout', 'int', function ($iValue) {
- return (int) (\in_array((int) $iValue, array(\RainLoop\Enumerations\Layout::NO_PREVIW,
- \RainLoop\Enumerations\Layout::SIDE_PREVIEW, \RainLoop\Enumerations\Layout::BOTTOM_PREVIEW)) ?
- $iValue : \RainLoop\Enumerations\Layout::SIDE_PREVIEW);
- });
-
- $this->setSettingsFromParams($oSettings, 'EditorDefaultType', 'string');
- $this->setSettingsFromParams($oSettings, 'ShowImages', 'bool');
- $this->setSettingsFromParams($oSettings, 'ContactsAutosave', 'bool');
- $this->setSettingsFromParams($oSettings, 'DesktopNotifications', 'bool');
- $this->setSettingsFromParams($oSettings, 'SoundNotification', 'bool');
- $this->setSettingsFromParams($oSettings, 'UseCheckboxesInList', 'bool');
- $this->setSettingsFromParams($oSettings, 'AllowDraftAutosave', 'bool');
- $this->setSettingsFromParams($oSettings, 'AutoLogout', 'int');
-
- $this->setSettingsFromParams($oSettings, 'EnableTwoFactor', 'bool');
-
- $this->setSettingsFromParams($oSettingsLocal, 'UseThreads', 'bool');
- $this->setSettingsFromParams($oSettingsLocal, 'ReplySameFolder', 'bool');
-
- return $this->DefaultResponse(__FUNCTION__,
- $this->SettingsProvider()->Save($oAccount, $oSettings) &&
- $this->SettingsProvider(true)->Save($oAccount, $oSettingsLocal));
- }
-
- /**
- * @return array
- */
- public function DoNoop()
- {
- $this->initMailClientConnection();
- return $this->TrueResponse(__FUNCTION__);
- }
-
- /**
- * @return array
- */
- public function DoPing()
- {
- return $this->DefaultResponse(__FUNCTION__, 'Pong');
- }
-
- /**
- * @return array
- */
- public function DoChangePassword()
- {
- $mResult = false;
-
- $oAccount = $this->getAccountFromToken();
- if ($oAccount)
- {
- try
- {
- $mResult = $this->ChangePasswordProvider()->ChangePassword(
- $oAccount,
- $this->GetActionParam('PrevPassword', ''),
- $this->GetActionParam('NewPassword', '')
- );
- }
- catch (\Exception $oException)
- {
- $this->loginErrorDelay();
- $this->Logger()->Write('Error: Can\'t change password for '.$oAccount->Email().' account.', \MailSo\Log\Enumerations\Type::NOTICE);
-
- throw $oException;
- }
- }
-
- return $this->DefaultResponse(__FUNCTION__, $mResult);
- }
-
- /**
- * @return array
- */
- public function DoJsInfo()
- {
- $bIsError = '1' === (string) $this->GetActionParam('IsError', '0');
- $mData = $this->GetActionParam('Data', null);
-
- $this->Logger()->WriteDump(is_array($mData) ? $mData : array(),
- $bIsError ? \MailSo\Log\Enumerations\Type::ERROR : \MailSo\Log\Enumerations\Type::INFO, 'JS-INFO');
-
- return $this->DefaultResponse(__FUNCTION__, true);
- }
-
- /**
- * @return array
- */
- public function DoWelcomeClose()
- {
- $oAccount = $this->getAccountFromToken();
- if ($oAccount && !$oAccount->IsAdditionalAccount())
- {
- $oSettings = $this->SettingsProvider()->Load($oAccount);
- $oSettings->SetConf('LastWelcomePage',
- $this->Config()->Get('branding', 'welcome_page_url', ''));
-
- return $this->DefaultResponse(__FUNCTION__,
- $this->SettingsProvider()->Save($oAccount, $oSettings));
- }
-
- return $this->FalseResponse(__FUNCTION__);
- }
-
- /**
- * @return array
- */
- public function DoVersion()
- {
- return $this->DefaultResponse(__FUNCTION__,
- APP_VERSION === (string) $this->GetActionParam('Version', ''));
- }
-
- /**
- * @return array
- */
- public function DoJsError()
- {
- $sMessage = $this->GetActionParam('Message', '');
- if (0 < strlen($sMessage))
- {
- $sFileName = $this->GetActionParam('FileName', '');
- $sLineNo = $this->GetActionParam('LineNo', '');
- $sLocation = $this->GetActionParam('Location', '');
- $sHtmlCapa = $this->GetActionParam('HtmlCapa', '');
- $sTimeOnPage = $this->GetActionParam('TimeOnPage', '');
-
- $oHttp = $this->Http();
-
- $this->Logger()->Write($sMessage.' ('.$sFileName.' ~ '.$sLineNo.')', \MailSo\Log\Enumerations\Type::ERROR, 'JS');
- $this->Logger()->WriteDump(array(
- 'Location' => $sLocation,
- 'Capability' => $sHtmlCapa,
- 'TimeOnPage' => $sTimeOnPage,
- 'HTTP_USER_AGENT' => $oHttp->GetServer('HTTP_USER_AGENT', ''),
- 'HTTP_ACCEPT_ENCODING' => $oHttp->GetServer('HTTP_ACCEPT_ENCODING', ''),
- 'HTTP_ACCEPT_LANGUAGE' => $oHttp->GetServer('HTTP_ACCEPT_LANGUAGE', '')
- ));
- }
-
- return $this->DefaultResponse(__FUNCTION__, true);
- }
-
- /**
- * @param \MailSo\Mail\FolderCollection $oFolders
- * @return array
- */
- private function recFoldersNames($oFolders)
- {
- $aResult = array();
- if ($oFolders)
- {
- $aFolders =& $oFolders->GetAsArray();
-
- foreach ($aFolders as $oFolder)
- {
- $aResult[] = $oFolder->FullNameRaw()."|".
- implode("|", $oFolder->Flags()).($oFolder->IsSubscribed() ? '1' : '0');
-
- $oSub = $oFolder->SubFolders();
- if ($oSub && 0 < $oSub->Count())
- {
- $aResult = \array_merge($aResult, $this->recFoldersNames($oSub));
- }
- }
- }
-
- return $aResult;
- }
-
- /**
- * @staticvar array $aCache
- * @param \RainLoop\Model\Account $oAccount
- *
- * @return array
- */
- private function systemFoldersNames($oAccount)
- {
- static $aCache = null;
- if (null === $aCache)
- {
- $aCache = array(
-
- 'Sent' => \MailSo\Imap\Enumerations\FolderType::SENT,
- 'Send' => \MailSo\Imap\Enumerations\FolderType::SENT,
-
- 'Outbox' => \MailSo\Imap\Enumerations\FolderType::SENT,
- 'Out box' => \MailSo\Imap\Enumerations\FolderType::SENT,
-
- 'Sent Item' => \MailSo\Imap\Enumerations\FolderType::SENT,
- 'Sent Items' => \MailSo\Imap\Enumerations\FolderType::SENT,
- 'Send Item' => \MailSo\Imap\Enumerations\FolderType::SENT,
- 'Send Items' => \MailSo\Imap\Enumerations\FolderType::SENT,
- 'Sent Mail' => \MailSo\Imap\Enumerations\FolderType::SENT,
- 'Sent Mails' => \MailSo\Imap\Enumerations\FolderType::SENT,
- 'Send Mail' => \MailSo\Imap\Enumerations\FolderType::SENT,
- 'Send Mails' => \MailSo\Imap\Enumerations\FolderType::SENT,
-
- 'Drafts' => \MailSo\Imap\Enumerations\FolderType::DRAFTS,
-
- 'Draft' => \MailSo\Imap\Enumerations\FolderType::DRAFTS,
- 'Draft Mail' => \MailSo\Imap\Enumerations\FolderType::DRAFTS,
- 'Draft Mails' => \MailSo\Imap\Enumerations\FolderType::DRAFTS,
- 'Drafts Mail' => \MailSo\Imap\Enumerations\FolderType::DRAFTS,
- 'Drafts Mails' => \MailSo\Imap\Enumerations\FolderType::DRAFTS,
-
- 'Junk E-mail' => \MailSo\Imap\Enumerations\FolderType::JUNK,
-
- 'Spam' => \MailSo\Imap\Enumerations\FolderType::JUNK,
- 'Spams' => \MailSo\Imap\Enumerations\FolderType::JUNK,
-
- 'Junk' => \MailSo\Imap\Enumerations\FolderType::JUNK,
- 'Bulk Mail' => \MailSo\Imap\Enumerations\FolderType::JUNK,
- 'Bulk Mails' => \MailSo\Imap\Enumerations\FolderType::JUNK,
-
- 'Deleted Items' => \MailSo\Imap\Enumerations\FolderType::TRASH,
-
- 'Trash' => \MailSo\Imap\Enumerations\FolderType::TRASH,
- 'Deleted' => \MailSo\Imap\Enumerations\FolderType::TRASH,
- 'Bin' => \MailSo\Imap\Enumerations\FolderType::TRASH,
-
- 'Archive' => \MailSo\Imap\Enumerations\FolderType::ALL,
- 'Archives' => \MailSo\Imap\Enumerations\FolderType::ALL,
-
- 'All' => \MailSo\Imap\Enumerations\FolderType::ALL,
- 'All Mail' => \MailSo\Imap\Enumerations\FolderType::ALL,
- 'All Mails' => \MailSo\Imap\Enumerations\FolderType::ALL,
- );
-
- $aNewCache = array();
- foreach ($aCache as $sKey => $iType)
- {
- $aNewCache[$sKey] = $iType;
- $aNewCache[\str_replace(' ', '', $sKey)] = $iType;
- }
-
- $aCache = $aNewCache;
-
- $this->Plugins()->RunHook('filter.system-folders-names', array($oAccount, &$aCache));
- }
-
- return $aCache;
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount
- * @param \MailSo\Mail\FolderCollection $oFolders
- * @param array $aResult
- * @param bool $bListFolderTypes = true
- */
- private function recFoldersTypes($oAccount, $oFolders, &$aResult, $bListFolderTypes = true)
- {
- if ($oFolders)
- {
- $aFolders =& $oFolders->GetAsArray();
- if (\is_array($aFolders) && 0 < \count($aFolders))
- {
- if ($bListFolderTypes)
- {
- foreach ($aFolders as $oFolder)
- {
- $iFolderListType = $oFolder->GetFolderListType();
- if (!isset($aResult[$iFolderListType]) && \in_array($iFolderListType, array(
- \MailSo\Imap\Enumerations\FolderType::SENT,
- \MailSo\Imap\Enumerations\FolderType::DRAFTS,
- \MailSo\Imap\Enumerations\FolderType::JUNK,
- \MailSo\Imap\Enumerations\FolderType::TRASH,
- \MailSo\Imap\Enumerations\FolderType::ALL
- )))
- {
- $aResult[$iFolderListType] = $oFolder->FullNameRaw();
- }
- }
-
- foreach ($aFolders as $oFolder)
- {
- $oSub = $oFolder->SubFolders();
- if ($oSub && 0 < $oSub->Count())
- {
- $this->recFoldersTypes($oAccount, $oSub, $aResult, true);
- }
- }
- }
-
- $aMap = $this->systemFoldersNames($oAccount);
- foreach ($aFolders as $oFolder)
- {
- $sName = $oFolder->Name();
- $sFullName = $oFolder->FullName();
-
- if (isset($aMap[$sName]) || isset($aMap[$sFullName]))
- {
- $iFolderType = isset($aMap[$sName]) ? $aMap[$sName] : $aMap[$sFullName];
- if (!isset($aResult[$iFolderType]) && \in_array($iFolderType, array(
- \MailSo\Imap\Enumerations\FolderType::SENT,
- \MailSo\Imap\Enumerations\FolderType::DRAFTS,
- \MailSo\Imap\Enumerations\FolderType::JUNK,
- \MailSo\Imap\Enumerations\FolderType::TRASH,
- \MailSo\Imap\Enumerations\FolderType::ALL
- )))
- {
- $aResult[$iFolderType] = $oFolder->FullNameRaw();
- }
- }
- }
-
- foreach ($aFolders as $oFolder)
- {
- $oSub = $oFolder->SubFolders();
- if ($oSub && 0 < $oSub->Count())
- {
- $this->recFoldersTypes($oAccount, $oSub, $aResult, false);
- }
- }
- }
- }
- }
-
- /**
- * @return array
- */
- public function DoFolders()
- {
- $oAccount = $this->initMailClientConnection();
-
- $oFolderCollection = null;
- $this->Plugins()->RunHook('filter.folders-before', array($oAccount, &$oFolderCollection));
-
- $bUseFolders = $this->GetCapa(false, false, \RainLoop\Enumerations\Capa::FOLDERS, $oAccount);
-
- if (null === $oFolderCollection)
- {
- $oFolderCollection = $this->MailClient()->Folders('',
- $bUseFolders ? '*' : 'INBOX',
- !!$this->Config()->Get('labs', 'use_imap_list_subscribe', true),
- (int) $this->Config()->Get('labs', 'imap_folder_list_limit', 200)
- );
- }
-
- $this->Plugins()->RunHook('filter.folders-post', array($oAccount, &$oFolderCollection));
-
- if ($oFolderCollection instanceof \MailSo\Mail\FolderCollection)
- {
- $oSettingsLocal = $this->SettingsProvider(true)->Load($oAccount);
-
- $aSystemFolders = array();
- $this->recFoldersTypes($oAccount, $oFolderCollection, $aSystemFolders);
- $oFolderCollection->SystemFolders = $aSystemFolders;
-
- if ($bUseFolders && $this->Config()->Get('labs', 'autocreate_system_folders', true))
- {
- $bDoItAgain = false;
-
- $sNamespace = $oFolderCollection->GetNamespace();
- $sParent = empty($sNamespace) ? '' : \substr($sNamespace, 0, -1);
-
- $sDelimiter = $oFolderCollection->FindDelimiter();
-
- $aList = array();
- $aMap = $this->systemFoldersNames($oAccount);
-
- if ('' === $oSettingsLocal->GetConf('SentFolder', ''))
- {
- $aList[] = \MailSo\Imap\Enumerations\FolderType::SENT;
- }
-
- if ('' === $oSettingsLocal->GetConf('DraftFolder', ''))
- {
- $aList[] = \MailSo\Imap\Enumerations\FolderType::DRAFTS;
- }
-
- if ('' === $oSettingsLocal->GetConf('SpamFolder', ''))
- {
- $aList[] = \MailSo\Imap\Enumerations\FolderType::JUNK;
- }
-
- if ('' === $oSettingsLocal->GetConf('TrashFolder', ''))
- {
- $aList[] = \MailSo\Imap\Enumerations\FolderType::TRASH;
- }
-
- if ('' === $oSettingsLocal->GetConf('ArchiveFolder', ''))
- {
- $aList[] = \MailSo\Imap\Enumerations\FolderType::ALL;
- }
-
- $this->Plugins()->RunHook('filter.folders-system-types', array($oAccount, &$aList));
-
- foreach ($aList as $iType)
- {
- if (!isset($aSystemFolders[$iType]))
- {
- $mFolderNameToCreate = \array_search($iType, $aMap);
- if (!empty($mFolderNameToCreate))
- {
- $iPos = \strrpos($mFolderNameToCreate, $sDelimiter);
- if (false !== $iPos)
- {
- $mNewParent = \substr($mFolderNameToCreate, 0, $iPos);
- $mNewFolderNameToCreate = \substr($mFolderNameToCreate, $iPos + 1);
- if (0 < \strlen($mNewFolderNameToCreate))
- {
- $mFolderNameToCreate = $mNewFolderNameToCreate;
- }
-
- if (0 < \strlen($mNewParent))
- {
- $sParent = 0 < \strlen($sParent) ? $sParent.$sDelimiter.$mNewParent : $mNewParent;
- }
- }
-
- $sFullNameToCheck = \MailSo\Base\Utils::ConvertEncoding($mFolderNameToCreate,
- \MailSo\Base\Enumerations\Charset::UTF_8, \MailSo\Base\Enumerations\Charset::UTF_7_IMAP);
-
- if (0 < \strlen(\trim($sParent)))
- {
- $sFullNameToCheck = $sParent.$sDelimiter.$sFullNameToCheck;
- }
-
- if (!$oFolderCollection->GetByFullNameRaw($sFullNameToCheck))
- {
- try
- {
- if ($this->MailClient()->FolderCreate($mFolderNameToCreate, $sParent, true, $sDelimiter))
- {
- $bDoItAgain = true;
- }
- }
- catch (\Exception $oException)
- {
- $this->Logger()->WriteException($oException);
- }
- }
- }
- }
- }
-
- if ($bDoItAgain)
- {
- $oFolderCollection = $this->MailClient()->Folders('', '*',
- !!$this->Config()->Get('labs', 'use_imap_list_subscribe', true),
- (int) $this->Config()->Get('labs', 'imap_folder_list_limit', 200)
- );
-
- if ($oFolderCollection)
- {
- $aSystemFolders = array();
- $this->recFoldersTypes($oAccount, $oFolderCollection, $aSystemFolders);
- $oFolderCollection->SystemFolders = $aSystemFolders;
- }
- }
- }
-
- if ($oFolderCollection)
- {
- $oFolderCollection->FoldersHash = \md5(\implode("\x0", $this->recFoldersNames($oFolderCollection)));
- }
- }
-
- $this->Plugins()->RunHook('filter.folders-complete', array($oAccount, &$oFolderCollection));
-
- return $this->DefaultResponse(__FUNCTION__, $oFolderCollection);
- }
-
- /**
- * @return array
- */
- public function DoFolderCreate()
- {
- $oAccount = $this->initMailClientConnection();
-
- if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::FOLDERS, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- try
- {
- $sFolderNameInUtf = $this->GetActionParam('Folder', '');
- $sFolderParentFullNameRaw = $this->GetActionParam('Parent', '');
-
- $this->MailClient()->FolderCreate($sFolderNameInUtf, $sFolderParentFullNameRaw,
- !!$this->Config()->Get('labs', 'use_imap_list_subscribe', true));
- }
- catch (\Exception $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantCreateFolder, $oException);
- }
-
- return $this->TrueResponse(__FUNCTION__);
- }
-
- /**
- * @return array
- */
- public function DoFolderSubscribe()
- {
- $oAccount = $this->initMailClientConnection();
-
- if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::FOLDERS, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $sFolderFullNameRaw = $this->GetActionParam('Folder', '');
- $bSubscribe = '1' === (string) $this->GetActionParam('Subscribe', '0');
-
- try
- {
- $this->MailClient()->FolderSubscribe($sFolderFullNameRaw, !!$bSubscribe);
- }
- catch (\Exception $oException)
- {
- if ($bSubscribe)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantSubscribeFolder, $oException);
- }
- else
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantUnsubscribeFolder, $oException);
- }
- }
-
- return $this->TrueResponse(__FUNCTION__);
- }
-
- /**
- * @return array
- */
- public function DoFolderCheckable()
- {
- $oAccount = $this->getAccountFromToken();
-
- if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::FOLDERS, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $sFolderFullNameRaw = $this->GetActionParam('Folder', '');
- $bCheckable = '1' === (string) $this->GetActionParam('Checkable', '0');
-
- $oSettingsLocal = $this->SettingsProvider(true)->Load($oAccount);
-
- $sCheckableFolder = $oSettingsLocal->GetConf('CheckableFolder', '[]');
- $aCheckableFolder = @\json_decode($sCheckableFolder);
-
- if (!\is_array($aCheckableFolder))
- {
- $aCheckableFolder = array();
- }
-
- if ($bCheckable)
- {
- $aCheckableFolder[] = $sFolderFullNameRaw;
- }
- else
- {
- $aCheckableFolderNew = array();
- foreach ($aCheckableFolder as $sFolder)
- {
- if ($sFolder !== $sFolderFullNameRaw)
- {
- $aCheckableFolderNew[] = $sFolder;
- }
- }
- $aCheckableFolder = $aCheckableFolderNew;
- }
-
- $aCheckableFolder = \array_unique($aCheckableFolder);
-
- $oSettingsLocal->SetConf('CheckableFolder', @\json_encode($aCheckableFolder));
-
- return $this->DefaultResponse(__FUNCTION__,
- $this->SettingsProvider(true)->Save($oAccount, $oSettingsLocal));
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoFolderRename()
- {
- $oAccount = $this->initMailClientConnection();
-
- if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::FOLDERS, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $sPrevFolderFullNameRaw = $this->GetActionParam('Folder', '');
- $sNewTopFolderNameInUtf = $this->GetActionParam('NewFolderName', '');
-
- try
- {
- $this->MailClient()->FolderRename($sPrevFolderFullNameRaw, $sNewTopFolderNameInUtf,
- !!$this->Config()->Get('labs', 'use_imap_list_subscribe', true));
- }
- catch (\Exception $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantRenameFolder, $oException);
- }
-
- return $this->TrueResponse(__FUNCTION__);
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoFolderDelete()
- {
- $oAccount = $this->initMailClientConnection();
-
- if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::FOLDERS, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $sFolderFullNameRaw = $this->GetActionParam('Folder', '');
-
- try
- {
- $this->MailClient()->FolderDelete($sFolderFullNameRaw,
- !!$this->Config()->Get('labs', 'use_imap_list_subscribe', true));
- }
- catch (\MailSo\Mail\Exceptions\NonEmptyFolder $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantDeleteNonEmptyFolder, $oException);
- }
- catch (\Exception $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantDeleteFolder, $oException);
- }
-
- return $this->TrueResponse(__FUNCTION__);
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoFolderClear()
- {
- $this->initMailClientConnection();
-
- $sFolderFullNameRaw = $this->GetActionParam('Folder', '');
-
- try
- {
- $this->MailClient()->FolderClear($sFolderFullNameRaw);
- }
- catch (\Exception $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::MailServerError, $oException);
- }
-
- return $this->TrueResponse(__FUNCTION__);
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoFolderInformation()
- {
- $sFolder = $this->GetActionParam('Folder', '');
- $sPrevUidNext = $this->GetActionParam('UidNext', '');
- $aFlagsUids = array();
- $sFlagsUids = (string) $this->GetActionParam('FlagsUids', '');
-
- $aFlagsFilteredUids = array();
- if (0 < strlen($sFlagsUids))
- {
- $aFlagsUids = explode(',', $sFlagsUids);
- $aFlagsFilteredUids = array_filter($aFlagsUids, function (&$sUid) {
- $sUid = (int) trim($sUid);
- return 0 < (int) trim($sUid);
- });
- }
-
- $this->initMailClientConnection();
-
- $sForwardedFlag = $this->Config()->Get('labs', 'imap_forwarded_flag', '');
- $sReadReceiptFlag = $this->Config()->Get('labs', 'imap_read_receipt_flag', '');
- try
- {
- $aInboxInformation = $this->MailClient()->FolderInformation(
- $sFolder, $sPrevUidNext, $aFlagsFilteredUids
- );
-
- if (\is_array($aInboxInformation) && isset($aInboxInformation['Flags']) && \is_array($aInboxInformation['Flags']))
- {
- foreach ($aInboxInformation['Flags'] as $iUid => $aFlags)
- {
- $aLowerFlags = array_map('strtolower', $aFlags);
- $aInboxInformation['Flags'][$iUid] = array(
- 'IsSeen' => in_array('\\seen', $aLowerFlags),
- 'IsFlagged' => in_array('\\flagged', $aLowerFlags),
- 'IsAnswered' => in_array('\\answered', $aLowerFlags),
- 'IsDeleted' => in_array('\\deleted', $aLowerFlags),
- 'IsForwarded' => 0 < strlen($sForwardedFlag) && in_array(strtolower($sForwardedFlag), $aLowerFlags),
- 'IsReadReceipt' => 0 < strlen($sReadReceiptFlag) && in_array(strtolower($sReadReceiptFlag), $aLowerFlags)
- );
- }
- }
- }
- catch (\Exception $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::MailServerError, $oException);
- }
-
- if (\is_array($aInboxInformation))
- {
- $aInboxInformation['Version'] = APP_VERSION;
- }
-
- return $this->DefaultResponse(__FUNCTION__, $aInboxInformation);
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoFolderInformationMultiply()
- {
- $aResult = array(
- 'List' => array(),
- 'Version' => APP_VERSION
- );
-
- $aFolders = $this->GetActionParam('Folders', null);
- if (\is_array($aFolders))
- {
- $this->initMailClientConnection();
-
- $aFolders = \array_unique($aFolders);
- foreach ($aFolders as $sFolder)
- {
- if (0 < \strlen(\trim($sFolder)) && 'INBOX' !== \strtoupper($sFolder))
- {
- try
- {
- $aInboxInformation = $this->MailClient()->FolderInformation($sFolder, '', array());
- if (\is_array($aInboxInformation) && isset($aInboxInformation['Folder']))
- {
- $aResult['List'][] = $aInboxInformation;
- }
- }
- catch (\Exception $oException)
- {
- $this->Logger()->WriteException($oException);
- }
- }
- }
- }
-
- return $this->DefaultResponse(__FUNCTION__, $aResult);
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoMessageList()
- {
-// \sleep(1);
-// throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantGetMessageList);
-
- $sFolder = '';
- $iOffset = 0;
- $iLimit = 20;
- $sSearch = '';
- $sUidNext = '';
- $bUseThreads = false;
- $sThreadUid = '';
-
- $sRawKey = $this->GetActionParam('RawKey', '');
- $aValues = $this->getDecodedClientRawKeyValue($sRawKey, 9);
-
- if (\is_array($aValues) && 7 < \count($aValues))
- {
- $sFolder =(string) $aValues[0];
- $iOffset = (int) $aValues[1];
- $iLimit = (int) $aValues[2];
- $sSearch = (string) $aValues[3];
- $sUidNext = (string) $aValues[6];
- $bUseThreads = (bool) $aValues[7];
-
- if ($bUseThreads)
- {
- $sThreadUid = isset($aValues[8]) ? (string) $aValues[8] : '';
- }
-
- $this->verifyCacheByKey($sRawKey);
- }
- else
- {
- $sFolder = $this->GetActionParam('Folder', '');
- $iOffset = (int) $this->GetActionParam('Offset', 0);
- $iLimit = (int) $this->GetActionParam('Limit', 10);
- $sSearch = $this->GetActionParam('Search', '');
- $sUidNext = $this->GetActionParam('UidNext', '');
- $bUseThreads = '1' === (string) $this->GetActionParam('UseThreads', '0');
-
- if ($bUseThreads)
- {
- $sThreadUid = (string) $this->GetActionParam('ThreadUid', '');
- }
- }
-
- if (0 === strlen($sFolder))
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantGetMessageList);
- }
-
- $this->initMailClientConnection();
-
- try
- {
- if (!$this->Config()->Get('labs', 'use_imap_thread', false))
- {
- $bUseThreads = false;
- }
-
- $oMessageList = $this->MailClient()->MessageList(
- $sFolder, $iOffset, $iLimit, $sSearch, $sUidNext,
- $this->cacherForUids(),
- !!$this->Config()->Get('labs', 'use_imap_sort', false),
- $bUseThreads,
- $sThreadUid,
- ''
- );
- }
- catch (\Exception $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantGetMessageList, $oException);
- }
-
- if ($oMessageList instanceof \MailSo\Mail\MessageCollection)
- {
- $this->cacheByKey($sRawKey);
- }
-
- return $this->DefaultResponse(__FUNCTION__, $oMessageList);
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount
- * @param bool $bWithDraftInfo = true
- *
- * @return \MailSo\Mime\Message
- */
- private function buildMessage($oAccount, $bWithDraftInfo = true)
- {
- $sIdentityID = $this->GetActionParam('IdentityID', '');
- $sTo = $this->GetActionParam('To', '');
- $sCc = $this->GetActionParam('Cc', '');
- $sBcc = $this->GetActionParam('Bcc', '');
- $sReplyTo = $this->GetActionParam('ReplyTo', '');
- $sSubject = $this->GetActionParam('Subject', '');
- $bTextIsHtml = '1' === $this->GetActionParam('TextIsHtml', '0');
- $bReadReceiptRequest = '1' === $this->GetActionParam('ReadReceiptRequest', '0');
- $bMarkAsImportant = '1' === $this->GetActionParam('MarkAsImportant', '0');
- $sText = $this->GetActionParam('Text', '');
- $aAttachments = $this->GetActionParam('Attachments', null);
-
- $aDraftInfo = $this->GetActionParam('DraftInfo', null);
- $sInReplyTo = $this->GetActionParam('InReplyTo', '');
- $sReferences = $this->GetActionParam('References', '');
-
- $oMessage = \MailSo\Mime\Message::NewInstance();
-
- if (!$this->Config()->Get('security', 'hide_x_mailer_header', false))
- {
- $oMessage->SetXMailer('RainLoop/'.APP_VERSION);
- }
-
- $oFromIdentity = $this->GetIdentityByID($oAccount, $sIdentityID);
- if ($oFromIdentity)
- {
- $oMessage->SetFrom(\MailSo\Mime\Email::NewInstance(
- $oFromIdentity->Email(), $oFromIdentity->Name()));
- }
- else
- {
- $oMessage->SetFrom(\MailSo\Mime\Email::Parse($oAccount->Email()));
- }
-
- $oFrom = $oMessage->GetFrom();
- $oMessage->RegenerateMessageId($oFrom ? $oFrom->GetDomain() : '');
-
- if (!empty($sReplyTo))
- {
- $oReplyTo = \MailSo\Mime\EmailCollection::NewInstance($sReplyTo);
- if ($oReplyTo && 0 < $oReplyTo->Count())
- {
- $oMessage->SetReplyTo($oReplyTo);
- }
- }
-
- if ($bReadReceiptRequest)
- {
- $oMessage->SetReadReceipt($oAccount->Email());
- }
-
- if ($bMarkAsImportant)
- {
- $oMessage->SetPriority(\MailSo\Mime\Enumerations\MessagePriority::HIGH);
- }
-
- $oMessage->SetSubject($sSubject);
-
- $oToEmails = \MailSo\Mime\EmailCollection::NewInstance($sTo);
- if ($oToEmails && $oToEmails->Count())
- {
- $oMessage->SetTo($oToEmails);
- }
-
- $oCcEmails = \MailSo\Mime\EmailCollection::NewInstance($sCc);
- if ($oCcEmails && $oCcEmails->Count())
- {
- $oMessage->SetCc($oCcEmails);
- }
-
- $oBccEmails = \MailSo\Mime\EmailCollection::NewInstance($sBcc);
- if ($oBccEmails && $oBccEmails->Count())
- {
- $oMessage->SetBcc($oBccEmails);
- }
-
- if ($bWithDraftInfo && \is_array($aDraftInfo) && !empty($aDraftInfo[0]) && !empty($aDraftInfo[1]) && !empty($aDraftInfo[2]))
- {
- $oMessage->SetDraftInfo($aDraftInfo[0], $aDraftInfo[1], $aDraftInfo[2]);
- }
-
- if (0 < \strlen($sInReplyTo))
- {
- $oMessage->SetInReplyTo($sInReplyTo);
- }
-
- if (0 < \strlen($sReferences))
- {
- $oMessage->SetReferences($sReferences);
- }
-
- $aFoundedCids = array();
- $mFoundDataURL = array();
- $aFoundedContentLocationUrls = array();
-
- $sTextToAdd = $bTextIsHtml ?
- \MailSo\Base\HtmlUtils::BuildHtml($sText, $aFoundedCids, $mFoundDataURL, $aFoundedContentLocationUrls) : $sText;
-
- $this->Plugins()->RunHook($bTextIsHtml ? 'filter.message-html' : 'filter.message-plain',
- array($oAccount, &$oMessage, &$sTextToAdd));
-
- if ($bTextIsHtml && 0 < \strlen($sTextToAdd))
- {
- $sTextConverted = \MailSo\Base\HtmlUtils::ConvertHtmlToPlain($sTextToAdd);
- $this->Plugins()->RunHook('filter.message-plain', array($oAccount, &$oMessage, &$sTextConverted));
- $oMessage->AddText($sTextConverted, false);
- }
-
- $oMessage->AddText($sTextToAdd, $bTextIsHtml);
-
- if (\is_array($aAttachments))
- {
- foreach ($aAttachments as $sTempName => $aData)
- {
- $sFileName = (string) $aData[0];
- $bIsInline = (bool) $aData[1];
- $sCID = (string) $aData[2];
- $sContentLocation = isset($aData[3]) ? (string) $aData[3] : '';
-
- $rResource = $this->FilesProvider()->GetFile($oAccount, $sTempName);
- if (\is_resource($rResource))
- {
- $iFileSize = $this->FilesProvider()->FileSize($oAccount, $sTempName);
-
- $oMessage->Attachments()->Add(
- \MailSo\Mime\Attachment::NewInstance($rResource, $sFileName, $iFileSize, $bIsInline,
- \in_array(trim(trim($sCID), '<>'), $aFoundedCids),
- $sCID, array(), $sContentLocation
- )
- );
- }
- }
- }
-
- if ($mFoundDataURL && \is_array($mFoundDataURL) && 0 < \count($mFoundDataURL))
- {
- foreach ($mFoundDataURL as $sCidHash => $sDataUrlString)
- {
- $aMatch = array();
- $sCID = '<'.$sCidHash.'>';
- if (\preg_match('/^data:(image\/[a-zA-Z0-9]+);base64,(.+)$/i', $sDataUrlString, $aMatch) &&
- !empty($aMatch[1]) && !empty($aMatch[2]))
- {
- $sRaw = \MailSo\Base\Utils::Base64Decode($aMatch[2]);
- $iFileSize = \strlen($sRaw);
- if (0 < $iFileSize)
- {
- $sFileName = \preg_replace('/[^a-z0-9]+/i', '.', $aMatch[1]);
- $rResource = \MailSo\Base\ResourceRegistry::CreateMemoryResourceFromString($sRaw);
-
- $sRaw = '';
- unset($sRaw);
- unset($aMatch);
-
- $oMessage->Attachments()->Add(
- \MailSo\Mime\Attachment::NewInstance($rResource, $sFileName, $iFileSize, true, true, $sCID)
- );
- }
- }
- }
- }
-
- $this->Plugins()->RunHook('filter.build-message', array(&$oMessage));
- $this->Plugins()->RunHook('filter.build-message[2]', array(&$oMessage, $oAccount));
-
- return $oMessage;
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount
- *
- * @return void
- */
- private function deleteMessageAttachmnets($oAccount)
- {
- $aAttachments = $this->GetActionParam('Attachments', null);
-
- if (\is_array($aAttachments))
- {
- foreach (\array_keys($aAttachments) as $sTempName)
- {
- if ($this->FilesProvider()->FileExists($oAccount, $sTempName))
- {
- $this->FilesProvider()->Clear($oAccount, $sTempName);
- }
- }
- }
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount
- *
- * @return \MailSo\Mime\Message
- */
- private function buildReadReceiptMessage($oAccount)
- {
- $sReadReceipt = $this->GetActionParam('ReadReceipt', '');
- $sSubject = $this->GetActionParam('Subject', '');
- $sText = $this->GetActionParam('Text', '');
-
- $oIdentity = $this->GetAccountIdentity($oAccount);
-
- if (empty($sReadReceipt) || empty($sSubject) || empty($sText) || !$oIdentity)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::UnknownError);
- }
-
- $oMessage = \MailSo\Mime\Message::NewInstance();
-
- if (!$this->Config()->Get('security', 'hide_x_mailer_header', false))
- {
- $oMessage->SetXMailer('RainLoop/'.APP_VERSION);
- }
-
- $oMessage->SetFrom(\MailSo\Mime\Email::NewInstance($oIdentity->Email(), $oIdentity->Name()));
-
- $oFrom = $oMessage->GetFrom();
- $oMessage->RegenerateMessageId($oFrom ? $oFrom->GetDomain() : '');
-
- $sReplyTo = $oIdentity->ReplyTo();
- if (!empty($sReplyTo))
- {
- $oReplyTo = \MailSo\Mime\EmailCollection::NewInstance($sReplyTo);
- if ($oReplyTo && $oReplyTo->Count())
- {
- $oMessage->SetReplyTo($oReplyTo);
- }
- }
-
- $oMessage->SetSubject($sSubject);
-
- $oToEmails = \MailSo\Mime\EmailCollection::NewInstance($sReadReceipt);
- if ($oToEmails && $oToEmails->Count())
- {
- $oMessage->SetTo($oToEmails);
- }
-
- $this->Plugins()->RunHook('filter.read-receipt-message-plain', array($oAccount, &$oMessage, &$sText));
-
- $oMessage->AddText($sText, false);
-
- $this->Plugins()->RunHook('filter.build-read-receipt-message', array(&$oMessage, $oAccount));
-
- return $oMessage;
- }
-
- /**
- * @return array
- */
- public function DoSaveMessage()
- {
- $oAccount = $this->initMailClientConnection();
-
- if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::COMPOSER, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $sMessageFolder = $this->GetActionParam('MessageFolder', '');
- $sMessageUid = $this->GetActionParam('MessageUid', '');
-
- $sDraftFolder = $this->GetActionParam('DraftFolder', '');
- if (0 === strlen($sDraftFolder))
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::UnknownError);
- }
-
- $oMessage = $this->buildMessage($oAccount, true);
-
- $this->Plugins()
- ->RunHook('filter.save-message', array(&$oMessage))
- ->RunHook('filter.save-message[2]', array(&$oMessage, $oAccount))
- ;
-
- $mResult = false;
- if ($oMessage)
- {
- $rMessageStream = \MailSo\Base\ResourceRegistry::CreateMemoryResource();
-
- $iMessageStreamSize = \MailSo\Base\Utils::MultipleStreamWriter(
- $oMessage->ToStream(false), array($rMessageStream), 8192, true, true);
-
- if (false !== $iMessageStreamSize)
- {
- $sMessageId = $oMessage->MessageId();
-
- \rewind($rMessageStream);
-
- $iNewUid = 0;
- $this->MailClient()->MessageAppendStream(
- $rMessageStream, $iMessageStreamSize, $sDraftFolder, array(
- \MailSo\Imap\Enumerations\MessageFlag::SEEN
- ), $iNewUid);
-
- if (!empty($sMessageId) && (null === $iNewUid || 0 === $iNewUid))
- {
- $iNewUid = $this->MailClient()->FindMessageUidByMessageId($sDraftFolder, $sMessageId);
- }
-
- $mResult = true;
-
- if (0 < strlen($sMessageFolder) && 0 < strlen($sMessageUid))
- {
- $this->MailClient()->MessageDelete($sMessageFolder, array($sMessageUid), true, true);
- }
-
- if (null !== $iNewUid && 0 < $iNewUid)
- {
- $mResult = array(
- 'NewFolder' => $sDraftFolder,
- 'NewUid' => $iNewUid
- );
- }
- }
- }
-
- return $this->DefaultResponse(__FUNCTION__, $mResult);
- }
-
- /**
- *
- * @param \RainLoop\Model\Account $oAccount
- * @param \MailSo\Mime\Message $oMessage
- * @param resource $rMessageStream
- * @param bool $bDsn = false
- * @param bool $bAddHiddenRcpt = true
- *
- * @throws \RainLoop\Exceptions\ClientException
- * @throws \MailSo\Net\Exceptions\ConnectionException
- */
- private function smtpSendMessage($oAccount, $oMessage,
- &$rMessageStream, &$iMessageStreamSize, $bDsn = false, $bAddHiddenRcpt = true)
- {
- $oRcpt = $oMessage->GetRcpt();
- if ($oRcpt && 0 < $oRcpt->Count())
- {
- $this->Plugins()->RunHook('filter.smtp-message-stream',
- array($oAccount, &$rMessageStream, &$iMessageStreamSize));
-
- $this->Plugins()->RunHook('filter.message-rcpt', array($oAccount, &$oRcpt));
-
- try
- {
- $oFrom = $oMessage->GetFrom();
- $sFrom = $oFrom instanceof \MailSo\Mime\Email ? $oFrom->GetEmail() : '';
- $sFrom = empty($sFrom) ? $oAccount->Email() : $sFrom;
-
- $this->Plugins()->RunHook('filter.smtp-from', array($oAccount, $oMessage, &$sFrom));
-
- $aHiddenRcpt = array();
- if ($bAddHiddenRcpt)
- {
- $this->Plugins()->RunHook('filter.smtp-hidden-rcpt', array($oAccount, $oMessage, &$aHiddenRcpt));
- }
-
- $bUsePhpMail = $oAccount->Domain()->OutUsePhpMail();
-
- $oSmtpClient = \MailSo\Smtp\SmtpClient::NewInstance()->SetLogger($this->Logger());
- $oSmtpClient->SetTimeOuts(10, (int) \RainLoop\Api::Config()->Get('labs', 'smtp_timeout', 60));
-
- $bLoggined = $oAccount->OutConnectAndLoginHelper($this->Plugins(), $oSmtpClient, $this->Config(), $bUsePhpMail);
-
- if ($bUsePhpMail)
- {
- if (\MailSo\Base\Utils::FunctionExistsAndEnabled('mail'))
- {
- $aToCollection = $oMessage->GetTo();
- if ($aToCollection && $oFrom)
- {
- $sRawBody = @\stream_get_contents($rMessageStream);
- if (!empty($sRawBody))
- {
- $sMailTo = \trim($aToCollection->ToString(true));
- $sMailSubject = \trim($oMessage->GetSubject());
- $sMailSubject = 0 === \strlen($sMailSubject) ? '' : \MailSo\Base\Utils::EncodeUnencodedValue(
- \MailSo\Base\Enumerations\Encoding::BASE64_SHORT, $sMailSubject);
-
- $sMailHeaders = $sMailBody = '';
- list($sMailHeaders, $sMailBody) = \explode("\r\n\r\n", $sRawBody, 2);
- unset($sRawBody);
-
- if ($this->Config()->Get('labs', 'mail_func_clear_headers', true))
- {
- $sMailHeaders = \MailSo\Base\Utils::RemoveHeaderFromHeaders($sMailHeaders, array(
- \MailSo\Mime\Enumerations\Header::TO_,
- \MailSo\Mime\Enumerations\Header::SUBJECT
- ));
- }
-
- if ($this->Config()->Get('debug', 'enable', false))
- {
- $this->Logger()->WriteDump(array(
- $sMailTo, $sMailSubject, $sMailBody, $sMailHeaders
- ));
- }
-
- $bR = $this->Config()->Get('labs', 'mail_func_additional_parameters', false) ?
- \mail($sMailTo, $sMailSubject, $sMailBody, $sMailHeaders, '-f'.$oFrom->GetEmail()) :
- \mail($sMailTo, $sMailSubject, $sMailBody, $sMailHeaders);
-
- if (!$bR)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantSendMessage);
- }
- }
- }
- }
- else
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantSendMessage);
- }
- }
- else if ($oSmtpClient->IsConnected())
- {
- if (!empty($sFrom))
- {
- $oSmtpClient->MailFrom($sFrom, '', $bDsn);
- }
-
- $aRcpt =& $oRcpt->GetAsArray();
- foreach ($aRcpt as /* @var $oEmail \MailSo\Mime\Email */ $oEmail)
- {
- $oSmtpClient->Rcpt($oEmail->GetEmail(), $bDsn);
- }
-
- if ($bAddHiddenRcpt && \is_array($aHiddenRcpt) && 0 < \count($aHiddenRcpt))
- {
- foreach ($aHiddenRcpt as $sEmail)
- {
- if (\preg_match('/^[^@\s]+@[^@\s]+$/', $sEmail))
- {
- $oSmtpClient->Rcpt($sEmail);
- }
- }
- }
-
- $oSmtpClient->DataWithStream($rMessageStream);
-
- if ($bLoggined)
- {
- $oSmtpClient->Logout();
- }
-
- $oSmtpClient->Disconnect();
- }
- }
- catch (\MailSo\Net\Exceptions\ConnectionException $oException)
- {
- if ($this->Config()->Get('labs', 'smtp_show_server_errors'))
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::ClientViewError, $oException);
- }
- else
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::ConnectionError, $oException);
- }
- }
- catch (\MailSo\Smtp\Exceptions\LoginException $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError, $oException);
- }
- catch (\Exception $oException)
- {
- if ($this->Config()->Get('labs', 'smtp_show_server_errors'))
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::ClientViewError, $oException);
- }
- else
- {
- throw $oException;
- }
- }
- }
- else
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::InvalidRecipients);
- }
- }
-
- /**
- * @return array
- */
- public function DoSendMessage()
- {
- $oAccount = $this->initMailClientConnection();
-
- if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::COMPOSER, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $oConfig = $this->Config();
-
- $sDraftFolder = $this->GetActionParam('MessageFolder', '');
- $sDraftUid = $this->GetActionParam('MessageUid', '');
- $sSentFolder = $this->GetActionParam('SentFolder', '');
- $aDraftInfo = $this->GetActionParam('DraftInfo', null);
- $bDsn = '1' === (string) $this->GetActionParam('Dsn', '0');
-
- $oMessage = $this->buildMessage($oAccount, false);
-
- $this->Plugins()
- ->RunHook('filter.send-message', array(&$oMessage))
- ->RunHook('filter.send-message[2]', array(&$oMessage, $oAccount))
- ;
-
- $mResult = false;
- try
- {
- if ($oMessage)
- {
- $rMessageStream = \MailSo\Base\ResourceRegistry::CreateMemoryResource();
-
- $iMessageStreamSize = \MailSo\Base\Utils::MultipleStreamWriter(
- $oMessage->ToStream(true), array($rMessageStream), 8192, true, true, true);
-
- if (false !== $iMessageStreamSize)
- {
- $this->smtpSendMessage($oAccount, $oMessage, $rMessageStream, $iMessageStreamSize, $bDsn, true);
-
- if (\is_array($aDraftInfo) && 3 === \count($aDraftInfo))
- {
- $sDraftInfoType = $aDraftInfo[0];
- $sDraftInfoUid = $aDraftInfo[1];
- $sDraftInfoFolder = $aDraftInfo[2];
-
- try
- {
- switch (\strtolower($sDraftInfoType))
- {
- case 'reply':
- case 'reply-all':
- $this->MailClient()->MessageSetFlag($sDraftInfoFolder, array($sDraftInfoUid), true,
- \MailSo\Imap\Enumerations\MessageFlag::ANSWERED, true);
- break;
- case 'forward':
- $sForwardedFlag = $this->Config()->Get('labs', 'imap_forwarded_flag', '');
- if (0 < strlen($sForwardedFlag))
- {
- $this->MailClient()->MessageSetFlag($sDraftInfoFolder, array($sDraftInfoUid), true,
- $sForwardedFlag, true);
- }
- break;
- }
- }
- catch (\Exception $oException)
- {
- $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
- }
- }
-
- if (0 < \strlen($sSentFolder))
- {
- try
- {
- if (!$oMessage->GetBcc())
- {
- if (\is_resource($rMessageStream))
- {
- \rewind($rMessageStream);
- }
-
- $this->Plugins()->RunHook('filter.sent-message-stream',
- array($oAccount, &$rMessageStream, &$iMessageStreamSize));
-
- $this->MailClient()->MessageAppendStream(
- $rMessageStream, $iMessageStreamSize, $sSentFolder, array(
- \MailSo\Imap\Enumerations\MessageFlag::SEEN
- )
- );
- }
- else
- {
- $rAppendMessageStream = \MailSo\Base\ResourceRegistry::CreateMemoryResource();
-
- $iAppendMessageStreamSize = \MailSo\Base\Utils::MultipleStreamWriter(
- $oMessage->ToStream(false), array($rAppendMessageStream), 8192, true, true, true);
-
- $this->Plugins()->RunHook('filter.sent-message-stream',
- array($oAccount, &$rAppendMessageStream, &$iAppendMessageStreamSize));
-
- $this->MailClient()->MessageAppendStream(
- $rAppendMessageStream, $iAppendMessageStreamSize, $sSentFolder, array(
- \MailSo\Imap\Enumerations\MessageFlag::SEEN
- ));
-
- if (\is_resource($rAppendMessageStream))
- {
- @fclose($rAppendMessageStream);
- }
- }
- }
- catch (\Exception $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantSaveMessage, $oException);
- }
- }
-
- if (\is_resource($rMessageStream))
- {
- @\fclose($rMessageStream);
- }
-
- $this->deleteMessageAttachmnets($oAccount);
-
- if (0 < \strlen($sDraftFolder) && 0 < \strlen($sDraftUid))
- {
- try
- {
- $this->MailClient()->MessageDelete($sDraftFolder, array($sDraftUid), true, true);
- }
- catch (\Exception $oException)
- {
- $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
- }
- }
-
- $mResult = true;
- }
- }
- }
- catch (\RainLoop\Exceptions\ClientException $oException)
- {
- throw $oException;
- }
- catch (\Exception $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantSendMessage, $oException);
- }
-
- if (false === $mResult)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantSendMessage);
- }
-
- try
- {
- if ($oMessage && $this->AddressBookProvider($oAccount)->IsActive())
- {
- $aArrayToFrec = array();
- $oToCollection = $oMessage->GetTo();
- if ($oToCollection)
- {
- $aTo =& $oToCollection->GetAsArray();
- foreach ($aTo as /* @var $oEmail \MailSo\Mime\Email */ $oEmail)
- {
- $aArrayToFrec[$oEmail->GetEmail(true)] = $oEmail->ToString(false, true);
- }
- }
-
- if (0 < \count($aArrayToFrec))
- {
- $oSettings = $this->SettingsProvider()->Load($oAccount);
-
- $this->AddressBookProvider($oAccount)->IncFrec(
- $oAccount->ParentEmailHelper(), \array_values($aArrayToFrec),
- !!$oSettings->GetConf('ContactsAutosave',
- !!$oConfig->Get('defaults', 'contacts_autosave', true)));
- }
- }
- }
- catch (\Exception $oException)
- {
- $this->Logger()->WriteException($oException);
- }
-
- return $this->TrueResponse(__FUNCTION__);
- }
-
- /**
- * @return array
- */
- public function DoSendReadReceiptMessage()
- {
- $oAccount = $this->initMailClientConnection();
-
- if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::COMPOSER, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $oMessage = $this->buildReadReceiptMessage($oAccount);
-
- $this->Plugins()->RunHook('filter.send-read-receipt-message', array(&$oMessage, $oAccount));
-
- $mResult = false;
- try
- {
- if ($oMessage)
- {
- $rMessageStream = \MailSo\Base\ResourceRegistry::CreateMemoryResource();
-
- $iMessageStreamSize = \MailSo\Base\Utils::MultipleStreamWriter(
- $oMessage->ToStream(true), array($rMessageStream), 8192, true, true, true);
-
- if (false !== $iMessageStreamSize)
- {
- $this->smtpSendMessage($oAccount, $oMessage, $rMessageStream, $iMessageStreamSize, false, false);
-
- if (\is_resource($rMessageStream))
- {
- @\fclose($rMessageStream);
- }
-
- $mResult = true;
-
- $sReadReceiptFlag = $this->Config()->Get('labs', 'imap_read_receipt_flag', '');
- if (!empty($sReadReceiptFlag))
- {
- $sFolderFullName = $this->GetActionParam('MessageFolder', '');
- $sUid = $this->GetActionParam('MessageUid', '');
-
- $this->Cacher($oAccount)->Set(\RainLoop\KeyPathHelper::ReadReceiptCache($oAccount->Email(), $sFolderFullName, $sUid), '1');
-
- if (0 < \strlen($sFolderFullName) && 0 < \strlen($sUid))
- {
- try
- {
- $this->MailClient()->MessageSetFlag($sFolderFullName, array($sUid), true, $sReadReceiptFlag, true, true);
- }
- catch (\Exception $oException) {}
- }
- }
- }
- }
- }
- catch (\RainLoop\Exceptions\ClientException $oException)
- {
- throw $oException;
- }
- catch (\Exception $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantSendMessage, $oException);
- }
-
- if (false === $mResult)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantSendMessage);
- }
-
- return $this->TrueResponse(__FUNCTION__);
- }
-
- /**
- * @return array
- */
- public function DoQuota()
- {
- $oAccount = $this->initMailClientConnection();
-
- if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::QUOTA, $oAccount))
- {
- return $this->DefaultResponse(__FUNCTION__, array(0, 0, 0, 0));
- }
-
- try
- {
- $aQuota = $this->MailClient()->Quota();
- }
- catch (\Exception $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::MailServerError, $oException);
- }
-
- return $this->DefaultResponse(__FUNCTION__, $aQuota);
- }
-
- private function getContactsSyncData($oAccount)
- {
- $mResult = null;
-
- $sData = $this->StorageProvider()->Get($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'contacts_sync'
- );
-
- if (!empty($sData))
- {
- $mData = \RainLoop\Utils::DecodeKeyValues($sData);
- if (\is_array($mData))
- {
- $mResult = array(
- 'Enable' => isset($mData['Enable']) ? !!$mData['Enable'] : false,
- 'Url' => isset($mData['Url']) ? \trim($mData['Url']) : '',
- 'User' => isset($mData['User']) ? \trim($mData['User']) : '',
- 'Password' => isset($mData['Password']) ? $mData['Password'] : ''
- );
- }
- }
-
- return $mResult;
- }
-
- /**
- * @return array
- */
- public function DoSaveContactsSyncData()
- {
- $oAccount = $this->getAccountFromToken();
-
- $oAddressBookProvider = $this->AddressBookProvider($oAccount);
- if (!$oAddressBookProvider || !$oAddressBookProvider->IsActive())
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $bEnabled = '1' === (string) $this->GetActionParam('Enable', '0');
- $sUrl = $this->GetActionParam('Url', '');
- $sUser = $this->GetActionParam('User', '');
- $sPassword = $this->GetActionParam('Password', '');
-
- $mData = $this->getContactsSyncData($oAccount);
-
- $bResult = $this->StorageProvider()->Put($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'contacts_sync',
- \RainLoop\Utils::EncodeKeyValues(array(
- 'Enable' => $bEnabled,
- 'User' => $sUser,
- 'Password' => APP_DUMMY === $sPassword && isset($mData['Password']) ?
- $mData['Password'] : (APP_DUMMY === $sPassword ? '' : $sPassword),
- 'Url' => $sUrl
- ))
- );
-
- return $this->DefaultResponse(__FUNCTION__, $bResult);
- }
-
- /**
- * @return array
- */
- public function DoContactsSync()
- {
- $bResult = false;
- $oAccount = $this->getAccountFromToken();
-
- $oAddressBookProvider = $this->AddressBookProvider($oAccount);
- if ($oAddressBookProvider && $oAddressBookProvider->IsActive())
- {
- $mData = $this->getContactsSyncData($oAccount);
- if (\is_array($mData) && isset($mData['Enable'], $mData['User'], $mData['Password'], $mData['Url']) && $mData['Enable'])
- {
- $bResult = $oAddressBookProvider->Sync(
- $oAccount->ParentEmailHelper(),
- $mData['Url'], $mData['User'], $mData['Password']);
- }
- }
-
- if (!$bResult)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::ContactsSyncError);
- }
-
- return $this->TrueResponse(__FUNCTION__);
- }
-
- private function getTwoFactorInfo($oAccount, $bRemoveSecret = false)
- {
- $sEmail = $oAccount->ParentEmailHelper();
-
- $mData = null;
-
- $aResult = array(
- 'User' => '',
- 'IsSet' => false,
- 'Enable' => false,
- 'Secret' => '',
- 'UrlTitle' => '',
- 'BackupCodes' => ''
- );
-
- if (!empty($sEmail))
- {
- $aResult['User'] = $sEmail;
-
- $sData = $this->StorageProvider()->Get($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'two_factor'
- );
-
- if ($sData)
- {
- $mData = \RainLoop\Utils::DecodeKeyValues($sData);
- }
- }
-
- if (\is_array($mData) && !empty($aResult['User']) &&
- !empty($mData['User']) && !empty($mData['Secret']) &&
- !empty($mData['BackupCodes']) && $sEmail === $mData['User'])
- {
- $aResult['IsSet'] = true;
- $aResult['Enable'] = isset($mData['Enable']) ? !!$mData['Enable'] : false;
- $aResult['Secret'] = $mData['Secret'];
- $aResult['BackupCodes'] = $mData['BackupCodes'];
- $aResult['UrlTitle'] = $this->Config()->Get('webmail', 'title', '');
- }
-
- if ($bRemoveSecret)
- {
- if (isset($aResult['Secret']))
- {
- unset($aResult['Secret']);
- }
-
- if (isset($aResult['UrlTitle']))
- {
- unset($aResult['UrlTitle']);
- }
-
- if (isset($aResult['BackupCodes']))
- {
- unset($aResult['BackupCodes']);
- }
- }
-
- return $aResult;
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount
- * @param string $sCode
- *
- * @return bool
- */
- private function removeBackupCodeFromTwoFactorInfo($oAccount, $sCode)
- {
- if (!$oAccount || empty($sCode))
- {
- return false;
- }
-
- $sData = $this->StorageProvider()->Get($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'two_factor'
- );
-
- if ($sData)
- {
- $mData = \RainLoop\Utils::DecodeKeyValues($sData);
-
- if (!empty($mData['BackupCodes']))
- {
- $sBackupCodes = \preg_replace('/[^\d]+/', ' ', ' '.$mData['BackupCodes'].' ');
- $sBackupCodes = \str_replace(' '.$sCode.' ', '', $sBackupCodes);
-
- $mData['BackupCodes'] = \trim(\preg_replace('/[^\d]+/', ' ', $sBackupCodes));
-
- return $this->StorageProvider()->Put($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'two_factor',
- \RainLoop\Utils::EncodeKeyValues($mData)
- );
- }
- }
-
- return false;
- }
-
- /**
- * @return array
- */
- public function DoGetTwoFactorInfo()
- {
- $oAccount = $this->getAccountFromToken();
-
- if (!$this->TwoFactorAuthProvider()->IsActive() ||
- !$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::TWO_FACTOR, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- return $this->DefaultResponse(__FUNCTION__,
- $this->getTwoFactorInfo($oAccount, true));
- }
-
- /**
- * @return array
- */
- public function DoCreateTwoFactorSecret()
- {
- $oAccount = $this->getAccountFromToken();
-
- if (!$this->TwoFactorAuthProvider()->IsActive() ||
- !$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::TWO_FACTOR, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $sEmail = $oAccount->ParentEmailHelper();
-
- $sSecret = $this->TwoFactorAuthProvider()->CreateSecret();
-
- $aCodes = array();
- for ($iIndex = 9; $iIndex > 0; $iIndex--)
- {
- $aCodes[] = \rand(100000000, 900000000);
- }
-
- $this->StorageProvider()->Put($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'two_factor',
- \RainLoop\Utils::EncodeKeyValues(array(
- 'User' => $sEmail,
- 'Enable' => false,
- 'Secret' => $sSecret,
- 'BackupCodes' => \implode(' ', $aCodes)
- ))
- );
-
- $this->requestSleep();
-
- return $this->DefaultResponse(__FUNCTION__,
- $this->getTwoFactorInfo($oAccount));
- }
-
- /**
- * @return array
- */
- public function DoShowTwoFactorSecret()
- {
- $oAccount = $this->getAccountFromToken();
-
- if (!$this->TwoFactorAuthProvider()->IsActive() ||
- !$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::TWO_FACTOR, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $aResult = $this->getTwoFactorInfo($oAccount);
- if (\is_array($aResult))
- {
- unset($aResult['BackupCodes']);
- }
-
- return $this->DefaultResponse(__FUNCTION__, $aResult);
- }
-
- /**
- * @return array
- */
- public function DoEnableTwoFactor()
- {
- $oAccount = $this->getAccountFromToken();
-
- if (!$this->TwoFactorAuthProvider()->IsActive() ||
- !$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::TWO_FACTOR, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $sEmail = $oAccount->ParentEmailHelper();
-
- $bResult = false;
- $mData = $this->getTwoFactorInfo($oAccount);
- if (isset($mData['Secret'], $mData['BackupCodes']))
- {
- $bResult = $this->StorageProvider()->Put($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'two_factor',
- \RainLoop\Utils::EncodeKeyValues(array(
- 'User' => $sEmail,
- 'Enable' => '1' === \trim($this->GetActionParam('Enable', '0')),
- 'Secret' => $mData['Secret'],
- 'BackupCodes' => $mData['BackupCodes']
- ))
- );
- }
-
- return $this->DefaultResponse(__FUNCTION__, $bResult);
- }
-
- /**
- * @return array
- */
- public function DoTestTwoFactorInfo()
- {
- $oAccount = $this->getAccountFromToken();
-
- if (!$this->TwoFactorAuthProvider()->IsActive() ||
- !$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::TWO_FACTOR, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $sCode = \trim($this->GetActionParam('Code', ''));
-
- $aData = $this->getTwoFactorInfo($oAccount);
- $sSecret = !empty($aData['Secret']) ? $aData['Secret'] : '';
-
-// $this->Logger()->WriteDump(array(
-// $sCode, $sSecret, $aData,
-// $this->TwoFactorAuthProvider()->VerifyCode($sSecret, $sCode)
-// ));
-
- $this->requestSleep();
-
- return $this->DefaultResponse(__FUNCTION__,
- $this->TwoFactorAuthProvider()->VerifyCode($sSecret, $sCode));
- }
-
- /**
- * @return array
- */
- public function DoClearTwoFactorInfo()
- {
- $oAccount = $this->getAccountFromToken();
-
- if (!$this->TwoFactorAuthProvider()->IsActive() ||
- !$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::TWO_FACTOR, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $this->StorageProvider()->Clear($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'two_factor'
- );
-
- return $this->DefaultResponse(__FUNCTION__,
- $this->getTwoFactorInfo($oAccount, true));
- }
-
- /**
- * @return array
- */
- public function DoContacts()
- {
- $oAccount = $this->getAccountFromToken();
-
- $sSearch = \trim($this->GetActionParam('Search', ''));
- $iOffset = (int) $this->GetActionParam('Offset', 0);
- $iLimit = (int) $this->GetActionParam('Limit', 20);
- $iOffset = 0 > $iOffset ? 0 : $iOffset;
- $iLimit = 0 > $iLimit ? 20 : $iLimit;
-
- $iResultCount = 0;
- $mResult = array();
-
- $oAbp = $this->AddressBookProvider($oAccount);
- if ($oAbp->IsActive())
- {
- $iResultCount = 0;
- $mResult = $oAbp->GetContacts($oAccount->ParentEmailHelper(),
- $iOffset, $iLimit, $sSearch, $iResultCount);
- }
-
- return $this->DefaultResponse(__FUNCTION__, array(
- 'Offset' => $iOffset,
- 'Limit' => $iLimit,
- 'Count' => $iResultCount,
- 'Search' => $sSearch,
- 'List' => $mResult
- ));
- }
-
- /**
- * @return array
- */
- public function DoContactsDelete()
- {
- $oAccount = $this->getAccountFromToken();
- $aUids = \explode(',', (string) $this->GetActionParam('Uids', ''));
-
- $aFilteredUids = \array_filter($aUids, function (&$mUid) {
- $mUid = (int) \trim($mUid);
- return 0 < $mUid;
- });
-
- $bResult = false;
- if (0 < \count($aFilteredUids) && $this->AddressBookProvider($oAccount)->IsActive())
- {
- $bResult = $this->AddressBookProvider($oAccount)->DeleteContacts($oAccount->ParentEmailHelper(), $aFilteredUids);
- }
-
- return $this->DefaultResponse(__FUNCTION__, $bResult);
- }
-
- /**
- * @return array
- */
- public function DoContactSave()
- {
- $oAccount = $this->getAccountFromToken();
-
- $bResult = false;
-
- $oAddressBookProvider = $this->AddressBookProvider($oAccount);
- $sRequestUid = \trim($this->GetActionParam('RequestUid', ''));
- if ($oAddressBookProvider && $oAddressBookProvider->IsActive() && 0 < \strlen($sRequestUid))
- {
- $sUid = \trim($this->GetActionParam('Uid', ''));
-
- $oContact = null;
- if (0 < \strlen($sUid))
- {
- $oContact = $oAddressBookProvider->GetContactByID($oAccount->ParentEmailHelper(), $sUid);
- }
-
- if (!$oContact)
- {
- $oContact = new \RainLoop\Providers\AddressBook\Classes\Contact();
- if (0 < \strlen($sUid))
- {
- $oContact->IdContact = $sUid;
- }
- }
-
- $oContact->Properties = array();
- $aProperties = $this->GetActionParam('Properties', array());
- if (\is_array($aProperties))
- {
- foreach ($aProperties as $aItem)
- {
- if ($aItem && isset($aItem[0], $aItem[1]) && \is_numeric($aItem[0]))
- {
- $oProp = new \RainLoop\Providers\AddressBook\Classes\Property();
- $oProp->Type = (int) $aItem[0];
- $oProp->Value = $aItem[1];
- $oProp->TypeStr = empty($aItem[2]) ? '': $aItem[2];
-
- $oContact->Properties[] = $oProp;
- }
- }
- }
-
- if (!empty($oContact->Etag))
- {
- $oContact->Etag = \md5($oContact->ToVCard());
- }
-
- $oContact->PopulateDisplayAndFullNameValue(true);
-
- $bResult = $oAddressBookProvider->ContactSave($oAccount->ParentEmailHelper(), $oContact);
- }
-
- return $this->DefaultResponse(__FUNCTION__, array(
- 'RequestUid' => $sRequestUid,
- 'ResultID' => $bResult ? $oContact->IdContact : '',
- 'Result' => $bResult
- ));
- }
-
- /**
- * @return array
- */
- public function DoSuggestions()
- {
- $oAccount = $this->getAccountFromToken();
-
- $sQuery = \trim($this->GetActionParam('Query', ''));
- $iLimit = (int) $this->Config()->Get('contacts', 'suggestions_limit', 20);
-
- $aResult = array();
-
- $this->Plugins()->RunHook('ajax.suggestions-input-parameters', array(&$sQuery, &$iLimit, $oAccount));
-
- $iLimit = (int) $iLimit;
- if (5 > $iLimit)
- {
- $iLimit = 5;
- }
-
- $this->Plugins()->RunHook('ajax.suggestions-pre', array(&$aResult, $sQuery, $oAccount, $iLimit));
-
- if ($iLimit > \count($aResult) && 0 < \strlen($sQuery))
- {
- try
- {
- // Address Book
- $oAddressBookProvider = $this->AddressBookProvider($oAccount);
- if ($oAddressBookProvider && $oAddressBookProvider->IsActive())
- {
- $aSuggestions = $oAddressBookProvider->GetSuggestions($oAccount->ParentEmailHelper(), $sQuery, $iLimit);
- if (0 === \count($aResult))
- {
- $aResult = $aSuggestions;
- }
- else
- {
- $aResult = \array_merge($aResult, $aSuggestions);
- }
- }
- }
- catch (\Exception $oException)
- {
- $this->Logger()->WriteException($oException);
- }
- }
-
- if ($iLimit > \count($aResult) && 0 < \strlen($sQuery))
- {
- $oSuggestionsProvider = $this->SuggestionsProvider();
- if ($oSuggestionsProvider && $oSuggestionsProvider->IsActive())
- {
- $aSuggestionsProviderResult = $oSuggestionsProvider->Process($oAccount, $sQuery, $iLimit);
- if (\is_array($aSuggestionsProviderResult) && 0 < \count($aSuggestionsProviderResult))
- {
- $aResult = \array_merge($aResult, $aSuggestionsProviderResult);
- }
- }
-
- }
-
- $aResult = \RainLoop\Utils::RemoveSuggestionDuplicates($aResult);
- if ($iLimit < \count($aResult))
- {
- $aResult = \array_slice($aResult, 0, $iLimit);
- }
-
- $this->Plugins()->RunHook('ajax.suggestions-post', array(&$aResult, $sQuery, $oAccount, $iLimit));
-
- $aResult = \RainLoop\Utils::RemoveSuggestionDuplicates($aResult);
- if ($iLimit < \count($aResult))
- {
- $aResult = \array_slice($aResult, 0, $iLimit);
- }
-
- return $this->DefaultResponse(__FUNCTION__, $aResult);
- }
-
- /**
- * @return array
- */
- private function messageSetFlag($sActionFunction, $sResponseFunction)
- {
- $this->initMailClientConnection();
-
- $sFolder = $this->GetActionParam('Folder', '');
- $bSetAction = '1' === (string) $this->GetActionParam('SetAction', '0');
- $aUids = \explode(',', (string) $this->GetActionParam('Uids', ''));
- $aFilteredUids = \array_filter($aUids, function (&$sUid) {
- $sUid = (int) \trim($sUid);
- return 0 < $sUid;
- });
-
- try
- {
- $this->MailClient()->{$sActionFunction}($sFolder, $aFilteredUids, true, $bSetAction, true);
- }
- catch (\Exception $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::MailServerError, $oException);
- }
-
- return $this->TrueResponse($sResponseFunction);
- }
-
- /**
- * @return array
- */
- public function DoMessageSetSeen()
- {
- return $this->messageSetFlag('MessageSetSeen', __FUNCTION__);
- }
-
- /**
- * @return array
- */
- public function DoMessageSetSeenToAll()
- {
- $this->initMailClientConnection();
-
- $sFolder = $this->GetActionParam('Folder', '');
- $bSetAction = '1' === (string) $this->GetActionParam('SetAction', '0');
- $sThreadUids = \trim($this->GetActionParam('ThreadUids', ''));
-
- try
- {
- $this->MailClient()->MessageSetSeenToAll($sFolder, $bSetAction,
- !empty($sThreadUids) ? explode(',', $sThreadUids) : null);
- }
- catch (\Exception $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::MailServerError, $oException);
- }
-
- return $this->TrueResponse(__FUNCTION__);
- }
-
- /**
- * @return array
- */
- public function DoMessageSetFlagged()
- {
- return $this->messageSetFlag('MessageSetFlagged', __FUNCTION__);
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoMessage()
- {
- $sRawKey = (string) $this->GetActionParam('RawKey', '');
-
- $sFolder = '';
- $iUid = 0;
-
- $aValues = $this->getDecodedClientRawKeyValue($sRawKey, 4);
- if (is_array($aValues) && 4 === count($aValues))
- {
- $sFolder = (string) $aValues[0];
- $iUid = (int) $aValues[1];
-
- $this->verifyCacheByKey($sRawKey);
- }
- else
- {
- $sFolder = $this->GetActionParam('Folder', '');
- $iUid = (int) $this->GetActionParam('Uid', 0);
- }
-
- $oAccount = $this->initMailClientConnection();
-
- try
- {
- $oMessage = $this->MailClient()->Message($sFolder, $iUid, true,
- $this->cacherForThreads(),
- (int) $this->Config()->Get('labs', 'imap_body_text_limit', 0)
- );
- }
- catch (\Exception $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantGetMessage, $oException);
- }
-
- if ($oMessage instanceof \MailSo\Mail\Message)
- {
- $this->Plugins()
- ->RunHook('filter.result-message', array(&$oMessage))
- ->RunHook('filter.result-message[2]', array(&$oMessage, $oAccount))
- ;
-
- $this->cacheByKey($sRawKey);
- }
-
- return $this->DefaultResponse(__FUNCTION__, $oMessage);
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoMessageDelete()
- {
- $this->initMailClientConnection();
-
- $sFolder = $this->GetActionParam('Folder', '');
- $aUids = \explode(',', (string) $this->GetActionParam('Uids', ''));
-
- $aFilteredUids = \array_filter($aUids, function (&$sUid) {
- $sUid = (int) \trim($sUid);
- return 0 < $sUid;
- });
-
- try
- {
- $this->MailClient()->MessageDelete($sFolder, $aFilteredUids, true, true,
- !!$this->Config()->Get('labs', 'use_imap_expunge_all_on_delete', false));
- }
- catch (\Exception $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantDeleteMessage, $oException);
- }
-
- if ($this->Config()->Get('labs', 'use_imap_unselect', true))
- {
- try
- {
- $this->MailClient()->FolderUnSelect();
- }
- catch (\Exception $oException)
- {
- unset($oException);
- }
- }
-
- $sHash = '';
-
- try
- {
- $sHash = $this->MailClient()->FolderHash($sFolder);
- }
- catch (\Exception $oException)
- {
- unset($oException);
- }
-
- return $this->DefaultResponse(__FUNCTION__, '' === $sHash ? false : array($sFolder, $sHash));
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoMessageMove()
- {
- $this->initMailClientConnection();
-
- $sFromFolder = $this->GetActionParam('FromFolder', '');
- $sToFolder = $this->GetActionParam('ToFolder', '');
- $aUids = \explode(',', (string) $this->GetActionParam('Uids', ''));
- $bMarkAsRead = '1' === (string) $this->GetActionParam('MarkAsRead', '0');
-
- $aFilteredUids = \array_filter($aUids, function (&$mUid) {
- $mUid = (int) \trim($mUid);
- return 0 < $mUid;
- });
-
- if ($bMarkAsRead)
- {
- try
- {
- $this->MailClient()->MessageSetSeen($sFromFolder, $aFilteredUids, true, true);
- }
- catch (\Exception $oException)
- {
- unset($oException);
- }
- }
-
- try
- {
- $this->MailClient()->MessageMove($sFromFolder, $sToFolder, $aFilteredUids, true,
- !!$this->Config()->Get('labs', 'use_imap_move', true),
- !!$this->Config()->Get('labs', 'use_imap_expunge_all_on_delete', false)
- );
- }
- catch (\Exception $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantMoveMessage, $oException);
- }
-
- if ($this->Config()->Get('labs', 'use_imap_unselect', true))
- {
- try
- {
- $this->MailClient()->FolderUnSelect();
- }
- catch (\Exception $oException)
- {
- unset($oException);
- }
- }
-
- $sHash = '';
-
- try
- {
- $sHash = $this->MailClient()->FolderHash($sFromFolder);
- }
- catch (\Exception $oException)
- {
- unset($oException);
- }
-
- return $this->DefaultResponse(__FUNCTION__, '' === $sHash ? false : array($sFromFolder, $sHash));
- }
-
- /**
- * @return array
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function DoMessageCopy()
- {
- $this->initMailClientConnection();
-
- $sFromFolder = $this->GetActionParam('FromFolder', '');
- $sToFolder = $this->GetActionParam('ToFolder', '');
- $aUids = \explode(',', (string) $this->GetActionParam('Uids', ''));
-
- $aFilteredUids = \array_filter($aUids, function (&$mUid) {
- $mUid = (int) \trim($mUid);
- return 0 < $mUid;
- });
-
- try
- {
- $this->MailClient()->MessageCopy($sFromFolder, $sToFolder,
- $aFilteredUids, true);
-
- $sHash = $this->MailClient()->FolderHash($sFromFolder);
- }
- catch (\Exception $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantCopyMessage, $oException);
- }
-
- return $this->DefaultResponse(__FUNCTION__,
- '' === $sHash ? false : array($sFromFolder, $sHash));
- }
-
- /**
- * @param string $sFileName
- * @param string $sContentType
- * @param string $sMimeIndex
- * @param int $iMaxLength = 250
- *
- * @return string
- */
- public function MainClearFileName($sFileName, $sContentType, $sMimeIndex, $iMaxLength = 250)
- {
- $sFileName = 0 === \strlen($sFileName) ? \preg_replace('/[^a-zA-Z0-9]/', '.', (empty($sMimeIndex) ? '' : $sMimeIndex.'.').$sContentType) : $sFileName;
- $sClearedFileName = \MailSo\Base\Utils::StripSpaces(\preg_replace('/[\.]+/', '.', $sFileName));
- $sExt = \MailSo\Base\Utils::GetFileExtension($sClearedFileName);
-
- if (10 < $iMaxLength && $iMaxLength < \strlen($sClearedFileName) - \strlen($sExt))
- {
- $sClearedFileName = \substr($sClearedFileName, 0, $iMaxLength).(empty($sExt) ? '' : '.'.$sExt);
- }
-
- return \MailSo\Base\Utils::ClearFileName(\MailSo\Base\Utils::Utf8Clear($sClearedFileName));
- }
-
- /**
- * @return array
- */
- public function DoMessageUploadAttachments()
- {
- $oAccount = $this->initMailClientConnection();
-
- $mResult = false;
- $self = $this;
-
- try
- {
- $aAttachments = $this->GetActionParam('Attachments', array());
- if (\is_array($aAttachments) && 0 < \count($aAttachments))
- {
- $mResult = array();
- foreach ($aAttachments as $sAttachment)
- {
- $aValues = \RainLoop\Utils::DecodeKeyValuesQ($sAttachment);
- if (\is_array($aValues))
- {
- $sFolder = isset($aValues['Folder']) ? $aValues['Folder'] : '';
- $iUid = (int) isset($aValues['Uid']) ? $aValues['Uid'] : 0;
- $sMimeIndex = (string) isset($aValues['MimeIndex']) ? $aValues['MimeIndex'] : '';
-
- $sTempName = \md5($sAttachment);
- if (!$this->FilesProvider()->FileExists($oAccount, $sTempName))
- {
- $this->MailClient()->MessageMimeStream(
- function($rResource, $sContentType, $sFileName, $sMimeIndex = '') use ($oAccount, &$mResult, $sTempName, $sAttachment, $self) {
- if (is_resource($rResource))
- {
- $sContentType = (empty($sFileName)) ? 'text/plain' : \MailSo\Base\Utils::MimeContentType($sFileName);
- $sFileName = $self->MainClearFileName($sFileName, $sContentType, $sMimeIndex);
-
- if ($self->FilesProvider()->PutFile($oAccount, $sTempName, $rResource))
- {
- $mResult[$sTempName] = $sAttachment;
- }
- }
- }, $sFolder, $iUid, true, $sMimeIndex);
- }
- else
- {
- $mResult[$sTempName] = $sAttachment;
- }
- }
- }
- }
- }
- catch (\Exception $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::MailServerError, $oException);
- }
-
- return $this->DefaultResponse(__FUNCTION__, $mResult);
- }
-
- /**
- * @return array
- */
- public function DoComposeUploadExternals()
- {
- $oAccount = $this->getAccountFromToken();
-
- $mResult = false;
- $aExternals = $this->GetActionParam('Externals', array());
- if (\is_array($aExternals) && 0 < \count($aExternals))
- {
- $oHttp = \MailSo\Base\Http::SingletonInstance();
-
- $mResult = array();
- foreach ($aExternals as $sUrl)
- {
- $mResult[$sUrl] = '';
-
- $sTempName = \md5($sUrl);
-
- $iCode = 0;
- $sContentType = '';
-
- $rFile = $this->FilesProvider()->GetFile($oAccount, $sTempName, 'wb+');
- if ($rFile && $oHttp->SaveUrlToFile($sUrl, $rFile, '', $sContentType, $iCode, $this->Logger(), 60,
- $this->Config()->Get('labs', 'curl_proxy', ''), $this->Config()->Get('labs', 'curl_proxy_auth', '')))
- {
- $mResult[$sUrl] = $sTempName;
- }
-
- if (\is_resource($rFile))
- {
- @\fclose($rFile);
- }
- }
- }
-
- return $this->DefaultResponse(__FUNCTION__, $mResult);
- }
-
- /**
- * @return array
- */
- public function DoComposeUploadDrive()
- {
- $oAccount = $this->getAccountFromToken();
-
- $mResult = false;
-
- $sUrl = $this->GetActionParam('Url', '');
- $sAccessToken = $this->GetActionParam('AccessToken', '');
- $sGoogleApiKey = (string) $this->Config()->Get('social', 'google_api_key', '');
-
- if (0 < \strlen($sUrl) && 0 < \strlen($sAccessToken) && 0 < \strlen($sGoogleApiKey))
- {
- $oHttp = \MailSo\Base\Http::SingletonInstance();
-
- $mResult[$sUrl] = false;
-
- $sTempName = \md5($sUrl);
-
- $iCode = 0;
- $sContentType = '';
-
- $rFile = $this->FilesProvider()->GetFile($oAccount, $sTempName, 'wb+');
- if ($rFile && $oHttp->SaveUrlToFile($sUrl.'&key='.$sGoogleApiKey, $rFile, '', $sContentType, $iCode, $this->Logger(), 60,
- $this->Config()->Get('labs', 'curl_proxy', ''), $this->Config()->Get('labs', 'curl_proxy_auth', ''),
- array('Authorization: Bearer '.$sAccessToken)))
- {
- $mResult[$sUrl] = array($sTempName, 0);
- }
-
- if (\is_resource($rFile))
- {
- @\fclose($rFile);
- }
-
- if (isset($mResult[$sUrl][1]))
- {
- $mResult[$sUrl][1] = $rFile = $this->FilesProvider()->FileSize($oAccount, $sTempName);
- }
- }
-
- return $this->DefaultResponse(__FUNCTION__, $mResult);
- }
-
- /**
- * @return array
- */
- public function DoSocialUsers()
- {
- $oAccount = $this->getAccountFromToken();
-
- $oSettings = $this->SettingsProvider()->Load($oAccount);
-
- $aData = array(
- 'Google' => '',
- 'Facebook' => '',
- 'Twitter' => ''
- );
-
- if ($oSettings)
- {
- $aData['Google'] = $oSettings->GetConf('GoogleSocialName', '');
- $aData['Facebook'] = $oSettings->GetConf('FacebookSocialName', '');
- $aData['Twitter'] = $oSettings->GetConf('TwitterSocialName', '');
- }
-
- return $this->DefaultResponse(__FUNCTION__, $aData);
- }
-
- /**
- * @return array
- */
- public function DoSocialGoogleDisconnect()
- {
- $oAccount = $this->getAccountFromToken();
- return $this->DefaultResponse(__FUNCTION__, $this->Social()->GoogleDisconnect($oAccount));
- }
-
- /**
- * @return array
- */
- public function DoSocialTwitterDisconnect()
- {
- $oAccount = $this->getAccountFromToken();
- return $this->DefaultResponse(__FUNCTION__, $this->Social()->TwitterDisconnect($oAccount));
- }
-
- /**
- * @return array
- */
- public function DoSocialFacebookDisconnect()
- {
- $oAccount = $this->getAccountFromToken();
- return $this->DefaultResponse(__FUNCTION__, $this->Social()->FacebookDisconnect($oAccount));
- }
-
- /**
- * @param int $iError
- * @param int $iClientError
- *
- * @return string
- */
- private function getUploadErrorMessageByCode($iError, &$iClientError)
- {
- $sError = '';
- $iClientError = UploadClientError::NORMAL;
- switch($iError)
- {
- case UPLOAD_ERR_OK:
- break;
- case UPLOAD_ERR_INI_SIZE:
- case UPLOAD_ERR_FORM_SIZE:
- case UploadError::CONFIG_SIZE:
- case UploadError::EMPTY_FILES_DATA:
- $sError = 'File is too big';
- $iClientError = UploadClientError::FILE_IS_TOO_BIG;
- break;
- case UPLOAD_ERR_PARTIAL:
- $sError = 'File partially uploaded';
- $iClientError = UploadClientError::FILE_PARTIALLY_UPLOADED;
- break;
- case UPLOAD_ERR_NO_FILE:
- $sError = 'No file uploaded';
- $iClientError = UploadClientError::FILE_NO_UPLOADED;
- break;
- case UPLOAD_ERR_NO_TMP_DIR:
- case UPLOAD_ERR_CANT_WRITE:
- case UPLOAD_ERR_EXTENSION:
- $sError = 'Missing temp folder';
- $iClientError = UploadClientError::MISSING_TEMP_FOLDER;
- break;
- case UploadError::ON_SAVING:
- $sError = 'Error on saving file';
- $iClientError = UploadClientError::FILE_ON_SAVING_ERROR;
- break;
- case UploadError::FILE_TYPE:
- $sError = 'Invalid file type';
- $iClientError = UploadClientError::FILE_TYPE;
- break;
- case UploadError::UNKNOWN:
- default:
- $sError = 'Unknown error';
- $iClientError = UploadClientError::UNKNOWN;
- break;
- }
-
- return $sError;
- }
-
- /**
- * @return array
- */
- public function Upload()
- {
- $oAccount = $this->getAccountFromToken();
-
- $aResponse = array();
-
- $aFile = $this->GetActionParam('File', null);
- $iError = $this->GetActionParam('Error', \RainLoop\Enumerations\UploadError::UNKNOWN);
-
- if ($oAccount && UPLOAD_ERR_OK === $iError && \is_array($aFile))
- {
- $sSavedName = 'upload-post-'.\md5($aFile['name'].$aFile['tmp_name']);
- if (!$this->FilesProvider()->MoveUploadedFile($oAccount, $sSavedName, $aFile['tmp_name']))
- {
- $iError = \RainLoop\Enumerations\UploadError::ON_SAVING;
- }
- else
- {
- $sUploadName = $aFile['name'];
- $iSize = $aFile['size'];
- $sMimeType = $aFile['type'];
-
- $aResponse['Attachment'] = array(
- 'Name' => $sUploadName,
- 'TempName' => $sSavedName,
- 'MimeType' => $sMimeType,
- 'Size' => (int) $iSize
- );
- }
- }
-
- if (UPLOAD_ERR_OK !== $iError)
- {
- $iClientError = \RainLoop\Enumerations\UploadClientError::NORMAL;
- $sError = $this->getUploadErrorMessageByCode($iError, $iClientError);
-
- if (!empty($sError))
- {
- $aResponse['ErrorCode'] = $iClientError;
- $aResponse['Error'] = $sError;
- }
- }
-
- return $this->DefaultResponse(__FUNCTION__, $aResponse);
- }
-
- /**
- * @return array
- */
- public function DoClearUserBackground()
- {
- $oAccount = $this->getAccountFromToken();
-
- if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::USER_BACKGROUND, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $oSettings = $this->SettingsProvider()->Load($oAccount);
- if ($oAccount && $oSettings)
- {
- $this->StorageProvider()->Clear($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'background'
- );
-
- $oSettings->SetConf('UserBackgroundName', '');
- $oSettings->SetConf('UserBackgroundHash', '');
- }
-
- return $this->DefaultResponse(__FUNCTION__, $oAccount && $oSettings ?
- $this->SettingsProvider()->Save($oAccount, $oSettings) : false);
- }
-
- /**
- * @return array
- */
- public function UploadBackground()
- {
- $oAccount = $this->getAccountFromToken();
-
- if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::USER_BACKGROUND, $oAccount))
- {
- return $this->FalseResponse(__FUNCTION__);
- }
-
- $sName = '';
- $sHash = '';
-
- $aFile = $this->GetActionParam('File', null);
- $iError = $this->GetActionParam('Error', \RainLoop\Enumerations\UploadError::UNKNOWN);
-
- if ($oAccount && UPLOAD_ERR_OK === $iError && \is_array($aFile))
- {
- $sMimeType = \strtolower(\MailSo\Base\Utils::MimeContentType($aFile['name']));
- if (\in_array($sMimeType, array('image/png', 'image/jpg', 'image/jpeg')))
- {
- $sSavedName = 'upload-post-'.\md5($aFile['name'].$aFile['tmp_name']);
- if (!$this->FilesProvider()->MoveUploadedFile($oAccount, $sSavedName, $aFile['tmp_name']))
- {
- $iError = \RainLoop\Enumerations\UploadError::ON_SAVING;
- }
- else
- {
- $rData = $this->FilesProvider()->GetFile($oAccount, $sSavedName);
- if (@\is_resource($rData))
- {
- $sData = @\stream_get_contents($rData);
- if (!empty($sData) && 0 < \strlen($sData))
- {
- $sName = $aFile['name'];
- if (empty($sName))
- {
- $sName = '_';
- }
-
- if ($this->StorageProvider()->Put($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'background',
- \json_encode(array(
- 'Name' => $aFile['name'],
- 'ContentType' => $sMimeType,
- 'Raw' => \base64_encode($sData)
- ))
- ))
- {
- $oSettings = $this->SettingsProvider()->Load($oAccount);
- if ($oSettings)
- {
- $sHash = \MailSo\Base\Utils::Md5Rand($sName.APP_VERSION.APP_SALT);
-
- $oSettings->SetConf('UserBackgroundName', $sName);
- $oSettings->SetConf('UserBackgroundHash', $sHash);
- $this->SettingsProvider()->Save($oAccount, $oSettings);
- }
- }
- }
-
- unset($sData);
- }
-
- if (@\is_resource($rData))
- {
- @\fclose($rData);
- }
-
- unset($rData);
- }
-
- $this->FilesProvider()->Clear($oAccount, $sSavedName);
- }
- else
- {
- $iError = \RainLoop\Enumerations\UploadError::FILE_TYPE;
- }
- }
-
- if (UPLOAD_ERR_OK !== $iError)
- {
- $iClientError = \RainLoop\Enumerations\UploadClientError::NORMAL;
- $sError = $this->getUploadErrorMessageByCode($iError, $iClientError);
-
- if (!empty($sError))
- {
- return $this->FalseResponse(__FUNCTION__, $iClientError, $sError);
- }
- }
-
- return $this->DefaultResponse(__FUNCTION__, !empty($sName) && !empty($sHash) ? array(
- 'Name' => $sName,
- 'Hash' => $sHash
- ) : false);
- }
-
- /**
- * @return array
- */
- public function UploadContacts()
- {
- $oAccount = $this->getAccountFromToken();
-
- $mResponse = false;
-
- $aFile = $this->GetActionParam('File', null);
- $iError = $this->GetActionParam('Error', \RainLoop\Enumerations\UploadError::UNKNOWN);
-
- if ($oAccount && UPLOAD_ERR_OK === $iError && \is_array($aFile))
- {
- $sSavedName = 'upload-post-'.\md5($aFile['name'].$aFile['tmp_name']);
- if (!$this->FilesProvider()->MoveUploadedFile($oAccount, $sSavedName, $aFile['tmp_name']))
- {
- $iError = \RainLoop\Enumerations\UploadError::ON_SAVING;
- }
- else
- {
- @\ini_set('auto_detect_line_endings', true);
- $mData = $this->FilesProvider()->GetFile($oAccount, $sSavedName);
- if ($mData)
- {
- $sFileStart = @\fread($mData, 20);
- \rewind($mData);
-
- if (false !== $sFileStart)
- {
- $sFileStart = \trim($sFileStart);
- if (false !== \strpos($sFileStart, 'BEGIN:VCARD'))
- {
- $mResponse = $this->importContactsFromVcfFile($oAccount, $mData);
- }
- else if (false !== \strpos($sFileStart, ',') || false !== \strpos($sFileStart, ';'))
- {
- $mResponse = $this->importContactsFromCsvFile($oAccount, $mData, $sFileStart);
- }
- }
- }
-
- if (\is_resource($mData))
- {
- @\fclose($mData);
- }
-
- unset($mData);
- $this->FilesProvider()->Clear($oAccount, $sSavedName);
-
- @\ini_set('auto_detect_line_endings', false);
- }
- }
-
- if (UPLOAD_ERR_OK !== $iError)
- {
- $iClientError = \RainLoop\Enumerations\UploadClientError::NORMAL;
- $sError = $this->getUploadErrorMessageByCode($iError, $iClientError);
-
- if (!empty($sError))
- {
- return $this->FalseResponse(__FUNCTION__, $iClientError, $sError);
- }
- }
-
- return $this->DefaultResponse(__FUNCTION__, $mResponse);
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount
- * @param resource $rFile
- * @param string $sFileStart
- *
- * @return int
- */
- private function importContactsFromCsvFile($oAccount, $rFile, $sFileStart)
- {
- $iCount = 0;
- $aHeaders = null;
- $aData = array();
-
- if ($oAccount && \is_resource($rFile))
- {
- $oAddressBookProvider = $this->AddressBookProvider($oAccount);
- if ($oAddressBookProvider && $oAddressBookProvider->IsActive())
- {
- $sDelimiter = ((int) \strpos($sFileStart, ',') > (int) \strpos($sFileStart, ';')) ? ',' : ';';
-
- @\setlocale(LC_CTYPE, 'en_US.UTF-8');
- while (false !== ($mRow = \fgetcsv($rFile, 5000, $sDelimiter, '"')))
- {
- if (null === $aHeaders)
- {
- if (3 >= \count($mRow))
- {
- return 0;
- }
-
- $aHeaders = $mRow;
-
- foreach ($aHeaders as $iIndex => $sHeaderValue)
- {
- $aHeaders[$iIndex] = \MailSo\Base\Utils::Utf8Clear($sHeaderValue);
- }
- }
- else
- {
- $aNewItem = array();
- foreach ($aHeaders as $iIndex => $sHeaderValue)
- {
- $aNewItem[$sHeaderValue] = isset($mRow[$iIndex]) ? $mRow[$iIndex] : '';
- }
-
- $aData[] = $aNewItem;
- }
- }
-
- if (\is_array($aData) && 0 < \count($aData))
- {
- $this->Logger()->Write('Import contacts from csv');
- $iCount = $oAddressBookProvider->ImportCsvArray($oAccount->ParentEmailHelper(), $aData);
- }
- }
- }
-
- return $iCount;
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount
- * @param resource $rFile
- *
- * @return int
- */
- private function importContactsFromVcfFile($oAccount, $rFile)
- {
- $iCount = 0;
- if ($oAccount && \is_resource($rFile))
- {
- $oAddressBookProvider = $this->AddressBookProvider($oAccount);
- if ($oAddressBookProvider && $oAddressBookProvider->IsActive())
- {
- $sFile = \stream_get_contents($rFile);
- if (\is_resource($rFile))
- {
- \fclose($rFile);
- }
-
- if (is_string($sFile) && 5 < \strlen($sFile))
- {
- $this->Logger()->Write('Import contacts from vcf');
- $iCount = $oAddressBookProvider->ImportVcfFile($oAccount->ParentEmailHelper(), $sFile);
- }
- }
- }
-
- return $iCount;
- }
-
- /**
- * @return bool
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function RawViewAsPlain()
- {
- $this->initMailClientConnection();
-
- $sRawKey = (string) $this->GetActionParam('RawKey', '');
- $aValues = $this->getDecodedRawKeyValue($sRawKey);
-
- $sFolder = isset($aValues['Folder']) ? $aValues['Folder'] : '';
- $iUid = (int) (isset($aValues['Uid']) ? $aValues['Uid'] : 0);
- $sMimeIndex = (string) (isset($aValues['MimeIndex']) ? $aValues['MimeIndex'] : '');
-
- \header('Content-Type: text/plain', true);
-
- return $this->MailClient()->MessageMimeStream(function ($rResource) {
- if (\is_resource($rResource))
- {
- \MailSo\Base\Utils::FpassthruWithTimeLimitReset($rResource);
- }
- }, $sFolder, $iUid, true, $sMimeIndex);
- }
-
- /**
- * @return string
- */
- public function RawFramedView()
- {
- $oAccount = $this->getAccountFromToken(false);
- if ($oAccount)
- {
- $sRawKey = (string) $this->GetActionParam('RawKey', '');
- $aParams = $this->GetActionParam('Params', null);
- $this->Http()->ServerNoCache();
-
- $aData = \RainLoop\Utils::DecodeKeyValuesQ($sRawKey);
- if (isset($aParams[0], $aParams[1], $aParams[2]) &&
- 'Raw' === $aParams[0] && 'FramedView' === $aParams[2] && isset($aData['Framed']) && $aData['Framed'] && $aData['FileName'])
- {
- if ($this->isFileHasFramedPreview($aData['FileName']))
- {
- $sNewSpecAuthToken = $this->GetShortLifeSpecAuthToken();
- if (!empty($sNewSpecAuthToken))
- {
- $aParams[1] = '_'.$sNewSpecAuthToken;
- $aParams[2] = 'View';
-
- \array_shift($aParams);
- $sLast = \array_pop($aParams);
-
- $sUrl = $this->Http()->GetFullUrl().'?/Raw/&q[]=/'.\implode('/', $aParams).'/&q[]=/'.$sLast;
- $sFullUrl = 'https://docs.google.com/viewer?embedded=true&url='.\urlencode($sUrl);
-
- @\header('Content-Type: text/html; charset=utf-8');
- echo ''.
- ''.
- ''.
- '';
- }
- }
- }
- }
-
-
- return true;
-
- }
-
- /**
- * @return bool
- *
- * @throws \MailSo\Base\Exceptions\Exception
- */
- public function Append()
- {
- $oAccount = $this->initMailClientConnection();
-
- $sFolderFullNameRaw = $this->GetActionParam('Folder', '');
-
- $_FILES = isset($_FILES) ? $_FILES : null;
- if ($oAccount instanceof \RainLoop\Model\Account &&
- $this->Config()->Get('labs', 'allow_message_append', false) &&
- isset($_FILES, $_FILES['AppendFile'], $_FILES['AppendFile']['name'],
- $_FILES['AppendFile']['tmp_name'], $_FILES['AppendFile']['size']))
- {
- if (is_string($_FILES['AppendFile']['tmp_name']) && 0 < strlen($_FILES['AppendFile']['tmp_name']))
- {
- if (\UPLOAD_ERR_OK === (int) $_FILES['AppendFile']['error'] && !empty($sFolderFullNameRaw))
- {
- $sSavedName = 'append-post-'.md5($sFolderFullNameRaw.$_FILES['AppendFile']['name'].$_FILES['AppendFile']['tmp_name']);
-
- if ($this->FilesProvider()->MoveUploadedFile($oAccount,
- $sSavedName, $_FILES['AppendFile']['tmp_name']))
- {
- $iMessageStreamSize = $this->FilesProvider()->FileSize($oAccount, $sSavedName);
- $rMessageStream = $this->FilesProvider()->GetFile($oAccount, $sSavedName);
-
- $this->MailClient()->MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderFullNameRaw);
-
- $this->FilesProvider()->Clear($oAccount, $sSavedName);
- }
- }
- }
- }
-
- return $this->DefaultResponse(__FUNCTION__, true);
- }
-
- /**
- * @param bool $bAdmin
- * @param bool $bMobile = false
- * @param \RainLoop\Model\Account $oAccount = null
- *
- * @return array
- */
- public function Capa($bAdmin, $bMobile = false, $oAccount = null)
- {
- $oConfig = $this->Config();
-
- $aResult = array();
-
- if ($oConfig->Get('capa', 'folders', true))
- {
- $aResult[] = \RainLoop\Enumerations\Capa::FOLDERS;
-
- if ($oConfig->Get('capa', 'messagelist_actions', true))
- {
- $aResult[] = \RainLoop\Enumerations\Capa::MESSAGELIST_ACTIONS;
-
- if ($oConfig->Get('capa', 'dangerous_actions', true))
- {
- $aResult[] = \RainLoop\Enumerations\Capa::DANGEROUS_ACTIONS;
- }
- }
- }
-
- if ($oConfig->Get('capa', 'reload', true))
- {
- $aResult[] = \RainLoop\Enumerations\Capa::RELOAD;
- }
-
- if ($oConfig->Get('capa', 'quota', true))
- {
- $aResult[] = \RainLoop\Enumerations\Capa::QUOTA;
- }
-
- if ($oConfig->Get('capa', 'settings', true))
- {
- $aResult[] = \RainLoop\Enumerations\Capa::SETTINGS;
-
- if ($oConfig->Get('webmail', 'allow_additional_accounts', false))
- {
- $aResult[] = \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS;
- }
-
- if ($oConfig->Get('webmail', 'allow_additional_identities', false))
- {
- $aResult[] = \RainLoop\Enumerations\Capa::IDENTITIES;
- }
-
- if ($oConfig->Get('capa', 'x-templates', true) && !$bMobile)
- {
- $aResult[] = \RainLoop\Enumerations\Capa::TEMPLATES;
- }
-
- if ($oConfig->Get('webmail', 'allow_themes', false) && !$bMobile)
- {
- $aResult[] = \RainLoop\Enumerations\Capa::THEMES;
- }
-
- if ($oConfig->Get('webmail', 'allow_user_background', false) && !$bMobile)
- {
- $aResult[] = \RainLoop\Enumerations\Capa::USER_BACKGROUND;
- }
-
- if ($oConfig->Get('security', 'openpgp', false) && !$bMobile)
- {
- $aResult[] = \RainLoop\Enumerations\Capa::OPEN_PGP;
- }
-
- if ($oConfig->Get('capa', 'filters', false))
- {
- $aResult[] = \RainLoop\Enumerations\Capa::FILTERS;
- if ($bAdmin || ($oAccount && $oAccount->Domain()->UseSieve()))
- {
- $aResult[] = \RainLoop\Enumerations\Capa::SIEVE;
- }
- }
- }
-
- if ($oConfig->Get('security', 'allow_two_factor_auth', false) &&
- ($bAdmin || ($oAccount && !$oAccount->IsAdditionalAccount())))
- {
- $aResult[] = \RainLoop\Enumerations\Capa::TWO_FACTOR;
-
- if ($oConfig->Get('security', 'force_two_factor_auth', false) &&
- ($bAdmin || ($oAccount && !$oAccount->IsAdditionalAccount())))
- {
- $aResult[] = \RainLoop\Enumerations\Capa::TWO_FACTOR_FORCE;
- }
- }
-
- if ($oConfig->Get('capa', 'help', true) && !$bMobile)
- {
- $aResult[] = \RainLoop\Enumerations\Capa::HELP;
- }
-
- if ($oConfig->Get('capa', 'attachments_actions', false))
- {
- $aResult[] = \RainLoop\Enumerations\Capa::ATTACHMENTS_ACTIONS;
- }
-
- if ($oConfig->Get('capa', 'message_actions', true))
- {
- $aResult[] = \RainLoop\Enumerations\Capa::MESSAGE_ACTIONS;
- }
-
- if ($oConfig->Get('capa', 'composer', true))
- {
- $aResult[] = \RainLoop\Enumerations\Capa::COMPOSER;
-
- if ($oConfig->Get('capa', 'contacts', true))
- {
- $aResult[] = \RainLoop\Enumerations\Capa::CONTACTS;
- }
- }
-
- if ($oConfig->Get('capa', 'search', true))
- {
- $aResult[] = \RainLoop\Enumerations\Capa::SEARCH;
-
- if ($oConfig->Get('capa', 'search_adv', true) && !$bMobile)
- {
- $aResult[] = \RainLoop\Enumerations\Capa::SEARCH_ADV;
- }
- }
-
- if ($oConfig->Get('labs', 'allow_gravatar', false))
- {
- $aResult[] = \RainLoop\Enumerations\Capa::GRAVATAR;
- }
-
- if ($oConfig->Get('interface', 'show_attachment_thumbnail', true))
- {
- $aResult[] = \RainLoop\Enumerations\Capa::ATTACHMENT_THUMBNAILS;
- }
-
- if ($oConfig->Get('labs', 'allow_prefetch', false) && !$bMobile)
- {
- $aResult[] = \RainLoop\Enumerations\Capa::PREFETCH;
- }
-
- if (!\RainLoop\Utils::IsOwnCloud())
- {
- $aResult[] = \RainLoop\Enumerations\Capa::AUTOLOGOUT;
- }
-
- return $aResult;
- }
-
- /**
- * @param bool $bAdmin
- * @param bool $bMobile
- * @param string $sName
- * @param \RainLoop\Model\Account $oAccount = null
- *
- * @return bool
- */
- public function GetCapa($bAdmin, $bMobile, $sName, $oAccount = null)
- {
- return \in_array($sName, $this->Capa($bAdmin, $bMobile, $oAccount));
- }
-
- /**
- * @param string $sKey
- *
- * @return string
- */
- public function etag($sKey)
- {
- return \md5('Etag:'.\md5($sKey.\md5($this->Config()->Get('cache', 'index', ''))));
- }
-
- /**
- * @param string $sKey
- * @param bool $bForce = false
- *
- * @return bool
- */
- public function cacheByKey($sKey, $bForce = false)
- {
- $bResult = false;
- if (!empty($sKey) && ($bForce || ($this->Config()->Get('cache', 'enable', true) && $this->Config()->Get('cache', 'http', true))))
- {
- $iExpires = $this->Config()->Get('cache', 'http_expires', 3600);
- if (0 < $iExpires)
- {
- $this->oHttp->ServerUseCache($this->etag($sKey), 1382478804, time() + $iExpires);
- $bResult = true;
- }
- }
-
- if (!$bResult)
- {
- $this->oHttp->ServerNoCache();
- }
-
- return $bResult;
- }
-
- /**
- * @param string $sKey
- * @param bool $bForce = false
- *
- * @return void
- */
- public function verifyCacheByKey($sKey, $bForce = false)
- {
- if (!empty($sKey) && ($bForce || $this->Config()->Get('cache', 'enable', true) && $this->Config()->Get('cache', 'http', true)))
- {
- $sIfNoneMatch = $this->Http()->GetHeader('If-None-Match', '');
- if ($this->etag($sKey) === $sIfNoneMatch)
- {
- $this->Http()->StatusHeader(304);
- $this->cacheByKey($sKey);
- exit(0);
- }
- }
- }
-
- /**
- * @param \RainLoop\Model\Account $oAccount
- * @param string $sHash
- *
- * @return array
- */
- private function getMimeFileByHash($oAccount, $sHash)
- {
- $aValues = $this->getDecodedRawKeyValue($sHash);
-
- $sFolder = isset($aValues['Folder']) ? $aValues['Folder'] : '';
- $iUid = (int) isset($aValues['Uid']) ? $aValues['Uid'] : 0;
- $sMimeIndex = (string) isset($aValues['MimeIndex']) ? $aValues['MimeIndex'] : '';
-
- $sContentTypeIn = (string) isset($aValues['MimeType']) ? $aValues['MimeType'] : '';
- $sFileNameIn = (string) isset($aValues['FileName']) ? $aValues['FileName'] : '';
-
- $oFileProvider = $this->FilesProvider();
-
- $sResultHash = '';
-
- $mResult = $this->MailClient()->MessageMimeStream(function($rResource, $sContentType, $sFileName, $sMimeIndex = '')
- use ($oAccount, $oFileProvider, $sFileNameIn, $sContentTypeIn, &$sResultHash) {
-
- unset($sContentType, $sFileName, $sMimeIndex);
-
- if ($oAccount && \is_resource($rResource))
- {
- $sHash = \MailSo\Base\Utils::Md5Rand($sFileNameIn.'~'.$sContentTypeIn);
- $rTempResource = $oFileProvider->GetFile($oAccount, $sHash, 'wb+');
-
- if (@\is_resource($rTempResource))
- {
- if (false !== \MailSo\Base\Utils::MultipleStreamWriter($rResource, array($rTempResource)))
- {
- $sResultHash = $sHash;
- }
-
- @\fclose($rTempResource);
- }
- }
-
- }, $sFolder, $iUid, true, $sMimeIndex);
-
- $aValues['FileHash'] = '';
- if ($mResult)
- {
- $aValues['FileHash'] = $sResultHash;
- }
-
- return $aValues;
- }
-
- /**
- * @param \Imagine\Image\AbstractImage $oImage
- * @param int $iOrientation
- */
- private function rotateImageByOrientation(&$oImage, $iOrientation)
- {
- if (0 < $iOrientation)
- {
- switch ($iOrientation)
- {
- default:
- case 1:
- break;
-
- case 2: // flip horizontal
- $oImage->flipHorizontally();
- break;
-
- case 3: // rotate 180
- $oImage->rotate(180);
- break;
-
- case 4: // flip vertical
- $oImage->flipVertically();
- break;
-
- case 5: // vertical flip + 90 rotate
- $oImage->flipVertically();
- $oImage->rotate(90);
- break;
-
- case 6: // rotate 90
- $oImage->rotate(90);
- break;
-
- case 7: // horizontal flip + 90 rotate
- $oImage->flipHorizontally();
- $oImage->rotate(90);
- break;
-
- case 8: // rotate 270
- $oImage->rotate(270);
- break;
- }
- }
- }
-
- /**
- * @param \Imagine\Image\AbstractImage $oImage
- */
- public function correctImageOrientation($oImage, $bDetectImageOrientation = true, $iThumbnailBoxSize = null)
- {
- $iOrientation = 1;
- if ($bDetectImageOrientation && \MailSo\Base\Utils::FunctionExistsAndEnabled('exif_read_data') &&
- \MailSo\Base\Utils::FunctionExistsAndEnabled('gd_info'))
- {
- $oMetadata = $oImage->metadata(new \Imagine\Image\Metadata\ExifMetadataReader());
- $iOrientation = isset($oMetadata['ifd0.Orientation']) &&
- is_numeric($oMetadata['ifd0.Orientation']) ? (int) $oMetadata['ifd0.Orientation'] : 1;
- }
-
- if ($iThumbnailBoxSize && 0 < $iThumbnailBoxSize)
- {
- $oImage = $oImage->thumbnail(
- new \Imagine\Image\Box($iThumbnailBoxSize, $iThumbnailBoxSize),
- \Imagine\Image\ImageInterface::THUMBNAIL_OUTBOUND);
-
- $this->rotateImageByOrientation($oImage, $iOrientation);
- }
- else
- {
- $this->rotateImageByOrientation($oImage, $iOrientation);
- }
-
- return $oImage;
- }
-
- /**
- * @param bool $bDownload
- * @param bool $bThumbnail = false
- *
- * @return bool
- */
- private function rawSmart($bDownload, $bThumbnail = false)
- {
- $sRawKey = (string) $this->GetActionParam('RawKey', '');
- $aValues = $this->getDecodedRawKeyValue($sRawKey);
-
- $sRange = $this->Http()->GetHeader('Range');
-
- $aMatch = array();
- $sRangeStart = $sRangeEnd = '';
- $bIsRangeRequest = false;
-
- if (!empty($sRange) && 'bytes=0-' !== \strtolower($sRange) && \preg_match('/^bytes=([0-9]+)-([0-9]*)/i', \trim($sRange), $aMatch))
- {
- $sRangeStart = $aMatch[1];
- $sRangeEnd = $aMatch[2];
-
- $bIsRangeRequest = true;
- }
-
- $sFolder = isset($aValues['Folder']) ? $aValues['Folder'] : '';
- $iUid = isset($aValues['Uid']) ? (int) $aValues['Uid'] : 0;
- $sMimeIndex = isset($aValues['MimeIndex']) ? (string) $aValues['MimeIndex'] : '';
-
- $sContentTypeIn = isset($aValues['MimeType']) ? (string) $aValues['MimeType'] : '';
- $sFileNameIn = isset($aValues['FileName']) ? (string) $aValues['FileName'] : '';
- $sFileHashIn = isset($aValues['FileHash']) ? (string) $aValues['FileHash'] : '';
-
- $bDetectImageOrientation = !!$this->Config()->Get('labs', 'detect_image_exif_orientation', true);
-
- if (!empty($sFileHashIn))
- {
- $this->verifyCacheByKey($sRawKey);
-
- $oAccount = $this->getAccountFromToken();
-
- $sContentTypeOut = empty($sContentTypeIn) ?
- \MailSo\Base\Utils::MimeContentType($sFileNameIn) : $sContentTypeIn;
-
- $sFileNameOut = $this->MainClearFileName($sFileNameIn, $sContentTypeIn, $sMimeIndex);
-
- $rResource = $this->FilesProvider()->GetFile($oAccount, $sFileHashIn);
- if (\is_resource($rResource))
- {
- $sFileNameOut = \MailSo\Base\Utils::ConvertEncoding(
- $sFileNameOut, \MailSo\Base\Enumerations\Charset::UTF_8,
- \MailSo\Base\Enumerations\Charset::CP858);
-
- \header('Content-Type: '.$sContentTypeOut);
- \header('Content-Disposition: attachment; '.
- \trim(\MailSo\Base\Utils::EncodeHeaderUtf8AttributeValue('filename', $sFileNameOut)), true);
-
- \header('Accept-Ranges: none', true);
- \header('Content-Transfer-Encoding: binary');
-
- \MailSo\Base\Utils::FpassthruWithTimeLimitReset($rResource);
- return true;
- }
-
- return false;
- }
- else
- {
- if (!empty($sFolder) && 0 < $iUid)
- {
- $this->verifyCacheByKey($sRawKey);
- }
- }
-
- $oAccount = $this->initMailClientConnection();
-
- $self = $this;
- return $this->MailClient()->MessageMimeStream(
- function($rResource, $sContentType, $sFileName, $sMimeIndex = '') use (
- $self, $oAccount, $sRawKey, $sContentTypeIn, $sFileNameIn, $bDownload, $bThumbnail, $bDetectImageOrientation,
- $bIsRangeRequest, $sRangeStart, $sRangeEnd
- ) {
- if ($oAccount && \is_resource($rResource))
- {
- \MailSo\Base\Utils::ResetTimeLimit();
-
- $sContentTypeOut = $sContentTypeIn;
- if (empty($sContentTypeOut))
- {
- $sContentTypeOut = $sContentType;
- if (empty($sContentTypeOut))
- {
- $sContentTypeOut = (empty($sFileName)) ? 'text/plain' : \MailSo\Base\Utils::MimeContentType($sFileName);
- }
- }
-
- $sFileNameOut = $sFileNameIn;
- if (empty($sFileNameOut))
- {
- $sFileNameOut = $sFileName;
- }
-
- $sFileNameOut = $self->MainClearFileName($sFileNameOut, $sContentTypeOut, $sMimeIndex);
-
- $self->cacheByKey($sRawKey);
-
- $sLoadedData = null;
- if (!$bDownload)
- {
- if ($bThumbnail)
- {
- try
- {
- $oImagine = new \Imagine\Gd\Imagine();
-
- $oImage = $oImagine->load(\stream_get_contents($rResource));
-
- $oImage = $self->correctImageOrientation($oImage, $bDetectImageOrientation, 60);
-
- \header('Content-Disposition: inline; '.
- \trim(\MailSo\Base\Utils::EncodeHeaderUtf8AttributeValue('filename', $sFileNameOut.'_thumb60x60.png')), true);
-
- $oImage->show('png');
- }
- catch (\Exception $oException)
- {
- $self->Logger()->WriteExceptionShort($oException);
- }
- }
- else if ($bDetectImageOrientation &&
- \in_array($sContentTypeOut, array('image/png', 'image/jpeg', 'image/jpg')) &&
- \MailSo\Base\Utils::FunctionExistsAndEnabled('gd_info'))
- {
- try
- {
- $oImagine = new \Imagine\Gd\Imagine();
-
- $sLoadedData = \stream_get_contents($rResource);
-
- $oImage = $oImagine->load($sLoadedData);
-
- $oImage = $self->correctImageOrientation($oImage, $bDetectImageOrientation);
-
- \header('Content-Disposition: inline; '.
- \trim(\MailSo\Base\Utils::EncodeHeaderUtf8AttributeValue('filename', $sFileNameOut)), true);
-
- $oImage->show($sContentTypeOut === 'image/png' ? 'png' : 'jpg');
- }
- catch (\Exception $oException)
- {
- $self->Logger()->WriteExceptionShort($oException);
- }
- }
- else
- {
- $sLoadedData = \stream_get_contents($rResource);
- }
- }
-
- if ($bDownload || $sLoadedData)
- {
- if (!headers_sent()) {
- \header('Content-Type: '.$sContentTypeOut);
- \header('Content-Disposition: '.($bDownload ? 'attachment' : 'inline').'; '.
- \trim(\MailSo\Base\Utils::EncodeHeaderUtf8AttributeValue('filename', $sFileNameOut)), true);
-
- \header('Accept-Ranges: bytes');
- \header('Content-Transfer-Encoding: binary');
- }
-
- if ($bIsRangeRequest && !$sLoadedData)
- {
- $sLoadedData = \stream_get_contents($rResource);
- }
-
- \MailSo\Base\Utils::ResetTimeLimit();
-
- if ($sLoadedData)
- {
- if ($bIsRangeRequest && (0 < \strlen($sRangeStart) || 0 < \strlen($sRangeEnd)))
- {
- $iFullContentLength = \strlen($sLoadedData);
-
- $self->Http()->StatusHeader(206);
-
- $iRangeStart = (int) $sRangeStart;
- $iRangeEnd = (int) $sRangeEnd;
-
- if ('' === $sRangeEnd)
- {
- $sLoadedData = 0 < $iRangeStart ? \substr($sLoadedData, $iRangeStart) : $sLoadedData;
- }
- else
- {
- if ($iRangeStart < $iRangeEnd)
- {
- $sLoadedData = \substr($sLoadedData, $iRangeStart, $iRangeEnd - $iRangeStart);
- }
- else
- {
- $sLoadedData = 0 < $iRangeStart ? \substr($sLoadedData, $iRangeStart) : $sLoadedData;
- }
- }
-
- $iContentLength = \strlen($sLoadedData);
-
- if (0 < $iContentLength)
- {
- \header('Content-Length: '.$iContentLength, true);
- \header('Content-Range: bytes '.$sRangeStart.'-'.(0 < $iRangeEnd ? $iRangeEnd : $iFullContentLength - 1).'/'.$iFullContentLength);
- }
-
- echo $sLoadedData;
- }
- else
- {
- echo $sLoadedData;
- }
-
- unset($sLoadedData);
- }
- else
- {
- \MailSo\Base\Utils::FpassthruWithTimeLimitReset($rResource);
- }
- }
- }
- }, $sFolder, $iUid, true, $sMimeIndex);
- }
-
- /**
- * @return bool
- */
- public function RawDownload()
- {
- return $this->rawSmart(true);
- }
-
- /**
- * @return bool
- */
- public function RawView()
- {
- return $this->rawSmart(false);
- }
-
- /**
- * @return bool
- */
- public function RawViewThumbnail()
- {
- return $this->rawSmart(false, true);
- }
-
- /**
- * @return bool
- */
- public function RawUserBackground()
- {
- $sRawKey = (string) $this->GetActionParam('RawKey', '');
- $this->verifyCacheByKey($sRawKey);
-
- $oAccount = $this->getAccountFromToken();
-
- $sData = $this->StorageProvider()->Get($oAccount,
- \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
- 'background'
- );
-
- if (!empty($sData))
- {
- $aData = \json_decode($sData, true);
- unset($sData);
-
- if (!empty($aData['ContentType']) && !empty($aData['Raw']) &&
- \in_array($aData['ContentType'], array('image/png', 'image/jpg', 'image/jpeg')))
- {
- $this->cacheByKey($sRawKey);
-
- @\header('Content-Type: '.$aData['ContentType']);
- echo \base64_decode($aData['Raw']);
- unset($aData);
-
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * @return bool
- */
- public function RawPublic()
- {
- $sRawKey = (string) $this->GetActionParam('RawKey', '');
- $this->verifyCacheByKey($sRawKey);
-
- $sHash = $sRawKey;
- $sData = '';
-
- if (!empty($sHash))
- {
- $sData = $this->StorageProvider()->Get(null,
- \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
- \RainLoop\KeyPathHelper::PublicFile($sHash)
- );
- }
-
- $aMatch = array();
- if (!empty($sData) && 0 === \strpos($sData, 'data:') &&
- \preg_match('/^data:([^:]+):/', $sData, $aMatch) && !empty($aMatch[1]))
- {
- $sContentType = \trim($aMatch[1]);
- if (\in_array($sContentType, array('image/png', 'image/jpg', 'image/jpeg')))
- {
- $this->cacheByKey($sRawKey);
-
- @\header('Content-Type: '.$sContentType);
- echo \preg_replace('/^data:[^:]+:/', '', $sData);
- unset($sData);
-
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * @param string $sFileName
- *
- * @return bool
- */
- public function isFileHasFramedPreview($sFileName)
- {
- $sExt = \MailSo\Base\Utils::GetFileExtension($sFileName);
- return \in_array($sExt, array('doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'));
- }
-
- /**
- * @param string $sFileName
- *
- * @return bool
- */
- public function isFileHasThumbnail($sFileName)
- {
- static $aCache = array();
-
- $sExt = \MailSo\Base\Utils::GetFileExtension($sFileName);
- if (isset($aCache[$sExt]))
- {
- return $aCache[$sExt];
- }
-
- $bResult = \function_exists('gd_info');
- if ($bResult)
- {
- $bResult = false;
- switch ($sExt)
- {
- case 'png':
- $bResult = \function_exists('imagecreatefrompng');
- break;
- case 'gif':
- $bResult = \function_exists('imagecreatefromgif');
- break;
- case 'jpg':
- case 'jpeg':
- $bResult = \function_exists('imagecreatefromjpeg');
- break;
- }
- }
-
- $aCache[$sExt] = $bResult;
-
- return $bResult;
- }
-
- /**
- * @return bool
- */
- public function RawAvatar()
- {
- $sData = '';
-
- $sRawKey = (string) $this->GetActionParam('RawKey', '');
- $sRawKey = \urldecode($sRawKey);
-
- $this->verifyCacheByKey($sRawKey);
-
- if (0 < \strlen($sRawKey) && \preg_match('/^[^@]+@([^@]+)$/', $sRawKey))
- {
- $sEmail = \MailSo\Base\Utils::IdnToAscii($sRawKey, true);
-
- $iCode = 0;
- $sContentType = '';
-
- $sGravatarUrl = 'http://gravatar.com/avatar/'.\md5(strtolower($sEmail)).'.jpg?s=80&d=404';
-
- $this->Logger()->Write('gravatar: '.$sGravatarUrl);
-
- $sData = $this->Http()->GetUrlAsString($sGravatarUrl, null, $sContentType, $iCode, null, 5,
- $this->Config()->Get('labs', 'curl_proxy', ''), $this->Config()->Get('labs', 'curl_proxy_auth', ''));
-
- $sContentType = \strtolower(\trim($sContentType));
- if (200 !== $iCode || empty($sData) || !\in_array($sContentType, array('image/jpeg', 'image/jpg', 'image/png')))
- {
- $this->Logger()->Write('gravatar: code: '.$iCode.', content-type: '.$sContentType);
-
- $sData = '';
-
- $aMatch = array();
- if (\preg_match('/^[^@]+@([a-z0-9\-\.]+)$/', $sEmail, $aMatch) && !empty($aMatch[1]))
- {
- $sDomain = $aMatch[1];
- if (\file_exists(APP_VERSION_ROOT_PATH.'app/resources/images/services/'.$sDomain.'.png'))
- {
- $sContentType = 'image/png';
- $sData = \file_get_contents(APP_VERSION_ROOT_PATH.'app/resources/images/services/'.$sDomain.'.png');
- }
- }
- }
- }
-
- if (empty($sData) || empty($sContentType))
- {
- $sContentType = 'image/png';
- $sData = \file_get_contents(APP_VERSION_ROOT_PATH.'app/resources/images/empty-contact.png');
- }
-
- $this->cacheByKey($sRawKey);
- \header('Content-Type: '.$sContentType);
- echo $sData;
- return true;
- }
-
- /**
- * @return bool
- */
- public function RawContactsVcf()
- {
- $oAccount = $this->getAccountFromToken();
-
- \header('Content-Type: text/x-vcard; charset=UTF-8');
- \header('Content-Disposition: attachment; filename="contacts.vcf"', true);
- \header('Accept-Ranges: none', true);
- \header('Content-Transfer-Encoding: binary');
-
- $this->oHttp->ServerNoCache();
-
- return $this->AddressBookProvider($oAccount)->IsActive() ?
- $this->AddressBookProvider($oAccount)->Export($oAccount->ParentEmailHelper(), 'vcf') : false;
- }
-
- /**
- * @return bool
- */
- public function RawContactsCsv()
- {
- $oAccount = $this->getAccountFromToken();
-
- \header('Content-Type: text/csv; charset=UTF-8');
- \header('Content-Disposition: attachment; filename="contacts.csv"', true);
- \header('Accept-Ranges: none', true);
- \header('Content-Transfer-Encoding: binary');
-
- $this->oHttp->ServerNoCache();
-
- return $this->AddressBookProvider($oAccount)->IsActive() ?
- $this->AddressBookProvider($oAccount)->Export($oAccount->ParentEmailHelper(), 'csv') : false;
- }
-
- /**
- * @return \RainLoop\Model\Account|bool
- */
- private function initMailClientConnection()
- {
- $oAccount = null;
-
- if (!$this->MailClient()->IsLoggined())
- {
- $oAccount = $this->getAccountFromToken();
-
- try
- {
- $oAccount->IncConnectAndLoginHelper($this->Plugins(), $this->MailClient(), $this->Config());
- }
- catch (\MailSo\Net\Exceptions\ConnectionException $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::ConnectionError, $oException);
- }
- catch (\Exception $oException)
- {
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError, $oException);
- }
-
- $this->MailClient()->ImapClient()->__FORCE_SELECT_ON_EXAMINE__ = !!$this->Config()->Get('labs', 'use_imap_force_selection');
- }
-
- return $oAccount;
- }
-
- /**
- * @param string $sRawKey
- *
- * @return array | false
- */
- private function getDecodedRawKeyValue($sRawKey)
- {
- $bResult = false;
- if (!empty($sRawKey))
- {
- $aValues = \RainLoop\Utils::DecodeKeyValuesQ($sRawKey);
- if (is_array($aValues))
- {
- $bResult = $aValues;
- }
- }
-
- return $bResult;
- }
-
- /**
- * @param string $sRawKey
- * @param int | null $iLenCache
- * @return array | bool
- */
- private function getDecodedClientRawKeyValue($sRawKey, $iLenCache = null)
- {
- $mResult = false;
- if (!empty($sRawKey))
- {
- $sRawKey = \MailSo\Base\Utils::UrlSafeBase64Decode($sRawKey);
- $aValues = explode("\x0", $sRawKey);
-
- if (is_array($aValues) && (null === $iLenCache || $iLenCache === count($aValues)))
- {
- $mResult = $aValues;
- }
- }
-
- return $mResult;
- }
-
- /**
- * @return string
- */
- public function StaticCache()
- {
- static $sCache = null;
- if (!$sCache)
- {
- $sCache = \md5(APP_VERSION.$this->Plugins()->Hash());
- }
- return $sCache;
- }
-
- /**
- * @param string $sTheme
- *
- * @return string
- */
- public function ThemeLink($sTheme, $bAdmin)
- {
- return './?/Css/0/'.($bAdmin ? 'Admin' : 'User').'/-/'.$sTheme.'/-/'.$this->StaticCache().'/Hash/-/';
- }
-
- /**
- * @param string $sTheme
- *
- * @return string
- */
- public function ValidateTheme($sTheme, $bMobile = false)
- {
- if ($bMobile)
- {
- return 'Mobile';
- }
-
- return \in_array($sTheme, $this->GetThemes($bMobile)) ?
- $sTheme : $this->Config()->Get('themes', 'default', $bMobile ? 'Mobile' : 'Default');
- }
-
- /**
- * @param string $sLanguage
- * @param string $sDefault = ''
- * @param bool $bAdmin = false
- * @param bool $bAllowEmptyResult = false
- *
- * @return string
- */
- public function ValidateLanguage($sLanguage, $sDefault = '', $bAdmin = false, $bAllowEmptyResult = false)
- {
- $sResult = '';
- $aLang = $this->GetLanguages($bAdmin);
-
- if (\is_array($aLang))
- {
- $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');
-
- $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);
-
- if (\in_array($sLanguage, $aLang))
- {
- $sResult = $sLanguage;
- }
-
- if (empty($sResult) && !empty($sDefault) && \in_array($sDefault, $aLang))
- {
- $sResult = $sDefault;
- }
-
- if (empty($sResult) && !$bAllowEmptyResult)
- {
- $sResult = $this->Config()->Get('webmail', $bAdmin ? 'language_admin' : 'language', 'en_US');
- $sResult = \in_array($sResult, $aLang) ? $sResult : 'en_US';
- }
- }
-
- return $sResult;
- }
-
- /**
- * @param string $sType
- *
- * @return string
- */
- public function ValidateContactPdoType($sType)
- {
- return \in_array($sType, array('mysql', 'pgsql', 'sqlite')) ? $sType : 'sqlite';
- }
-
- /**
- * @staticvar array $aCache
- *
- * @return array
- */
- public function GetThemes($bMobile = false, $bIncludeMobile = true)
- {
- if ($bMobile)
- {
- return array('Mobile');
- }
-
- static $aCache = array('full' => null, 'mobile' => null);
- if ($bIncludeMobile && \is_array($aCache['full']))
- {
- return $aCache['full'];
- }
- else if ($bIncludeMobile && \is_array($aCache['mobile']))
- {
- return $aCache['mobile'];
- }
-
- $bClear = false;
- $bDefault = false;
- $sList = array();
- $sDir = APP_VERSION_ROOT_PATH.'themes';
- if (@\is_dir($sDir))
- {
- $rDirH = \opendir($sDir);
- if ($rDirH)
- {
- while (($sFile = \readdir($rDirH)) !== false)
- {
- if ('.' !== $sFile{0} && \is_dir($sDir.'/'.$sFile) && \file_exists($sDir.'/'.$sFile.'/styles.less'))
- {
- if ('Default' === $sFile)
- {
- $bDefault = true;
- }
- else if ('Clear' === $sFile)
- {
- $bClear = true;
- }
- else if ($bIncludeMobile || 'Mobile' !== $sFile)
- {
- $sList[] = $sFile;
- }
- }
- }
- @closedir($rDirH);
- }
- }
-
- $sDir = APP_INDEX_ROOT_PATH.'themes'; // custom user themes
- if (@\is_dir($sDir))
- {
- $rDirH = \opendir($sDir);
- if ($rDirH)
- {
- while (($sFile = \readdir($rDirH)) !== false)
- {
- if ('.' !== $sFile{0} && \is_dir($sDir.'/'.$sFile) && \file_exists($sDir.'/'.$sFile.'/styles.less'))
- {
- $sList[] = $sFile.'@custom';
- }
- }
-
- @\closedir($rDirH);
- }
- }
-
- $sList = \array_unique($sList);
- \sort($sList);
-
- if ($bDefault)
- {
- \array_unshift($sList, 'Default');
- }
-
- if ($bClear)
- {
- \array_push($sList, 'Clear');
- }
-
- $aCache[$bIncludeMobile ? 'full' : 'mobile'] = $sList;
- return $sList;
- }
-
- /**
- * @staticvar array $aCache
- * @param bool $bAdmin = false
- *
- * @return array
- */
- public function GetLanguages($bAdmin = false)
- {
- 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];
- }
-
- /**
- * @param string $sName
- * @param string $sHtml
- *
- * @return string
- */
- public function ProcessTemplate($sName, $sHtml)
- {
- $sHtml = $this->Plugins()->ProcessTemplate($sName, $sHtml);
- $sHtml = \preg_replace('/\{\{INCLUDE\/([a-zA-Z]+)\/PLACE\}\}/', '', $sHtml);
-
- $sHtml = \preg_replace('/';
- }
-
- unset($aTemplates);
-
- return $bJsOutput ? 'window.rainloopTEMPLATES='.\MailSo\Base\Utils::Php2js(array($sHtml), $this->Logger()).';' : $sHtml;
- }
-
- /**
- * @param string $sLanguage
- *
- * @return string
- */
- private function convertLanguageNameToMomentLanguageName($sLanguage)
- {
- $aHelper = array('en_gb' => 'en-gb', 'fr_ca' => 'fr-ca', 'pt_br' => 'pt-br',
- 'uk_ua' => 'ua', 'zh_cn' => 'zh-cn', 'zh_tw' => 'zh-tw', 'fa_ir' => 'fa');
-
- return isset($aHelper[$sLanguage]) ? $aHelper[$sLanguage] : \substr($sLanguage, 0, 2);
- }
-
- /**
- * @param string $sLanguage
- * @param bool $bAdmin = false
- * @param bool $bWrapByScriptTag = true
- *
- * @return string
- */
- private function compileLanguage($sLanguage, $bAdmin = false, $bWrapByScriptTag = true)
- {
- $aResultLang = array();
-
- $sMoment = 'window.moment && window.moment.locale && window.moment.locale(\'en\');';
- $sMomentFileName = APP_VERSION_ROOT_PATH.'app/localization/moment/'.
- $this->convertLanguageNameToMomentLanguageName($sLanguage).'.js';
-
- if (\file_exists($sMomentFileName))
- {
- $sMoment = \file_get_contents($sMomentFileName);
- $sMoment = \preg_replace('/\/\/[^\n]+\n/', '', $sMoment);
- }
-
- \RainLoop\Utils::ReadAndAddLang(APP_VERSION_ROOT_PATH.'app/localization/langs.yml', $aResultLang);
- \RainLoop\Utils::ReadAndAddLang(APP_VERSION_ROOT_PATH.'app/localization/'.
- ($bAdmin ? 'admin' : 'webmail').'/_source.en.yml', $aResultLang);
- \RainLoop\Utils::ReadAndAddLang(APP_VERSION_ROOT_PATH.'app/localization/'.
- ($bAdmin ? 'admin' : 'webmail').'/'.$sLanguage.'.yml', $aResultLang);
-
- $this->Plugins()->ReadLang($sLanguage, $aResultLang);
-
- $sLangJs = '';
- $aLangKeys = \array_keys($aResultLang);
- foreach ($aLangKeys as $sKey)
- {
- $sString = isset($aResultLang[$sKey]) ? $aResultLang[$sKey] : $sKey;
- if (\is_array($sString))
- {
- $sString = \implode("\n", $sString);
- }
-
- $sLangJs .= '"'.\str_replace('"', '\\"', \str_replace('\\', '\\\\', $sKey)).'":'
- .'"'.\str_replace(array("\r", "\n", "\t"), array('\r', '\n', '\t'),
- \str_replace('"', '\\"', \str_replace('\\', '\\\\', $sString))).'",';
- }
-
- $sResult = empty($sLangJs) ? 'null' : '{'.\substr($sLangJs, 0, -1).'}';
-
- return
- ($bWrapByScriptTag ? '' : '')
- ;
- }
-
- /**
- * @param array $aAppData
- * @param bool $bWrapByScriptTag = true
- *
- * @return string
- */
- private function compileAppData($aAppData, $bWrapByScriptTag = true)
- {
- return
- ($bWrapByScriptTag ? '' : '')
- ;
- }
-}
+oHttp = $oHttp;
+ $this->oActions = $oActions;
+ $this->aPaths = array();
+ $this->sQuery = '';
+ }
+
+ /**
+ * @return \MailSo\Log\Logger
+ */
+ public function Logger()
+ {
+ return $this->oActions->Logger();
+ }
+
+ /**
+ * @return \RainLoop\Plugins\Manager
+ */
+ public function Plugins()
+ {
+ return $this->oActions->Plugins();
+ }
+
+ /**
+ * @return \RainLoop\Application
+ */
+ public function Config()
+ {
+ return $this->oActions->Config();
+ }
+
+ /**
+ * @return \MailSo\Cache\CacheClient
+ */
+ public function Cacher()
+ {
+ return $this->oActions->Cacher();
+ }
+
+ /**
+ * @return \RainLoop\Providers\Storage
+ */
+ public function StorageProvider()
+ {
+ return $this->oActions->StorageProvider();
+ }
+
+ /**
+ * @return \RainLoop\Providers\Settings
+ */
+ public function SettingsProvider()
+ {
+ return $this->oActions->SettingsProvider();
+ }
+
+ /**
+ * @param array $aPaths
+ *
+ * @return \RainLoop\ServiceActions
+ */
+ public function SetPaths($aPaths)
+ {
+ $this->aPaths = \is_array($aPaths) ? $aPaths : array();
+ return $this;
+ }
+
+ /**
+ * @param string $sQuery
+ *
+ * @return \RainLoop\ServiceActions
+ */
+ public function SetQuery($sQuery)
+ {
+ $this->sQuery = $sQuery;
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceAjax()
+ {
+ @\ob_start();
+
+ $aResponseItem = null;
+ $oException = null;
+
+ $sAction = $this->oHttp->GetPost('Action', null);
+ if (empty($sAction) && $this->oHttp->IsGet() && !empty($this->aPaths[2]))
+ {
+ $sAction = $this->aPaths[2];
+ }
+
+ try
+ {
+ if ($this->oHttp->IsPost() && !in_array($sAction, array('JsInfo', 'JsError')) &&
+ $this->Config()->Get('security', 'csrf_protection', false) &&
+ $this->oHttp->GetPost('XToken', '') !== \RainLoop\Utils::GetCsrfToken())
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::InvalidToken);
+ }
+ else if (!empty($sAction))
+ {
+ $sMethodName = 'Do'.$sAction;
+
+ $this->Logger()->Write('Action: '.$sMethodName, \MailSo\Log\Enumerations\Type::NOTE, 'AJAX');
+
+ $aPost = $this->oHttp->GetPostAsArray();
+ if (\is_array($aPost) && 0 < \count($aPost))
+ {
+ $this->oActions->SetActionParams($aPost, $sMethodName);
+ switch ($sMethodName)
+ {
+ case 'DoLogin':
+ case 'DoAdminLogin':
+ case 'DoAccountAdd':
+ $this->Logger()->AddSecret($this->oActions->GetActionParam('Password', ''));
+ break;
+ case 'DoChangePassword':
+ $this->Logger()->AddSecret($this->oActions->GetActionParam('PrevPassword', ''));
+ $this->Logger()->AddSecret($this->oActions->GetActionParam('NewPassword', ''));
+ break;
+ }
+
+ $this->Logger()->Write(\MailSo\Base\Utils::Php2js($aPost, $this->Logger()),
+ \MailSo\Log\Enumerations\Type::INFO, 'POST', true);
+ }
+ else if (3 < \count($this->aPaths) && $this->oHttp->IsGet())
+ {
+ $this->oActions->SetActionParams(array(
+ 'RawKey' => empty($this->aPaths[3]) ? '' : $this->aPaths[3]
+ ), $sMethodName);
+ }
+
+ if (\method_exists($this->oActions, $sMethodName) &&
+ \is_callable(array($this->oActions, $sMethodName)))
+ {
+ $this->Plugins()->RunHook('ajax.action-pre-call', array($sAction));
+ $aResponseItem = \call_user_func(array($this->oActions, $sMethodName));
+ $this->Plugins()->RunHook('ajax.action-post-call', array($sAction, &$aResponseItem));
+ }
+ else if ($this->Plugins()->HasAdditionalAjax($sMethodName))
+ {
+ $this->Plugins()->RunHook('ajax.action-pre-call', array($sAction));
+ $aResponseItem = $this->Plugins()->RunAdditionalAjax($sMethodName);
+ $this->Plugins()->RunHook('ajax.action-post-call', array($sAction, &$aResponseItem));
+ }
+ }
+
+ if (!\is_array($aResponseItem))
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::UnknownError);
+ }
+ }
+ catch (\Exception $oException)
+ {
+ $aResponseItem = $this->oActions->ExceptionResponse(
+ empty($sAction) ? 'Unknown' : $sAction, $oException);
+
+ if (\is_array($aResponseItem) && $oException instanceof \RainLoop\Exceptions\ClientException)
+ {
+ if ('Folders' === $sAction)
+ {
+ $aResponseItem['ClearAuth'] = true;
+ }
+
+ if ($oException->getLogoutOnException())
+ {
+ $aResponseItem['Logout'] = true;
+ if ($oException->getAdditionalMessage())
+ {
+ $this->oActions->SetSpecLogoutCustomMgsWithDeletion($oException->getAdditionalMessage());
+ }
+ }
+ }
+ }
+
+ if (\is_array($aResponseItem))
+ {
+ $aResponseItem['Time'] = (int) ((\microtime(true) - APP_START) * 1000);
+ }
+
+ $this->Plugins()->RunHook('filter.ajax-response', array($sAction, &$aResponseItem));
+
+ @\header('Content-Type: application/json; charset=utf-8');
+
+ $sResult = \MailSo\Base\Utils::Php2js($aResponseItem, $this->Logger());
+
+ $sObResult = @\ob_get_clean();
+
+ if ($this->Logger()->IsEnabled())
+ {
+ if (0 < \strlen($sObResult))
+ {
+ $this->Logger()->Write($sObResult, \MailSo\Log\Enumerations\Type::ERROR, 'OB-DATA');
+ }
+
+ if ($oException)
+ {
+ $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
+ }
+
+ $iLimit = (int) $this->Config()->Get('labs', 'log_ajax_response_write_limit', 0);
+ $this->Logger()->Write(0 < $iLimit && $iLimit < \strlen($sResult)
+ ? \substr($sResult, 0, $iLimit).'...' : $sResult, \MailSo\Log\Enumerations\Type::INFO, 'AJAX');
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceOwnCloudAuth()
+ {
+ $this->oHttp->ServerNoCache();
+
+ if (!\RainLoop\Utils::IsOwnCloud() ||
+ !isset($_ENV['___rainloop_owncloud_email']) ||
+ !isset($_ENV['___rainloop_owncloud_password']) ||
+ empty($_ENV['___rainloop_owncloud_email'])
+ )
+ {
+ $this->oActions->SetAuthLogoutToken();
+ $this->oActions->Location('./');
+ return '';
+ }
+
+ $bLogout = true;
+
+ $sEmail = $_ENV['___rainloop_owncloud_email'];
+ $sPassword = $_ENV['___rainloop_owncloud_password'];
+
+ try
+ {
+ $oAccount = $this->oActions->LoginProcess($sEmail, $sPassword);
+ $this->oActions->AuthToken($oAccount);
+
+ $bLogout = !($oAccount instanceof \RainLoop\Model\Account);
+ }
+ catch (\Exception $oException)
+ {
+ $this->oActions->Logger()->WriteException($oException);
+ }
+
+ if ($bLogout)
+ {
+ $this->oActions->SetAuthLogoutToken();
+ }
+
+ $this->oActions->Location('./');
+ return '';
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceAppend()
+ {
+ @\ob_start();
+ $bResponse = false;
+ $oException = null;
+ try
+ {
+ if (\method_exists($this->oActions, 'Append') &&
+ \is_callable(array($this->oActions, 'Append')))
+ {
+ $this->oActions->SetActionParams($this->oHttp->GetPostAsArray(), 'Append');
+ $bResponse = \call_user_func(array($this->oActions, 'Append'));
+ }
+ }
+ catch (\Exception $oException)
+ {
+ $bResponse = false;
+ }
+
+ @\header('Content-Type: text/plain; charset=utf-8');
+ $sResult = true === $bResponse ? '1' : '0';
+
+ $sObResult = @\ob_get_clean();
+ if (0 < \strlen($sObResult))
+ {
+ $this->Logger()->Write($sObResult, \MailSo\Log\Enumerations\Type::ERROR, 'OB-DATA');
+ }
+
+ if ($oException)
+ {
+ $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
+ }
+
+ $this->Logger()->Write($sResult, \MailSo\Log\Enumerations\Type::INFO, 'APPEND');
+
+ return $sResult;
+ }
+
+ /**
+ * @param string $sAction
+ * @param int $iSizeLimit = 0
+ *
+ * @return string
+ */
+ private function privateUpload($sAction, $iSizeLimit = 0)
+ {
+ $oConfig = $this->Config();
+
+ @\ob_start();
+ $aResponseItem = null;
+ try
+ {
+ $aFile = null;
+ $sInputName = 'uploader';
+ $iError = \RainLoop\Enumerations\UploadError::UNKNOWN;
+ $iSizeLimit = (0 < $iSizeLimit ? $iSizeLimit : ((int) $oConfig->Get('webmail', 'attachment_size_limit', 0))) * 1024 * 1024;
+
+ $iError = UPLOAD_ERR_OK;
+ $_FILES = isset($_FILES) ? $_FILES : null;
+ if (isset($_FILES, $_FILES[$sInputName], $_FILES[$sInputName]['name'], $_FILES[$sInputName]['tmp_name'], $_FILES[$sInputName]['size']))
+ {
+ $iError = (isset($_FILES[$sInputName]['error'])) ? (int) $_FILES[$sInputName]['error'] : UPLOAD_ERR_OK;
+
+ if (UPLOAD_ERR_OK === $iError && 0 < $iSizeLimit && $iSizeLimit < (int) $_FILES[$sInputName]['size'])
+ {
+ $iError = \RainLoop\Enumerations\UploadError::CONFIG_SIZE;
+ }
+
+ if (UPLOAD_ERR_OK === $iError)
+ {
+ $aFile = $_FILES[$sInputName];
+ }
+ }
+ else if (!isset($_FILES) || !is_array($_FILES) || 0 === count($_FILES))
+ {
+ $iError = UPLOAD_ERR_INI_SIZE;
+ }
+ else
+ {
+ $iError = \RainLoop\Enumerations\UploadError::EMPTY_FILES_DATA;
+ }
+
+ if (\method_exists($this->oActions, $sAction) &&
+ \is_callable(array($this->oActions, $sAction)))
+ {
+ $aActionParams = $this->oHttp->GetQueryAsArray();
+
+ $aActionParams['File'] = $aFile;
+ $aActionParams['Error'] = $iError;
+
+ $this->oActions->SetActionParams($aActionParams, $sAction);
+
+ $aResponseItem = \call_user_func(array($this->oActions, $sAction));
+ }
+
+ if (!is_array($aResponseItem))
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::UnknownError);
+ }
+ }
+ catch (\Exception $oException)
+ {
+ $aResponseItem = $this->oActions->ExceptionResponse($sAction, $oException);
+ }
+
+ if ('iframe' === $this->oHttp->GetPost('jua-post-type', ''))
+ {
+ @\header('Content-Type: text/html; charset=utf-8');
+ }
+ else
+ {
+ @\header('Content-Type: application/json; charset=utf-8');
+ }
+
+ $this->Plugins()->RunHook('filter.upload-response', array(&$aResponseItem));
+ $sResult = \MailSo\Base\Utils::Php2js($aResponseItem, $this->Logger());
+
+ $sObResult = @\ob_get_clean();
+ if (0 < \strlen($sObResult))
+ {
+ $this->Logger()->Write($sObResult, \MailSo\Log\Enumerations\Type::ERROR, 'OB-DATA');
+ }
+
+ $this->Logger()->Write($sResult, \MailSo\Log\Enumerations\Type::INFO, 'UPLOAD');
+
+ return $sResult;
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceUpload()
+ {
+ return $this->privateUpload('Upload');
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceUploadContacts()
+ {
+ return $this->privateUpload('UploadContacts', 5);
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceUploadBackground()
+ {
+ return $this->privateUpload('UploadBackground', 1);
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceProxyExternal()
+ {
+ $bResult = false;
+ $sData = empty($this->aPaths[1]) ? '' : $this->aPaths[1];
+ if (!empty($sData) && $this->oActions->Config()->Get('labs', 'use_local_proxy_for_external_images', false))
+ {
+ $this->oActions->verifyCacheByKey($sData);
+
+ $aData = \RainLoop\Utils::DecodeKeyValuesQ($sData);
+ if (\is_array($aData) && !empty($aData['Token']) && !empty($aData['Url']) && $aData['Token'] === \RainLoop\Utils::GetConnectionToken())
+ {
+ $iCode = 404;
+ $sContentType = '';
+ $mResult = $this->oHttp->GetUrlAsString($aData['Url'], 'RainLoop External Proxy', $sContentType, $iCode);
+
+ if (false !== $mResult && 200 === $iCode &&
+ \in_array($sContentType, array('image/png', 'image/jpeg', 'image/jpg', 'image/bmp', 'image/gif')))
+ {
+ $bResult = true;
+
+ $this->oActions->cacheByKey($sData);
+
+ \header('Content-Type: '.$sContentType);
+ echo $mResult;
+ }
+ }
+ }
+
+ if (!$bResult)
+ {
+ $this->oHttp->StatusHeader(404);
+ }
+
+ return '';
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceRaw()
+ {
+ $sResult = '';
+ $sRawError = '';
+ $sAction = empty($this->aPaths[2]) ? '' : $this->aPaths[2];
+ $oException = null;
+
+ try
+ {
+ $sRawError = 'Invalid action';
+ if (0 !== \strlen($sAction))
+ {
+ $sMethodName = 'Raw'.$sAction;
+ if (\method_exists($this->oActions, $sMethodName))
+ {
+ @\header('X-Raw-Action: '.$sMethodName, true);
+
+ $sRawError = '';
+ $this->oActions->SetActionParams(array(
+ 'RawKey' => empty($this->aPaths[3]) ? '' : $this->aPaths[3],
+ 'Params' => $this->aPaths
+ ), $sMethodName);
+
+ if (!\call_user_func(array($this->oActions, $sMethodName)))
+ {
+ $sRawError = 'False result';
+ }
+ else
+ {
+ $sRawError = '';
+ }
+ }
+ else
+ {
+ $sRawError = 'Unknown action "'.$sAction.'"';
+ }
+ }
+ else
+ {
+ $sRawError = 'Empty action';
+ }
+ }
+ catch (\RainLoop\Exceptions\ClientException $oException)
+ {
+ $sRawError = 'Exception as result';
+ switch ($oException->getCode())
+ {
+ case \RainLoop\Notifications::AuthError:
+ $sRawError = 'Authentication failed';
+ break;
+ }
+ }
+ catch (\Exception $oException)
+ {
+ $sRawError = 'Exception as result';
+ }
+
+ if (0 < \strlen($sRawError))
+ {
+ $this->oActions->Logger()->Write($sRawError, \MailSo\Log\Enumerations\Type::ERROR);
+ $this->oActions->Logger()->WriteDump($this->aPaths, \MailSo\Log\Enumerations\Type::ERROR, 'PATHS');
+ }
+
+ if ($oException)
+ {
+ $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR, 'RAW');
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceLang()
+ {
+// sleep(2);
+ $sResult = '';
+ @\header('Content-Type: application/javascript; charset=utf-8');
+
+ if (!empty($this->aPaths[3]))
+ {
+ $bAdmim = 'Admin' === (isset($this->aPaths[2]) ? (string) $this->aPaths[2] : 'App');
+ $sLanguage = $this->oActions->ValidateLanguage($this->aPaths[3], '', $bAdmim);
+
+ $bCacheEnabled = $this->Config()->Get('labs', 'cache_system_data', true);
+ if (!empty($sLanguage) && $bCacheEnabled)
+ {
+ $this->oActions->verifyCacheByKey($this->sQuery);
+ }
+
+ $sCacheFileName = '';
+ if ($bCacheEnabled)
+ {
+ $sCacheFileName = \RainLoop\KeyPathHelper::LangCache(
+ $sLanguage, $bAdmim, $this->oActions->Plugins()->Hash());
+
+ $sResult = $this->Cacher()->Get($sCacheFileName);
+ }
+
+ if (0 === \strlen($sResult))
+ {
+ $sResult = $this->compileLanguage($sLanguage, $bAdmim, false);
+ if ($bCacheEnabled && 0 < \strlen($sCacheFileName))
+ {
+ $this->Cacher()->Set($sCacheFileName, $sResult);
+ }
+ }
+
+ if ($bCacheEnabled)
+ {
+ $this->oActions->cacheByKey($this->sQuery);
+ }
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceTemplates()
+ {
+ $sResult = '';
+ @\header('Content-Type: application/javascript; charset=utf-8');
+
+ $bCacheEnabled = $this->Config()->Get('labs', 'cache_system_data', true);
+ if ($bCacheEnabled)
+ {
+ $this->oActions->verifyCacheByKey($this->sQuery);
+ }
+
+ $bAdmin = false !== \strpos($this->sQuery, 'Admin');
+
+ $sCacheFileName = '';
+ if ($bCacheEnabled)
+ {
+ $sCacheFileName = \RainLoop\KeyPathHelper::TemplatesCache($bAdmin, $this->oActions->Plugins()->Hash());
+ $sResult = $this->Cacher()->Get($sCacheFileName);
+ }
+
+ if (0 === \strlen($sResult))
+ {
+ $sResult = $this->compileTemplates($bAdmin);
+ if ($bCacheEnabled && 0 < \strlen($sCacheFileName))
+ {
+ $this->Cacher()->Set($sCacheFileName, $sResult);
+ }
+ }
+
+ if ($bCacheEnabled)
+ {
+ $this->oActions->cacheByKey($this->sQuery);
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @return string
+ */
+ public function ServicePlugins()
+ {
+ $sResult = '';
+ $bAdmin = !empty($this->aPaths[2]) && 'Admin' === $this->aPaths[2];
+
+ @\header('Content-Type: application/javascript; charset=utf-8');
+
+ $bCacheEnabled = $this->Config()->Get('labs', 'cache_system_data', true);
+ if ($bCacheEnabled)
+ {
+ $this->oActions->verifyCacheByKey($this->sQuery);
+ }
+
+ $sCacheFileName = '';
+ if ($bCacheEnabled)
+ {
+ $sCacheFileName = \RainLoop\KeyPathHelper::PluginsJsCache($this->oActions->Plugins()->Hash());
+ $sResult = $this->Cacher()->Get($sCacheFileName);
+ }
+
+ if (0 === strlen($sResult))
+ {
+ $sResult = $this->Plugins()->CompileJs($bAdmin);
+ if ($bCacheEnabled && 0 < \strlen($sCacheFileName))
+ {
+ $this->Cacher()->Set($sCacheFileName, $sResult);
+ }
+ }
+
+ if ($bCacheEnabled)
+ {
+ $this->oActions->cacheByKey($this->sQuery);
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceCss()
+ {
+ $sResult = '';
+
+ $bAdmin = !empty($this->aPaths[2]) && 'Admin' === $this->aPaths[2];
+ $bJson = !empty($this->aPaths[9]) && 'Json' === $this->aPaths[9];
+
+ if ($bJson)
+ {
+ @\header('Content-Type: application/json; charset=utf-8');
+ }
+ else
+ {
+ @\header('Content-Type: text/css; charset=utf-8');
+ }
+
+ $sTheme = '';
+ if (!empty($this->aPaths[4]))
+ {
+ $sTheme = $this->oActions->ValidateTheme($this->aPaths[4]);
+ $sRealTheme = $sTheme;
+
+ $bCustomTheme = '@custom' === \substr($sTheme, -7);
+ if ($bCustomTheme)
+ {
+ $sRealTheme = \substr($sTheme, 0, -7);
+ }
+
+ $bCacheEnabled = $this->Config()->Get('labs', 'cache_system_data', true);
+ if ($bCacheEnabled)
+ {
+ $this->oActions->verifyCacheByKey($this->sQuery);
+ }
+
+ $sCacheFileName = '';
+ if ($bCacheEnabled)
+ {
+ $sCacheFileName = \RainLoop\KeyPathHelper::CssCache($sTheme, $this->oActions->Plugins()->Hash());
+ $sResult = $this->Cacher()->Get($sCacheFileName);
+ }
+
+ if (0 === \strlen($sResult))
+ {
+ try
+ {
+ include_once APP_VERSION_ROOT_PATH.'app/libraries/lessphp/ctype.php';
+ include_once APP_VERSION_ROOT_PATH.'app/libraries/lessphp/lessc.inc.php';
+
+ $oLess = new \RainLoopVendor\lessc();
+ $oLess->setFormatter('compressed');
+
+ $aResult = array();
+
+ $sThemeFile = ($bCustomTheme ? APP_INDEX_ROOT_PATH : APP_VERSION_ROOT_PATH).'themes/'.$sRealTheme.'/styles.less';
+ $sThemeExtFile = ($bCustomTheme ? APP_INDEX_ROOT_PATH : APP_VERSION_ROOT_PATH).'themes/'.$sRealTheme.'/ext.less';
+
+ $sThemeValuesFile = APP_VERSION_ROOT_PATH.'app/templates/Themes/values.less';
+ $sThemeTemplateFile = APP_VERSION_ROOT_PATH.'app/templates/Themes/template.less';
+
+ if (\file_exists($sThemeFile) && \file_exists($sThemeTemplateFile) && \file_exists($sThemeValuesFile))
+ {
+ $aResult[] = '@base: "'.
+ ($bCustomTheme ? \RainLoop\Utils::WebPath() : \RainLoop\Utils::WebVersionPath()).
+ 'themes/'.$sRealTheme.'/";';
+
+ $aResult[] = \file_get_contents($sThemeValuesFile);
+ $aResult[] = \file_get_contents($sThemeFile);
+ $aResult[] = \file_get_contents($sThemeTemplateFile);
+
+ if (\file_exists($sThemeExtFile))
+ {
+ $aResult[] = \file_get_contents($sThemeExtFile);
+ }
+ }
+
+ $aResult[] = $this->Plugins()->CompileCss($bAdmin);
+
+ $sResult = $oLess->compile(\implode("\n", $aResult));
+
+ if ($bCacheEnabled)
+ {
+ if (0 < \strlen($sCacheFileName))
+ {
+ $this->Cacher()->Set($sCacheFileName, $sResult);
+ }
+ }
+ }
+ catch (\Exception $oException)
+ {
+ $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR, 'LESS');
+ }
+ }
+
+ if ($bCacheEnabled)
+ {
+ $this->oActions->cacheByKey($this->sQuery);
+ }
+ }
+
+ return $bJson ? \MailSo\Base\Utils::Php2js(array($sTheme, $sResult), $this->Logger()) : $sResult;
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceSocialGoogle()
+ {
+ $bXAuth = '1' === (string) $this->oHttp->GetQuery('xauth', '0');
+ return $this->oActions->Social()->GooglePopupService($bXAuth);
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceSocialFacebook()
+ {
+ return $this->oActions->Social()->FacebookPopupService();
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceSocialTwitter()
+ {
+ return $this->oActions->Social()->TwitterPopupService();
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceAppData($sAdd = '')
+ {
+ return $this->localAppData(false, $sAdd);
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceAdminAppData($sAdd = '')
+ {
+ return $this->localAppData(true, $sAdd);
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceMobileVersion()
+ {
+ \RainLoop\Utils::SetCookie(\RainLoop\Actions::RL_MOBILE_TYPE, 'mobile');
+ $this->oActions->Location('./');
+ return '';
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceDesktopVersion()
+ {
+ \RainLoop\Utils::SetCookie(\RainLoop\Actions::RL_MOBILE_TYPE, 'desktop');
+ $this->oActions->Location('./');
+ return '';
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceNoScript()
+ {
+ return $this->localError($this->oActions->StaticI18N('STATIC/NO_SCRIPT_TITLE'), $this->oActions->StaticI18N('STATIC/NO_SCRIPT_DESC'));
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceNoCookie()
+ {
+ return $this->localError($this->oActions->StaticI18N('STATIC/NO_COOKIE_TITLE'), $this->oActions->StaticI18N('STATIC/NO_COOKIE_DESC'));
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceBadBrowser()
+ {
+ $sTitle = $this->oActions->StaticI18N('STATIC/BAD_BROWSER_TITLE');
+ $sDesc = \nl2br($this->oActions->StaticI18N('STATIC/BAD_BROWSER_DESC'));
+
+ @\header('Content-Type: text/html; charset=utf-8');
+ return \strtr(\file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/BadBrowser.html'), array(
+ '{{BaseWebStaticPath}}' => \RainLoop\Utils::WebStaticPath(),
+ '{{ErrorTitle}}' => $sTitle,
+ '{{ErrorHeader}}' => $sTitle,
+ '{{ErrorDesc}}' => $sDesc
+ ));
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceMailto()
+ {
+ $this->oHttp->ServerNoCache();
+
+ $sTo = \trim($this->oHttp->GetQuery('to', ''));
+ if (!empty($sTo) && \preg_match('/^mailto:/i', $sTo))
+ {
+ $oAccount = $this->oActions->GetAccountFromSignMeToken();
+ if ($oAccount)
+ {
+ $this->oActions->SetMailtoRequest($sTo);
+ }
+ }
+
+ $this->oActions->Location('./');
+ return '';
+ }
+
+ /**
+ * @return string
+ */
+ public function ServicePing()
+ {
+ $this->oHttp->ServerNoCache();
+
+ @\header('Content-Type: text/plain; charset=utf-8');
+ $this->oActions->Logger()->Write('Pong', \MailSo\Log\Enumerations\Type::INFO, 'PING');
+ return 'Pong';
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceInfo()
+ {
+ $this->oHttp->ServerNoCache();
+
+ if ($this->oActions->IsAdminLoggined(false))
+ {
+ @\header('Content-Type: text/html; charset=utf-8');
+ \phpinfo();
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceSso()
+ {
+ $this->oHttp->ServerNoCache();
+
+ $oException = null;
+ $oAccount = null;
+ $bLogout = true;
+
+ $sSsoHash = $this->oHttp->GetRequest('hash', '');
+ if (!empty($sSsoHash))
+ {
+ $mData = null;
+
+ $sSsoSubData = $this->Cacher()->Get(\RainLoop\KeyPathHelper::SsoCacherKey($sSsoHash));
+ if (!empty($sSsoSubData))
+ {
+ $mData = \RainLoop\Utils::DecodeKeyValuesQ($sSsoSubData);
+ $this->Cacher()->Delete(\RainLoop\KeyPathHelper::SsoCacherKey($sSsoHash));
+
+ if (\is_array($mData) && !empty($mData['Email']) && isset($mData['Password'], $mData['Time']) &&
+ (0 === $mData['Time'] || \time() - 10 < $mData['Time']))
+ {
+ $sEmail = \trim($mData['Email']);
+ $sPassword = $mData['Password'];
+
+ $aAdditionalOptions = isset($mData['AdditionalOptions']) && \is_array($mData['AdditionalOptions']) &&
+ 0 < \count($mData['AdditionalOptions']) ? $mData['AdditionalOptions'] : null;
+
+ try
+ {
+ $oAccount = $this->oActions->LoginProcess($sEmail, $sPassword);
+
+ if ($oAccount instanceof \RainLoop\Model\Account && $aAdditionalOptions)
+ {
+ $bNeedToSettings = false;
+
+ $oSettings = $this->SettingsProvider()->Load($oAccount);
+ if ($oSettings)
+ {
+ $sLanguage = isset($aAdditionalOptions['Language']) ?
+ $aAdditionalOptions['Language'] : '';
+
+ if ($sLanguage)
+ {
+ $sLanguage = $this->oActions->ValidateLanguage($sLanguage);
+ if ($sLanguage !== $oSettings->GetConf('Language', ''))
+ {
+ $bNeedToSettings = true;
+ $oSettings->SetConf('Language', $sLanguage);
+ }
+ }
+ }
+
+ if ($bNeedToSettings)
+ {
+ $this->SettingsProvider()->Save($oAccount, $oSettings);
+ }
+ }
+
+ $this->oActions->AuthToken($oAccount);
+
+ $bLogout = !($oAccount instanceof \RainLoop\Model\Account);
+ }
+ catch (\Exception $oException)
+ {
+ $this->oActions->Logger()->WriteException($oException);
+ }
+ }
+ }
+ }
+
+ if ($bLogout)
+ {
+ $this->oActions->SetAuthLogoutToken();
+ }
+
+ $this->oActions->Location('./');
+ return '';
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceRemoteAutoLogin()
+ {
+ $oException = null;
+ $oAccount = null;
+ $bLogout = true;
+
+ $sEmail = $this->oHttp->GetEnv('REMOTE_USER', '');
+ $sPassword = $this->oHttp->GetEnv('REMOTE_PASSWORD', '');
+
+ if (0 < \strlen($sEmail) && 0 < \strlen(\trim($sPassword)))
+ {
+ try
+ {
+ $oAccount = $this->oActions->LoginProcess($sEmail, $sPassword);
+ $this->oActions->AuthToken($oAccount);
+ $bLogout = !($oAccount instanceof \RainLoop\Model\Account);
+ }
+ catch (\Exception $oException)
+ {
+ $this->oActions->Logger()->WriteException($oException);
+ }
+ }
+
+ if ($bLogout)
+ {
+ $this->oActions->SetAuthLogoutToken();
+ }
+
+ $this->oActions->Location('./');
+ return '';
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceExternalLogin()
+ {
+ $this->oHttp->ServerNoCache();
+
+ $oException = null;
+ $oAccount = null;
+ $bLogout = true;
+
+ if ($this->oActions->Config()->Get('labs', 'allow_external_login', false))
+ {
+ $sEmail = \trim($this->oHttp->GetRequest('Email', ''));
+ $sPassword = $this->oHttp->GetRequest('Password', '');
+
+ try
+ {
+ $oAccount = $this->oActions->LoginProcess($sEmail, $sPassword);
+ $this->oActions->AuthToken($oAccount);
+ $bLogout = !($oAccount instanceof \RainLoop\Model\Account);
+ }
+ catch (\Exception $oException)
+ {
+ $this->oActions->Logger()->WriteException($oException);
+ }
+
+ if ($bLogout)
+ {
+ $this->oActions->SetAuthLogoutToken();
+ }
+ }
+
+ switch (\strtolower($this->oHttp->GetRequest('Output', 'Redirect')))
+ {
+ case 'json':
+
+ @\header('Content-Type: application/json; charset=utf-8');
+
+ $aResult = array(
+ 'Action' => 'ExternalLogin',
+ 'Result' => $oAccount instanceof \RainLoop\Model\Account ? true : false,
+ 'ErrorCode' => 0
+ );
+
+ if (!$aResult['Result'])
+ {
+ if ($oException instanceof \RainLoop\Exceptions\ClientException)
+ {
+ $aResult['ErrorCode'] = $oException->getCode();
+ }
+ else
+ {
+ $aResult['ErrorCode'] = \RainLoop\Notifications::AuthError;
+ }
+ }
+
+ return \MailSo\Base\Utils::Php2js($aResult, $this->Logger());
+
+ case 'redirect':
+ default:
+ $this->oActions->Location('./');
+ break;
+ }
+
+ return '';
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceExternalSso()
+ {
+ $this->oHttp->ServerNoCache();
+
+ $sResult = '';
+ $bLogout = true;
+ $sKey = $this->oActions->Config()->Get('labs', 'external_sso_key', '');
+ if ($this->oActions->Config()->Get('labs', 'allow_external_sso', false) &&
+ !empty($sKey) && $sKey === \trim($this->oHttp->GetRequest('SsoKey', '')))
+ {
+ $sEmail = \trim($this->oHttp->GetRequest('Email', ''));
+ $sPassword = $this->oHttp->GetRequest('Password', '');
+
+ $sResult = \RainLoop\Api::GetUserSsoHash($sEmail, $sPassword);
+ $bLogout = 0 === \strlen($sResult);
+
+ switch (\strtolower($this->oHttp->GetRequest('Output', 'Plain')))
+ {
+ case 'plain':
+ @\header('Content-Type: text/plain');
+ break;
+
+ case 'json':
+ @\header('Content-Type: application/json; charset=utf-8');
+ $sResult = \MailSo\Base\Utils::Php2js(array(
+ 'Action' => 'ExternalSso',
+ 'Result' => $sResult
+ ), $this->Logger());
+ break;
+ }
+ }
+
+ if ($bLogout)
+ {
+ $this->oActions->SetAuthLogoutToken();
+ }
+
+ return $sResult;
+ }
+
+ private function changeAction()
+ {
+ $this->oHttp->ServerNoCache();
+
+ $oAccount = $this->oActions->GetAccount();
+
+ if ($oAccount && $this->oActions->GetCapa(false, false, \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS, $oAccount))
+ {
+ $oAccountToLogin = null;
+ $sEmail = empty($this->aPaths[2]) ? '' : \urldecode(\trim($this->aPaths[2]));
+ if (!empty($sEmail))
+ {
+ $sEmail = \MailSo\Base\Utils::IdnToAscii($sEmail);
+
+ $aAccounts = $this->oActions->GetAccounts($oAccount);
+ if (isset($aAccounts[$sEmail]))
+ {
+ $oAccountToLogin = $this->oActions->GetAccountFromCustomToken($aAccounts[$sEmail], false, false);
+ }
+ }
+
+ if ($oAccountToLogin)
+ {
+ $this->oActions->AuthToken($oAccountToLogin);
+ }
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function ServiceChange()
+ {
+ $this->changeAction();
+ $this->oActions->Location('./');
+ return '';
+ }
+
+ /**
+ * @param string $sTitle
+ * @param string $sDesc
+ *
+ * @return mixed
+ */
+ public function ErrorTemplates($sTitle, $sDesc, $bShowBackLink = true)
+ {
+ return strtr(file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/Error.html'), array(
+ '{{BaseWebStaticPath}}' => \RainLoop\Utils::WebStaticPath(),
+ '{{ErrorTitle}}' => $sTitle,
+ '{{ErrorHeader}}' => $sTitle,
+ '{{ErrorDesc}}' => $sDesc,
+ '{{BackLinkVisibilityStyle}}' => $bShowBackLink ? 'display:inline-block' : 'display:none',
+ '{{BackLink}}' => $this->oActions->StaticI18N('STATIC/BACK_LINK'),
+ '{{BackHref}}' => './'
+ ));
+ }
+
+ /**
+ * @param string $sTitle
+ * @param string $sDesc
+ *
+ * @return string
+ */
+ private function localError($sTitle, $sDesc)
+ {
+ @header('Content-Type: text/html; charset=utf-8');
+ return $this->ErrorTemplates($sTitle, \nl2br($sDesc));
+ }
+
+ /**
+ * @param bool $bAdmin = true
+ * @param string $sAdd = ''
+ *
+ * @return string
+ */
+ private function localAppData($bAdmin = false, $sAdd = '')
+ {
+ @\header('Content-Type: application/javascript; charset=utf-8');
+ $this->oHttp->ServerNoCache();
+
+ $sAuthAccountHash = '';
+ if (!$bAdmin && 0 === \strlen($this->oActions->GetSpecAuthLogoutTokenWithDeletion()))
+ {
+ $sAuthAccountHash = $this->oActions->GetSpecAuthTokenWithDeletion();
+ if (empty($sAuthAccountHash))
+ {
+ $sAuthAccountHash = $this->oActions->GetSpecAuthToken();
+ }
+
+ if (empty($sAuthAccountHash))
+ {
+ $oAccount = $this->oActions->GetAccountFromSignMeToken();
+ if ($oAccount)
+ {
+ try
+ {
+ $this->oActions->CheckMailConnection($oAccount);
+
+ $this->oActions->AuthToken($oAccount);
+
+ $sAuthAccountHash = $this->oActions->GetSpecAuthToken();
+ }
+ catch (\Exception $oException)
+ {
+ $oException = null;
+ $this->oActions->ClearSignMeData($oAccount);
+ }
+ }
+ }
+
+ $this->oActions->SetSpecAuthToken($sAuthAccountHash);
+ }
+
+ $sResult = $this->compileAppData($this->oActions->AppData($bAdmin,
+ 0 === \strpos($sAdd, 'mobile'), '1' === \substr($sAdd, -1),
+ $sAuthAccountHash), false);
+
+ $this->Logger()->Write($sResult, \MailSo\Log\Enumerations\Type::INFO, 'APPDATA');
+
+ return $sResult;
+ }
+
+ /**
+ * @param bool $bAdmin = false
+ * @param bool $bJsOutput = true
+ *
+ * @return string
+ */
+ public function compileTemplates($bAdmin = false, $bJsOutput = true)
+ {
+ $aTemplates = array();
+
+ \RainLoop\Utils::CompileTemplates($aTemplates, APP_VERSION_ROOT_PATH.'app/templates/Views/Components', 'Component');
+ \RainLoop\Utils::CompileTemplates($aTemplates, APP_VERSION_ROOT_PATH.'app/templates/Views/'.($bAdmin ? 'Admin' : 'User'));
+ \RainLoop\Utils::CompileTemplates($aTemplates, APP_VERSION_ROOT_PATH.'app/templates/Views/Common');
+
+ $this->oActions->Plugins()->CompileTemplate($aTemplates, $bAdmin);
+
+ $sHtml = '';
+ foreach ($aTemplates as $sName => $sFile)
+ {
+ $sName = \preg_replace('/[^a-zA-Z0-9]/', '', $sName);
+ $sHtml .= '';
+ }
+
+ unset($aTemplates);
+
+ return $bJsOutput ? 'window.rainloopTEMPLATES='.\MailSo\Base\Utils::Php2js(array($sHtml), $this->Logger()).';' : $sHtml;
+ }
+
+ /**
+ * @param string $sLanguage
+ *
+ * @return string
+ */
+ private function convertLanguageNameToMomentLanguageName($sLanguage)
+ {
+ $aHelper = array('en_gb' => 'en-gb', 'fr_ca' => 'fr-ca', 'pt_br' => 'pt-br',
+ 'uk_ua' => 'ua', 'zh_cn' => 'zh-cn', 'zh_tw' => 'zh-tw', 'fa_ir' => 'fa');
+
+ return isset($aHelper[$sLanguage]) ? $aHelper[$sLanguage] : \substr($sLanguage, 0, 2);
+ }
+
+ /**
+ * @param string $sLanguage
+ * @param bool $bAdmin = false
+ * @param bool $bWrapByScriptTag = true
+ *
+ * @return string
+ */
+ private function compileLanguage($sLanguage, $bAdmin = false, $bWrapByScriptTag = true)
+ {
+ $aResultLang = array();
+
+ $sMoment = 'window.moment && window.moment.locale && window.moment.locale(\'en\');';
+ $sMomentFileName = APP_VERSION_ROOT_PATH.'app/localization/moment/'.
+ $this->convertLanguageNameToMomentLanguageName($sLanguage).'.js';
+
+ if (\file_exists($sMomentFileName))
+ {
+ $sMoment = \file_get_contents($sMomentFileName);
+ $sMoment = \preg_replace('/\/\/[^\n]+\n/', '', $sMoment);
+ }
+
+ \RainLoop\Utils::ReadAndAddLang(APP_VERSION_ROOT_PATH.'app/localization/langs.yml', $aResultLang);
+ \RainLoop\Utils::ReadAndAddLang(APP_VERSION_ROOT_PATH.'app/localization/'.
+ ($bAdmin ? 'admin' : 'webmail').'/_source.en.yml', $aResultLang);
+ \RainLoop\Utils::ReadAndAddLang(APP_VERSION_ROOT_PATH.'app/localization/'.
+ ($bAdmin ? 'admin' : 'webmail').'/'.$sLanguage.'.yml', $aResultLang);
+
+ $this->Plugins()->ReadLang($sLanguage, $aResultLang);
+
+ $sLangJs = '';
+ $aLangKeys = \array_keys($aResultLang);
+ foreach ($aLangKeys as $sKey)
+ {
+ $sString = isset($aResultLang[$sKey]) ? $aResultLang[$sKey] : $sKey;
+ if (\is_array($sString))
+ {
+ $sString = \implode("\n", $sString);
+ }
+
+ $sLangJs .= '"'.\str_replace('"', '\\"', \str_replace('\\', '\\\\', $sKey)).'":'
+ .'"'.\str_replace(array("\r", "\n", "\t"), array('\r', '\n', '\t'),
+ \str_replace('"', '\\"', \str_replace('\\', '\\\\', $sString))).'",';
+ }
+
+ $sResult = empty($sLangJs) ? 'null' : '{'.\substr($sLangJs, 0, -1).'}';
+
+ return
+ ($bWrapByScriptTag ? '' : '')
+ ;
+ }
+
+ /**
+ * @param array $aAppData
+ * @param bool $bWrapByScriptTag = true
+ *
+ * @return string
+ */
+ private function compileAppData($aAppData, $bWrapByScriptTag = true)
+ {
+ return
+ ($bWrapByScriptTag ? '' : '')
+ ;
+ }
+}
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/RainLoop/Settings.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Settings.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/RainLoop/Settings.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Settings.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/RainLoop/Social.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Social.php
similarity index 96%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/RainLoop/Social.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Social.php
index a1363756bd77c05b9cb622b665dd9f09b491f7d1..d19164f81ef34a3d8912b36bf6f60c0ae0e312d0 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/libraries/RainLoop/Social.php
+++ b/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Social.php
@@ -1,792 +1,792 @@
-oHttp = $oHttp;
- $this->oActions = $oActions;
- }
-
- /**
- * @return bool
- */
- public function GoogleDisconnect($oAccount)
- {
- $oGoogle = $this->GoogleConnector();
- if ($oAccount && $oGoogle)
- {
- $oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
- $sEncodedeData = $oSettings->GetConf('GoogleAccessToken', '');
-
- if (!empty($sEncodedeData))
- {
- $aData = \RainLoop\Utils::DecodeKeyValues($sEncodedeData);
- if (\is_array($aData) && !empty($aData['id']))
- {
- $this->oActions->StorageProvider()->Clear(null,
- \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
- $this->GoogleUserLoginStorageKey($oGoogle, $aData['id'])
- );
- }
- }
-
- $oSettings->SetConf('GoogleAccessToken', '');
- $oSettings->SetConf('GoogleSocialName', '');
-
- return $this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
- }
-
- return false;
- }
-
- /**
- * @return bool
- */
- public function FacebookDisconnect($oAccount)
- {
- $oFacebook = $this->FacebookConnector($oAccount ? $oAccount : null);
- if ($oAccount && $oFacebook)
- {
- $oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
-
- $sEncodedeData = $oSettings->GetConf('FacebookAccessToken', '');
-
- if (!empty($sEncodedeData))
- {
- $aData = \RainLoop\Utils::DecodeKeyValues($sEncodedeData);
- if (is_array($aData) && isset($aData['id']))
- {
- $this->oActions->StorageProvider()->Clear(null,
- \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
- $this->FacebookUserLoginStorageKey($oFacebook, $aData['id'])
- );
- }
- }
-
- $oSettings->SetConf('FacebookAccessToken', '');
- $oSettings->SetConf('FacebookSocialName', '');
-
- return $this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
- }
-
- return false;
- }
-
- /**
- * @return bool
- */
- public function TwitterDisconnect($oAccount)
- {
- $oTwitter = $this->TwitterConnector();
- if ($oAccount && $oTwitter)
- {
- $oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
- $sEncodedData = $oSettings->GetConf('TwitterAccessToken', '');
-
- if (!empty($sEncodedData))
- {
- $aData = \RainLoop\Utils::DecodeKeyValues($sEncodedData);
- if (is_array($aData) && isset($aData['id']))
- {
- $this->oActions->StorageProvider()->Clear(null,
- \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
- $this->TwitterUserLoginStorageKey($oTwitter, $aData['id'])
- );
- }
- }
-
- $oSettings->SetConf('TwitterAccessToken', '');
- $oSettings->SetConf('TwitterSocialName', '');
-
- return $this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
- }
-
- return false;
- }
-
- /**
- * @return string
- */
- public function popupServiceResult($sTypeStr, $sLoginUrl, $bLogin, $iErrorCode)
- {
- $sResult = '';
- $bAppCssDebug = !!$this->oActions->Config()->Get('labs', 'use_app_debug_css', false);
-
- $sIcon = $sTypeStr;
- if ('facebook' === $sIcon)
- {
- $sIcon = $sIcon.'-alt';
- }
-
- if ($sLoginUrl)
- {
- $this->oHttp->ServerNoCache();
- @\header('Content-Type: text/html; charset=utf-8');
-
- $sResult = \strtr(\file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/Social.html'), array(
- '{{RefreshMeta}}' => ' ',
- '{{Stylesheet}}' => $this->oActions->StaticPath('css/social'.($bAppCssDebug ? '' : '.min').'.css'),
- '{{Icon}}' => $sIcon,
- '{{Script}}' => ''
- ));
- }
- else
- {
- $this->oHttp->ServerNoCache();
- @\header('Content-Type: text/html; charset=utf-8');
-
- $sCallBackType = $bLogin ? '_login' : '';
- $sConnectionFunc = 'rl_'.\md5(\RainLoop\Utils::GetConnectionToken()).'_'.$sTypeStr.$sCallBackType.'_service';
-
- $sResult = \strtr(\file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/Social.html'), array(
- '{{RefreshMeta}}' => '',
- '{{Stylesheet}}' => $this->oActions->StaticPath('css/social'.($bAppCssDebug ? '' : '.min').'.css'),
- '{{Icon}}' => $sIcon,
- '{{Script}}' => ''
- ));
- }
-
- return $sResult;
- }
-
- /**
- * @return string
- */
- public function GooglePopupService($bGmail = false)
- {
- $sLoginUrl = '';
- $oAccount = null;
-
- $bLogin = false;
- $iErrorCode = \RainLoop\Notifications::UnknownError;
-
- try
- {
- $oGoogle = $this->GoogleConnector();
- if ($this->oHttp->HasQuery('error'))
- {
- $iErrorCode = ('access_denied' === $this->oHttp->GetQuery('error')) ?
- \RainLoop\Notifications::SocialGoogleLoginAccessDisable : \RainLoop\Notifications::UnknownError;
- }
- else if ($oGoogle)
- {
- $oAccount = $this->oActions->GetAccount();
- $bLogin = !$oAccount;
-
- $sCheckToken = '';
- $sCheckAuth = '';
- $sState = $this->oHttp->GetQuery('state');
- if (!empty($sState))
- {
- $aParts = explode('|', $sState, 3);
-
- if (!$bGmail)
- {
- $bGmail = !empty($aParts[0]) ? '1' === (string) $aParts[0] : false;
- }
-
- $sCheckToken = !empty($aParts[1]) ? $aParts[1] : '';
- $sCheckAuth = !empty($aParts[2]) ? $aParts[2] : '';
- }
-
- $sRedirectUrl = $this->oHttp->GetFullUrl().'?SocialGoogle';
- if (!$this->oHttp->HasQuery('code'))
- {
- $aParams = array(
- 'scope' => \trim(\implode(' ', array(
- 'https://www.googleapis.com/auth/userinfo.email',
- 'https://www.googleapis.com/auth/userinfo.profile',
- $bGmail ? 'https://mail.google.com/' : ''
- ))),
- 'state' => ($bGmail ? '1' : '0').'|'.\RainLoop\Utils::GetConnectionToken().'|'.$this->oActions->GetSpecAuthToken(),
- 'response_type' => 'code'
- );
-
-// if ($bGmail)
-// {
-// $aParams['access_type'] = 'offline';
-// $aParams['approval_prompt'] = 'force';
-// }
-
- $sLoginUrl = $oGoogle->getAuthenticationUrl('https://accounts.google.com/o/oauth2/auth', $sRedirectUrl, $aParams);
- }
- else if (!empty($sState) && $sCheckToken === \RainLoop\Utils::GetConnectionToken())
- {
- if (!empty($sCheckAuth))
- {
- $this->oActions->SetSpecAuthToken($sCheckAuth);
- $oAccount = $this->oActions->GetAccount();
- $bLogin = !$oAccount;
- }
-
- $aParams = array('code' => $this->oHttp->GetQuery('code'), 'redirect_uri' => $sRedirectUrl);
- $aAuthorizationResponse = $oGoogle->getAccessToken('https://accounts.google.com/o/oauth2/token', 'authorization_code', $aParams);
-
- if (!empty($aAuthorizationResponse['result']['access_token']))
- {
- $oGoogle->setAccessToken($aAuthorizationResponse['result']['access_token']);
- $aUserInfoResponse = $oGoogle->fetch('https://www.googleapis.com/oauth2/v2/userinfo');
-
- if (!empty($aUserInfoResponse['result']['id']))
- {
- if ($bLogin)
- {
- $aUserData = null;
- if ($bGmail)
- {
- if (!empty($aUserInfoResponse['result']['email']))
- {
- $aUserData = array(
- 'Email' => $aUserInfoResponse['result']['email'],
- 'Password' => APP_GOOGLE_ACCESS_TOKEN_PREFIX.$aAuthorizationResponse['result']['access_token']
- );
- }
- }
- else
- {
- $sUserData = $this->oActions->StorageProvider()->Get(null,
- \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
- $this->GoogleUserLoginStorageKey($oGoogle, $aUserInfoResponse['result']['id'])
- );
-
- $aUserData = \RainLoop\Utils::DecodeKeyValues($sUserData);
- }
-
- if ($aUserData && \is_array($aUserData) &&
- !empty($aUserData['Email']) && isset($aUserData['Password']))
- {
- $iErrorCode = $this->loginProcess($oAccount, $aUserData['Email'], $aUserData['Password']);
- }
- else
- {
- $iErrorCode = \RainLoop\Notifications::SocialGoogleLoginAccessDisable;
- }
- }
-
- if ($oAccount && !$bGmail)
- {
- $aUserData = array(
- 'ID' => $aUserInfoResponse['result']['id'],
- 'Email' => $oAccount->Email(),
- 'Password' => $oAccount->Password()
- );
-
- $sSocialName = !empty($aUserInfoResponse['result']['name']) ? $aUserInfoResponse['result']['name'] : '';
- $sSocialName .= !empty($aUserInfoResponse['result']['email']) ? ' ('.$aUserInfoResponse['result']['email'].')' : '';
- $sSocialName = \trim($sSocialName);
-
- $oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
-
- $oSettings->SetConf('GoogleAccessToken', \RainLoop\Utils::EncodeKeyValues(array(
- 'id' => $aUserInfoResponse['result']['id']
- )));
-
- $oSettings->SetConf('GoogleSocialName', $sSocialName);
-
- $this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
-
- $this->oActions->StorageProvider()->Put(null,
- \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
- $this->GoogleUserLoginStorageKey($oGoogle, $aUserInfoResponse['result']['id']),
- \RainLoop\Utils::EncodeKeyValues($aUserData));
-
- $iErrorCode = 0;
- }
- }
- }
- }
- }
- }
- catch (\Exception $oException)
- {
- $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
- }
-
- return $this->popupServiceResult('google', $sLoginUrl, $bLogin, $iErrorCode);
- }
-
- /**
- * @return string
- */
- public function FacebookPopupService()
- {
- $sLoginUrl = '';
- $sSocialName = '';
-
- $mData = false;
- $sUserData = '';
- $aUserData = false;
- $oAccount = null;
-
- $bLogin = false;
- $iErrorCode = \RainLoop\Notifications::UnknownError;
-
- if (0 === \strlen($this->oActions->GetSpecAuthToken()) && $this->oHttp->HasQuery('rlah'))
- {
- $this->oActions->SetSpecAuthToken($this->oHttp->GetQuery('rlah', ''));
- }
-
- $oAccount = $this->oActions->GetAccount();
-
- $sRedirectUrl = '';
- $oFacebook = $this->FacebookConnector($oAccount, $sRedirectUrl);
- if ($oFacebook)
- {
- try
- {
- $oRedirectLoginHelper = $oFacebook->getRedirectLoginHelper();
- $oAccessToken = $oRedirectLoginHelper->getAccessToken();
-
- if (!$oAccessToken && !$this->oHttp->HasQuery('state'))
- {
- $sLoginUrl = $oFacebook->getRedirectLoginHelper()->getLoginUrl($sRedirectUrl.'&display=popup');
- }
- else if ($oAccessToken)
- {
- $oResponse = $oFacebook->get('/me?fields=id,name', (string) $oAccessToken);
- $oGraphUser = $oResponse->getGraphUser();
-
- $mData = $oGraphUser->getId();
- $sSocialName = $oGraphUser->getName();
-
- if ($oAccount)
- {
- if ($mData && 0 < \strlen($mData))
- {
- $aUserData = array(
- 'id' => $mData,
- 'Email' => $oAccount->Email(),
- 'Password' => $oAccount->Password()
- );
-
- $oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
- $oSettings->SetConf('FacebookSocialName', $sSocialName);
- $oSettings->SetConf('FacebookAccessToken', \RainLoop\Utils::EncodeKeyValues(array('id' => $mData)));
-
- $this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
-
- $this->oActions->StorageProvider()->Put(null,
- \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
- $this->FacebookUserLoginStorageKey($oFacebook, $mData),
- \RainLoop\Utils::EncodeKeyValues($aUserData));
-
- $iErrorCode = 0;
- }
- }
- else
- {
- $bLogin = true;
-
- if ($mData && 0 < \strlen($mData))
- {
- $sUserData = $this->oActions->StorageProvider()->Get(null,
- \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
- $this->FacebookUserLoginStorageKey($oFacebook, $mData));
-
- if ($sUserData)
- {
- $aUserData = \RainLoop\Utils::DecodeKeyValues($sUserData);
- }
- }
-
- if ($aUserData && \is_array($aUserData) &&
- !empty($aUserData['Email']) && isset($aUserData['Password']))
- {
- $iErrorCode = $this->loginProcess($oAccount, $aUserData['Email'], $aUserData['Password']);
- }
- else
- {
- $iErrorCode = \RainLoop\Notifications::SocialFacebookLoginAccessDisable;
- }
- }
- }
- }
- catch (\Exception $oException)
- {
- $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
- }
- }
-
- return $this->popupServiceResult('facebook', $sLoginUrl, $bLogin, $iErrorCode);
- }
-
- /**
- * @return string
- */
- public function TwitterPopupService()
- {
- $sLoginUrl = '';
-
- $sSocialName = '';
- $oAccount = null;
-
- $bLogin = false;
- $iErrorCode = \RainLoop\Notifications::UnknownError;
-
- $sRedirectUrl = $this->oHttp->GetFullUrl().'?SocialTwitter';
- if (0 < strlen($this->oActions->GetSpecAuthToken()))
- {
- $sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken();
- }
- else if ($this->oHttp->HasQuery('rlah'))
- {
- $this->oActions->SetSpecAuthToken($this->oHttp->GetQuery('rlah', ''));
- $sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken();
- }
-
- try
- {
- $oTwitter = $this->TwitterConnector();
- if ($oTwitter)
- {
- $sSessionKey = \implode('_', array('twitter',
- \md5($oTwitter->config['consumer_secret']), \md5(\RainLoop\Utils::GetConnectionToken()), 'AuthSessionData'));
-
- $oAccount = $this->oActions->GetAccount();
- if ($oAccount)
- {
- if (isset($_REQUEST['oauth_verifier']))
- {
- $sAuth = $this->oActions->Cacher()->Get($sSessionKey);
- $oAuth = $sAuth ? \json_decode($sAuth, true) : null;
-
- if ($oAuth && !empty($oAuth['oauth_token']) && !empty($oAuth['oauth_token_secret']))
- {
- $oTwitter->config['user_token'] = $oAuth['oauth_token'];
- $oTwitter->config['user_secret'] = $oAuth['oauth_token_secret'];
-
- $iCode = $oTwitter->request('POST', $oTwitter->url('oauth/access_token', ''), array(
- 'oauth_callback' => $sRedirectUrl,
- 'oauth_verifier' => $_REQUEST['oauth_verifier']
- ));
-
- if (200 === $iCode && isset($oTwitter->response['response']))
- {
- $aAccessToken = $oTwitter->extract_params($oTwitter->response['response']);
- if ($aAccessToken && isset($aAccessToken['oauth_token']) && !empty($aAccessToken['user_id']))
- {
- $aAccessToken['id'] = $aAccessToken['user_id'];
-
- $oTwitter->config['user_token'] = $aAccessToken['oauth_token'];
- $oTwitter->config['user_secret'] = $aAccessToken['oauth_token_secret'];
-
- $sSocialName = !empty($aAccessToken['screen_name']) ? '@'.$aAccessToken['screen_name'] : $aAccessToken['user_id'];
- $sSocialName = \trim($sSocialName);
-
- $aUserData = array(
- 'id' => $aAccessToken['id'],
- 'Email' => $oAccount->Email(),
- 'Password' => $oAccount->Password()
- );
-
- $oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
- $oSettings->SetConf('TwitterAccessToken', \RainLoop\Utils::EncodeKeyValues($aAccessToken));
- $oSettings->SetConf('TwitterSocialName', $sSocialName);
- $this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
-
- $this->oActions->StorageProvider()->Put(null,
- \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
- $this->TwitterUserLoginStorageKey($oTwitter, $aAccessToken['id']),
- \RainLoop\Utils::EncodeKeyValues($aUserData));
-
- $iErrorCode = 0;
- }
- }
- }
- }
- else
- {
- $aParams = array(
- 'oauth_callback' => $sRedirectUrl,
- 'x_auth_access_type' => 'read'
- );
-
- $iCode = $oTwitter->request('POST', $oTwitter->url('oauth/request_token', ''), $aParams);
- if (200 === $iCode && isset($oTwitter->response['response']))
- {
- $oAuth = $oTwitter->extract_params($oTwitter->response['response']);
- if (!empty($oAuth['oauth_token']))
- {
- $this->oActions->Cacher()->Set($sSessionKey, \json_encode($oAuth));
- $sLoginUrl = $oTwitter->url('oauth/authenticate', '').'?oauth_token='.$oAuth['oauth_token'];
- }
- }
- }
- }
- else
- {
- $bLogin = true;
-
- if (isset($_REQUEST['oauth_verifier']))
- {
- $sAuth = $this->oActions->Cacher()->Get($sSessionKey);
- $oAuth = $sAuth ? \json_decode($sAuth, true) : null;
- if ($oAuth && !empty($oAuth['oauth_token']) && !empty($oAuth['oauth_token_secret']))
- {
- $oTwitter->config['user_token'] = $oAuth['oauth_token'];
- $oTwitter->config['user_secret'] = $oAuth['oauth_token_secret'];
-
- $iCode = $oTwitter->request('POST', $oTwitter->url('oauth/access_token', ''), array(
- 'oauth_callback' => $sRedirectUrl,
- 'oauth_verifier' => $_REQUEST['oauth_verifier']
- ));
-
- if (200 === $iCode && isset($oTwitter->response['response']))
- {
- $aAccessToken = $oTwitter->extract_params($oTwitter->response['response']);
- if ($aAccessToken && isset($aAccessToken['oauth_token']) && !empty($aAccessToken['user_id']))
- {
- $sUserData = $this->oActions->StorageProvider()->Get(null,
- \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
- $this->TwitterUserLoginStorageKey($oTwitter, $aAccessToken['user_id'])
- );
-
- $aUserData = \RainLoop\Utils::DecodeKeyValues($sUserData);
-
- if ($aUserData && \is_array($aUserData) &&
- !empty($aUserData['Email']) && isset($aUserData['Password']))
- {
- $iErrorCode = $this->loginProcess($oAccount, $aUserData['Email'], $aUserData['Password']);
- }
- else
- {
- $iErrorCode = \RainLoop\Notifications::SocialTwitterLoginAccessDisable;
- }
-
- $this->oActions->Cacher()->Delete($sSessionKey);
- }
- }
- }
- }
- else
- {
- $aParams = array(
- 'oauth_callback' => $sRedirectUrl,
- 'x_auth_access_type' => 'read'
- );
-
- $iCode = $oTwitter->request('POST', $oTwitter->url('oauth/request_token', ''), $aParams);
- if (200 === $iCode && isset($oTwitter->response['response']))
- {
- $oAuth = $oTwitter->extract_params($oTwitter->response['response']);
- if (!empty($oAuth['oauth_token']))
- {
- $this->oActions->Cacher()->Set($sSessionKey, \json_encode($oAuth));
- $sLoginUrl = $oTwitter->url('oauth/authenticate', '').'?oauth_token='.$oAuth['oauth_token'];
- }
- }
- }
- }
- }
- }
- catch (\Exception $oException)
- {
- $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
- }
-
- return $this->popupServiceResult('twitter', $sLoginUrl, $bLogin, $iErrorCode);
- }
-
- /**
- * @return \OAuth2\Client|null
- */
- public function GoogleConnector()
- {
- $oGoogle = false;
- $oConfig = $this->oActions->Config();
- if ($oConfig->Get('social', 'google_enable', false) &&
- '' !== \trim($oConfig->Get('social', 'google_client_id', '')) &&
- '' !== \trim($oConfig->Get('social', 'google_client_secret', '')))
- {
- include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/Client.php';
- include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/GrantType/IGrantType.php';
- include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/GrantType/AuthorizationCode.php';
- include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/GrantType/RefreshToken.php';
-
- try
- {
- $oGoogle = new \OAuth2\Client(
- \trim($oConfig->Get('social', 'google_client_id', '')),
- \trim($oConfig->Get('social', 'google_client_secret', '')));
-
- $sProxy = $this->oActions->Config()->Get('labs', 'curl_proxy', '');
- if (0 < \strlen($sProxy))
- {
- $oGoogle->setCurlOption(CURLOPT_PROXY, $sProxy);
-
- $sProxyAuth = $this->oActions->Config()->Get('labs', 'curl_proxy_auth', '');
- if (0 < \strlen($sProxyAuth))
- {
- $oGoogle->setCurlOption(CURLOPT_PROXYUSERPWD, $sProxyAuth);
- }
- }
- }
- catch (\Exception $oException)
- {
- $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
- }
- }
-
- return false === $oGoogle ? null : $oGoogle;
- }
-
- /**
- * @return \tmhOAuth|null
- */
- public function TwitterConnector()
- {
- $oTwitter = false;
- $oConfig = $this->oActions->Config();
- if ($oConfig->Get('social', 'twitter_enable', false) &&
- '' !== \trim($oConfig->Get('social', 'twitter_consumer_key', '')) &&
- '' !== \trim($oConfig->Get('social', 'twitter_consumer_secret', '')))
- {
- include_once APP_VERSION_ROOT_PATH.'app/libraries/tmhOAuth/tmhOAuth.php';
- include_once APP_VERSION_ROOT_PATH.'app/libraries/tmhOAuth/tmhUtilities.php';
-
- $sProxy = $this->oActions->Config()->Get('labs', 'curl_proxy', '');
- $sProxyAuth = $this->oActions->Config()->Get('labs', 'curl_proxy_auth', '');
-
- $oTwitter = new \tmhOAuth(array(
- 'consumer_key' => \trim($oConfig->Get('social', 'twitter_consumer_key', '')),
- 'consumer_secret' => \trim($oConfig->Get('social', 'twitter_consumer_secret', '')),
- 'curl_proxy' => 0 < \strlen($sProxy) ? $sProxy : false,
- 'curl_proxyuserpwd' => 0 < \strlen($sProxyAuth) ? $sProxyAuth : false
- ));
- }
-
- return false === $oTwitter ? null : $oTwitter;
- }
-
- /**
- * @param \RainLoop\Model\Account|null $oAccount = null
- * @param string $sRedirectUrl = ''
- *
- * @return \RainLoop\Common\RainLoopFacebookRedirectLoginHelper|null
- */
- public function FacebookConnector($oAccount = null, &$sRedirectUrl = '')
- {
- $oFacebook = false;
- $oConfig = $this->oActions->Config();
- $sAppID = \trim($oConfig->Get('social', 'fb_app_id', ''));
- $sAppSecret = \trim($oConfig->Get('social', 'fb_app_secret', ''));
-
- if (\version_compare(PHP_VERSION, '5.4.0', '>=') &&
- $oConfig->Get('social', 'fb_enable', false) && '' !== $sAppID &&
- '' !== \trim($oConfig->Get('social', 'fb_app_secret', '')) &&
- \class_exists('Facebook\Facebook')
- )
- {
- $sRedirectUrl = $this->oHttp->GetFullUrl().'?SocialFacebook';
- if (0 < \strlen($this->oActions->GetSpecAuthToken()))
- {
- $sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken();
- }
- else if ($this->oHttp->HasQuery('rlah'))
- {
- $this->oActions->SetSpecAuthToken($this->oHttp->GetQuery('rlah', ''));
- $sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken();
- }
-
- try
- {
- $oAccount = $this->oActions->GetAccount();
-
- $oFacebook = new \Facebook\Facebook(array(
- 'app_id' => $sAppID, // Replace {app-id} with your app id
- 'app_secret' => $sAppSecret,
- 'persistent_data_handler' => new \RainLoop\Common\FacebookRainLoopPersistentDataHandler(
- $oAccount, \RainLoop\Utils::GetConnectionToken(), $this->oActions->StorageProvider()
- )
- ));
- }
- catch (\Exception $oException)
- {
- $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
- }
- }
-
- return false === $oFacebook ? null : $oFacebook;
- }
-
- /**
- * @return string
- */
- public function GoogleUserLoginStorageKey($oGoogle, $sGoogleUserId)
- {
- return \implode('_', array('google', \md5($oGoogle->getClientId()), $sGoogleUserId, APP_SALT));
- }
-
- /**
- * @return string
- */
- public function FacebookUserLoginStorageKey($oFacebook, $sFacebookUserId)
- {
- return \implode('_', array('facebookNew', \md5($oFacebook->getApp()->getId()), $sFacebookUserId, APP_SALT));
- }
-
- /**
- * @return string
- */
- public function TwitterUserLoginStorageKey($oTwitter, $sTwitterUserId)
- {
- return \implode('_', array('twitter_2', \md5($oTwitter->config['consumer_secret']), $sTwitterUserId, APP_SALT));
- }
-
- /**
- * @param \RainLoop\Model\Account|null $oAccount
- * @param string $sEmail
- * @param string $sPassword
- *
- * @return int
- */
- private function loginProcess(&$oAccount, $sEmail, $sPassword)
- {
- $iErrorCode = \RainLoop\Notifications::UnknownError;
-
- try
- {
- $oAccount = $this->oActions->LoginProcess($sEmail, $sPassword, '', '', false, true);
- if ($oAccount instanceof \RainLoop\Model\Account)
- {
- $this->oActions->AuthToken($oAccount);
- $iErrorCode = 0;
- }
- else
- {
- $oAccount = null;
- $iErrorCode = \RainLoop\Notifications::AuthError;
- }
- }
- catch (\RainLoop\Exceptions\ClientException $oException)
- {
- $iErrorCode = $oException->getCode();
- }
- catch (\Exception $oException)
- {
- unset($oException);
- $iErrorCode = \RainLoop\Notifications::UnknownError;
- }
-
- return $iErrorCode;
- }
+oHttp = $oHttp;
+ $this->oActions = $oActions;
+ }
+
+ /**
+ * @return bool
+ */
+ public function GoogleDisconnect($oAccount)
+ {
+ $oGoogle = $this->GoogleConnector();
+ if ($oAccount && $oGoogle)
+ {
+ $oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
+ $sEncodedeData = $oSettings->GetConf('GoogleAccessToken', '');
+
+ if (!empty($sEncodedeData))
+ {
+ $aData = \RainLoop\Utils::DecodeKeyValues($sEncodedeData);
+ if (\is_array($aData) && !empty($aData['id']))
+ {
+ $this->oActions->StorageProvider()->Clear(null,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
+ $this->GoogleUserLoginStorageKey($oGoogle, $aData['id'])
+ );
+ }
+ }
+
+ $oSettings->SetConf('GoogleAccessToken', '');
+ $oSettings->SetConf('GoogleSocialName', '');
+
+ return $this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
+ }
+
+ return false;
+ }
+
+ /**
+ * @return bool
+ */
+ public function FacebookDisconnect($oAccount)
+ {
+ $oFacebook = $this->FacebookConnector($oAccount ? $oAccount : null);
+ if ($oAccount && $oFacebook)
+ {
+ $oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
+
+ $sEncodedeData = $oSettings->GetConf('FacebookAccessToken', '');
+
+ if (!empty($sEncodedeData))
+ {
+ $aData = \RainLoop\Utils::DecodeKeyValues($sEncodedeData);
+ if (is_array($aData) && isset($aData['id']))
+ {
+ $this->oActions->StorageProvider()->Clear(null,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
+ $this->FacebookUserLoginStorageKey($oFacebook, $aData['id'])
+ );
+ }
+ }
+
+ $oSettings->SetConf('FacebookAccessToken', '');
+ $oSettings->SetConf('FacebookSocialName', '');
+
+ return $this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
+ }
+
+ return false;
+ }
+
+ /**
+ * @return bool
+ */
+ public function TwitterDisconnect($oAccount)
+ {
+ $oTwitter = $this->TwitterConnector();
+ if ($oAccount && $oTwitter)
+ {
+ $oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
+ $sEncodedData = $oSettings->GetConf('TwitterAccessToken', '');
+
+ if (!empty($sEncodedData))
+ {
+ $aData = \RainLoop\Utils::DecodeKeyValues($sEncodedData);
+ if (is_array($aData) && isset($aData['id']))
+ {
+ $this->oActions->StorageProvider()->Clear(null,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
+ $this->TwitterUserLoginStorageKey($oTwitter, $aData['id'])
+ );
+ }
+ }
+
+ $oSettings->SetConf('TwitterAccessToken', '');
+ $oSettings->SetConf('TwitterSocialName', '');
+
+ return $this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
+ }
+
+ return false;
+ }
+
+ /**
+ * @return string
+ */
+ public function popupServiceResult($sTypeStr, $sLoginUrl, $bLogin, $iErrorCode)
+ {
+ $sResult = '';
+ $bAppCssDebug = !!$this->oActions->Config()->Get('labs', 'use_app_debug_css', false);
+
+ $sIcon = $sTypeStr;
+ if ('facebook' === $sIcon)
+ {
+ $sIcon = $sIcon.'-alt';
+ }
+
+ if ($sLoginUrl)
+ {
+ $this->oHttp->ServerNoCache();
+ @\header('Content-Type: text/html; charset=utf-8');
+
+ $sResult = \strtr(\file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/Social.html'), array(
+ '{{RefreshMeta}}' => ' ',
+ '{{Stylesheet}}' => $this->oActions->StaticPath('css/social'.($bAppCssDebug ? '' : '.min').'.css'),
+ '{{Icon}}' => $sIcon,
+ '{{Script}}' => ''
+ ));
+ }
+ else
+ {
+ $this->oHttp->ServerNoCache();
+ @\header('Content-Type: text/html; charset=utf-8');
+
+ $sCallBackType = $bLogin ? '_login' : '';
+ $sConnectionFunc = 'rl_'.\md5(\RainLoop\Utils::GetConnectionToken()).'_'.$sTypeStr.$sCallBackType.'_service';
+
+ $sResult = \strtr(\file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/Social.html'), array(
+ '{{RefreshMeta}}' => '',
+ '{{Stylesheet}}' => $this->oActions->StaticPath('css/social'.($bAppCssDebug ? '' : '.min').'.css'),
+ '{{Icon}}' => $sIcon,
+ '{{Script}}' => ''
+ ));
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @return string
+ */
+ public function GooglePopupService($bGmail = false)
+ {
+ $sLoginUrl = '';
+ $oAccount = null;
+
+ $bLogin = false;
+ $iErrorCode = \RainLoop\Notifications::UnknownError;
+
+ try
+ {
+ $oGoogle = $this->GoogleConnector();
+ if ($this->oHttp->HasQuery('error'))
+ {
+ $iErrorCode = ('access_denied' === $this->oHttp->GetQuery('error')) ?
+ \RainLoop\Notifications::SocialGoogleLoginAccessDisable : \RainLoop\Notifications::UnknownError;
+ }
+ else if ($oGoogle)
+ {
+ $oAccount = $this->oActions->GetAccount();
+ $bLogin = !$oAccount;
+
+ $sCheckToken = '';
+ $sCheckAuth = '';
+ $sState = $this->oHttp->GetQuery('state');
+ if (!empty($sState))
+ {
+ $aParts = explode('|', $sState, 3);
+
+ if (!$bGmail)
+ {
+ $bGmail = !empty($aParts[0]) ? '1' === (string) $aParts[0] : false;
+ }
+
+ $sCheckToken = !empty($aParts[1]) ? $aParts[1] : '';
+ $sCheckAuth = !empty($aParts[2]) ? $aParts[2] : '';
+ }
+
+ $sRedirectUrl = $this->oHttp->GetFullUrl().'?SocialGoogle';
+ if (!$this->oHttp->HasQuery('code'))
+ {
+ $aParams = array(
+ 'scope' => \trim(\implode(' ', array(
+ 'https://www.googleapis.com/auth/userinfo.email',
+ 'https://www.googleapis.com/auth/userinfo.profile',
+ $bGmail ? 'https://mail.google.com/' : ''
+ ))),
+ 'state' => ($bGmail ? '1' : '0').'|'.\RainLoop\Utils::GetConnectionToken().'|'.$this->oActions->GetSpecAuthToken(),
+ 'response_type' => 'code'
+ );
+
+// if ($bGmail)
+// {
+// $aParams['access_type'] = 'offline';
+// $aParams['approval_prompt'] = 'force';
+// }
+
+ $sLoginUrl = $oGoogle->getAuthenticationUrl('https://accounts.google.com/o/oauth2/auth', $sRedirectUrl, $aParams);
+ }
+ else if (!empty($sState) && $sCheckToken === \RainLoop\Utils::GetConnectionToken())
+ {
+ if (!empty($sCheckAuth))
+ {
+ $this->oActions->SetSpecAuthToken($sCheckAuth);
+ $oAccount = $this->oActions->GetAccount();
+ $bLogin = !$oAccount;
+ }
+
+ $aParams = array('code' => $this->oHttp->GetQuery('code'), 'redirect_uri' => $sRedirectUrl);
+ $aAuthorizationResponse = $oGoogle->getAccessToken('https://accounts.google.com/o/oauth2/token', 'authorization_code', $aParams);
+
+ if (!empty($aAuthorizationResponse['result']['access_token']))
+ {
+ $oGoogle->setAccessToken($aAuthorizationResponse['result']['access_token']);
+ $aUserInfoResponse = $oGoogle->fetch('https://www.googleapis.com/oauth2/v2/userinfo');
+
+ if (!empty($aUserInfoResponse['result']['id']))
+ {
+ if ($bLogin)
+ {
+ $aUserData = null;
+ if ($bGmail)
+ {
+ if (!empty($aUserInfoResponse['result']['email']))
+ {
+ $aUserData = array(
+ 'Email' => $aUserInfoResponse['result']['email'],
+ 'Password' => APP_GOOGLE_ACCESS_TOKEN_PREFIX.$aAuthorizationResponse['result']['access_token']
+ );
+ }
+ }
+ else
+ {
+ $sUserData = $this->oActions->StorageProvider()->Get(null,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
+ $this->GoogleUserLoginStorageKey($oGoogle, $aUserInfoResponse['result']['id'])
+ );
+
+ $aUserData = \RainLoop\Utils::DecodeKeyValues($sUserData);
+ }
+
+ if ($aUserData && \is_array($aUserData) &&
+ !empty($aUserData['Email']) && isset($aUserData['Password']))
+ {
+ $iErrorCode = $this->loginProcess($oAccount, $aUserData['Email'], $aUserData['Password']);
+ }
+ else
+ {
+ $iErrorCode = \RainLoop\Notifications::SocialGoogleLoginAccessDisable;
+ }
+ }
+
+ if ($oAccount && !$bGmail)
+ {
+ $aUserData = array(
+ 'ID' => $aUserInfoResponse['result']['id'],
+ 'Email' => $oAccount->Email(),
+ 'Password' => $oAccount->Password()
+ );
+
+ $sSocialName = !empty($aUserInfoResponse['result']['name']) ? $aUserInfoResponse['result']['name'] : '';
+ $sSocialName .= !empty($aUserInfoResponse['result']['email']) ? ' ('.$aUserInfoResponse['result']['email'].')' : '';
+ $sSocialName = \trim($sSocialName);
+
+ $oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
+
+ $oSettings->SetConf('GoogleAccessToken', \RainLoop\Utils::EncodeKeyValues(array(
+ 'id' => $aUserInfoResponse['result']['id']
+ )));
+
+ $oSettings->SetConf('GoogleSocialName', $sSocialName);
+
+ $this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
+
+ $this->oActions->StorageProvider()->Put(null,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
+ $this->GoogleUserLoginStorageKey($oGoogle, $aUserInfoResponse['result']['id']),
+ \RainLoop\Utils::EncodeKeyValues($aUserData));
+
+ $iErrorCode = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ catch (\Exception $oException)
+ {
+ $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
+ }
+
+ return $this->popupServiceResult('google', $sLoginUrl, $bLogin, $iErrorCode);
+ }
+
+ /**
+ * @return string
+ */
+ public function FacebookPopupService()
+ {
+ $sLoginUrl = '';
+ $sSocialName = '';
+
+ $mData = false;
+ $sUserData = '';
+ $aUserData = false;
+ $oAccount = null;
+
+ $bLogin = false;
+ $iErrorCode = \RainLoop\Notifications::UnknownError;
+
+ if (0 === \strlen($this->oActions->GetSpecAuthToken()) && $this->oHttp->HasQuery('rlah'))
+ {
+ $this->oActions->SetSpecAuthToken($this->oHttp->GetQuery('rlah', ''));
+ }
+
+ $oAccount = $this->oActions->GetAccount();
+
+ $sRedirectUrl = '';
+ $oFacebook = $this->FacebookConnector($oAccount, $sRedirectUrl);
+ if ($oFacebook)
+ {
+ try
+ {
+ $oRedirectLoginHelper = $oFacebook->getRedirectLoginHelper();
+ $oAccessToken = $oRedirectLoginHelper->getAccessToken();
+
+ if (!$oAccessToken && !$this->oHttp->HasQuery('state'))
+ {
+ $sLoginUrl = $oFacebook->getRedirectLoginHelper()->getLoginUrl($sRedirectUrl.'&display=popup');
+ }
+ else if ($oAccessToken)
+ {
+ $oResponse = $oFacebook->get('/me?fields=id,name', (string) $oAccessToken);
+ $oGraphUser = $oResponse->getGraphUser();
+
+ $mData = $oGraphUser->getId();
+ $sSocialName = $oGraphUser->getName();
+
+ if ($oAccount)
+ {
+ if ($mData && 0 < \strlen($mData))
+ {
+ $aUserData = array(
+ 'id' => $mData,
+ 'Email' => $oAccount->Email(),
+ 'Password' => $oAccount->Password()
+ );
+
+ $oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
+ $oSettings->SetConf('FacebookSocialName', $sSocialName);
+ $oSettings->SetConf('FacebookAccessToken', \RainLoop\Utils::EncodeKeyValues(array('id' => $mData)));
+
+ $this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
+
+ $this->oActions->StorageProvider()->Put(null,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
+ $this->FacebookUserLoginStorageKey($oFacebook, $mData),
+ \RainLoop\Utils::EncodeKeyValues($aUserData));
+
+ $iErrorCode = 0;
+ }
+ }
+ else
+ {
+ $bLogin = true;
+
+ if ($mData && 0 < \strlen($mData))
+ {
+ $sUserData = $this->oActions->StorageProvider()->Get(null,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
+ $this->FacebookUserLoginStorageKey($oFacebook, $mData));
+
+ if ($sUserData)
+ {
+ $aUserData = \RainLoop\Utils::DecodeKeyValues($sUserData);
+ }
+ }
+
+ if ($aUserData && \is_array($aUserData) &&
+ !empty($aUserData['Email']) && isset($aUserData['Password']))
+ {
+ $iErrorCode = $this->loginProcess($oAccount, $aUserData['Email'], $aUserData['Password']);
+ }
+ else
+ {
+ $iErrorCode = \RainLoop\Notifications::SocialFacebookLoginAccessDisable;
+ }
+ }
+ }
+ }
+ catch (\Exception $oException)
+ {
+ $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
+ }
+ }
+
+ return $this->popupServiceResult('facebook', $sLoginUrl, $bLogin, $iErrorCode);
+ }
+
+ /**
+ * @return string
+ */
+ public function TwitterPopupService()
+ {
+ $sLoginUrl = '';
+
+ $sSocialName = '';
+ $oAccount = null;
+
+ $bLogin = false;
+ $iErrorCode = \RainLoop\Notifications::UnknownError;
+
+ $sRedirectUrl = $this->oHttp->GetFullUrl().'?SocialTwitter';
+ if (0 < strlen($this->oActions->GetSpecAuthToken()))
+ {
+ $sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken();
+ }
+ else if ($this->oHttp->HasQuery('rlah'))
+ {
+ $this->oActions->SetSpecAuthToken($this->oHttp->GetQuery('rlah', ''));
+ $sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken();
+ }
+
+ try
+ {
+ $oTwitter = $this->TwitterConnector();
+ if ($oTwitter)
+ {
+ $sSessionKey = \implode('_', array('twitter',
+ \md5($oTwitter->config['consumer_secret']), \md5(\RainLoop\Utils::GetConnectionToken()), 'AuthSessionData'));
+
+ $oAccount = $this->oActions->GetAccount();
+ if ($oAccount)
+ {
+ if (isset($_REQUEST['oauth_verifier']))
+ {
+ $sAuth = $this->oActions->Cacher()->Get($sSessionKey);
+ $oAuth = $sAuth ? \json_decode($sAuth, true) : null;
+
+ if ($oAuth && !empty($oAuth['oauth_token']) && !empty($oAuth['oauth_token_secret']))
+ {
+ $oTwitter->config['user_token'] = $oAuth['oauth_token'];
+ $oTwitter->config['user_secret'] = $oAuth['oauth_token_secret'];
+
+ $iCode = $oTwitter->request('POST', $oTwitter->url('oauth/access_token', ''), array(
+ 'oauth_callback' => $sRedirectUrl,
+ 'oauth_verifier' => $_REQUEST['oauth_verifier']
+ ));
+
+ if (200 === $iCode && isset($oTwitter->response['response']))
+ {
+ $aAccessToken = $oTwitter->extract_params($oTwitter->response['response']);
+ if ($aAccessToken && isset($aAccessToken['oauth_token']) && !empty($aAccessToken['user_id']))
+ {
+ $aAccessToken['id'] = $aAccessToken['user_id'];
+
+ $oTwitter->config['user_token'] = $aAccessToken['oauth_token'];
+ $oTwitter->config['user_secret'] = $aAccessToken['oauth_token_secret'];
+
+ $sSocialName = !empty($aAccessToken['screen_name']) ? '@'.$aAccessToken['screen_name'] : $aAccessToken['user_id'];
+ $sSocialName = \trim($sSocialName);
+
+ $aUserData = array(
+ 'id' => $aAccessToken['id'],
+ 'Email' => $oAccount->Email(),
+ 'Password' => $oAccount->Password()
+ );
+
+ $oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
+ $oSettings->SetConf('TwitterAccessToken', \RainLoop\Utils::EncodeKeyValues($aAccessToken));
+ $oSettings->SetConf('TwitterSocialName', $sSocialName);
+ $this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
+
+ $this->oActions->StorageProvider()->Put(null,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
+ $this->TwitterUserLoginStorageKey($oTwitter, $aAccessToken['id']),
+ \RainLoop\Utils::EncodeKeyValues($aUserData));
+
+ $iErrorCode = 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ $aParams = array(
+ 'oauth_callback' => $sRedirectUrl,
+ 'x_auth_access_type' => 'read'
+ );
+
+ $iCode = $oTwitter->request('POST', $oTwitter->url('oauth/request_token', ''), $aParams);
+ if (200 === $iCode && isset($oTwitter->response['response']))
+ {
+ $oAuth = $oTwitter->extract_params($oTwitter->response['response']);
+ if (!empty($oAuth['oauth_token']))
+ {
+ $this->oActions->Cacher()->Set($sSessionKey, \json_encode($oAuth));
+ $sLoginUrl = $oTwitter->url('oauth/authenticate', '').'?oauth_token='.$oAuth['oauth_token'];
+ }
+ }
+ }
+ }
+ else
+ {
+ $bLogin = true;
+
+ if (isset($_REQUEST['oauth_verifier']))
+ {
+ $sAuth = $this->oActions->Cacher()->Get($sSessionKey);
+ $oAuth = $sAuth ? \json_decode($sAuth, true) : null;
+ if ($oAuth && !empty($oAuth['oauth_token']) && !empty($oAuth['oauth_token_secret']))
+ {
+ $oTwitter->config['user_token'] = $oAuth['oauth_token'];
+ $oTwitter->config['user_secret'] = $oAuth['oauth_token_secret'];
+
+ $iCode = $oTwitter->request('POST', $oTwitter->url('oauth/access_token', ''), array(
+ 'oauth_callback' => $sRedirectUrl,
+ 'oauth_verifier' => $_REQUEST['oauth_verifier']
+ ));
+
+ if (200 === $iCode && isset($oTwitter->response['response']))
+ {
+ $aAccessToken = $oTwitter->extract_params($oTwitter->response['response']);
+ if ($aAccessToken && isset($aAccessToken['oauth_token']) && !empty($aAccessToken['user_id']))
+ {
+ $sUserData = $this->oActions->StorageProvider()->Get(null,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
+ $this->TwitterUserLoginStorageKey($oTwitter, $aAccessToken['user_id'])
+ );
+
+ $aUserData = \RainLoop\Utils::DecodeKeyValues($sUserData);
+
+ if ($aUserData && \is_array($aUserData) &&
+ !empty($aUserData['Email']) && isset($aUserData['Password']))
+ {
+ $iErrorCode = $this->loginProcess($oAccount, $aUserData['Email'], $aUserData['Password']);
+ }
+ else
+ {
+ $iErrorCode = \RainLoop\Notifications::SocialTwitterLoginAccessDisable;
+ }
+
+ $this->oActions->Cacher()->Delete($sSessionKey);
+ }
+ }
+ }
+ }
+ else
+ {
+ $aParams = array(
+ 'oauth_callback' => $sRedirectUrl,
+ 'x_auth_access_type' => 'read'
+ );
+
+ $iCode = $oTwitter->request('POST', $oTwitter->url('oauth/request_token', ''), $aParams);
+ if (200 === $iCode && isset($oTwitter->response['response']))
+ {
+ $oAuth = $oTwitter->extract_params($oTwitter->response['response']);
+ if (!empty($oAuth['oauth_token']))
+ {
+ $this->oActions->Cacher()->Set($sSessionKey, \json_encode($oAuth));
+ $sLoginUrl = $oTwitter->url('oauth/authenticate', '').'?oauth_token='.$oAuth['oauth_token'];
+ }
+ }
+ }
+ }
+ }
+ }
+ catch (\Exception $oException)
+ {
+ $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
+ }
+
+ return $this->popupServiceResult('twitter', $sLoginUrl, $bLogin, $iErrorCode);
+ }
+
+ /**
+ * @return \OAuth2\Client|null
+ */
+ public function GoogleConnector()
+ {
+ $oGoogle = false;
+ $oConfig = $this->oActions->Config();
+ if ($oConfig->Get('social', 'google_enable', false) &&
+ '' !== \trim($oConfig->Get('social', 'google_client_id', '')) &&
+ '' !== \trim($oConfig->Get('social', 'google_client_secret', '')))
+ {
+ include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/Client.php';
+ include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/GrantType/IGrantType.php';
+ include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/GrantType/AuthorizationCode.php';
+ include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/GrantType/RefreshToken.php';
+
+ try
+ {
+ $oGoogle = new \OAuth2\Client(
+ \trim($oConfig->Get('social', 'google_client_id', '')),
+ \trim($oConfig->Get('social', 'google_client_secret', '')));
+
+ $sProxy = $this->oActions->Config()->Get('labs', 'curl_proxy', '');
+ if (0 < \strlen($sProxy))
+ {
+ $oGoogle->setCurlOption(CURLOPT_PROXY, $sProxy);
+
+ $sProxyAuth = $this->oActions->Config()->Get('labs', 'curl_proxy_auth', '');
+ if (0 < \strlen($sProxyAuth))
+ {
+ $oGoogle->setCurlOption(CURLOPT_PROXYUSERPWD, $sProxyAuth);
+ }
+ }
+ }
+ catch (\Exception $oException)
+ {
+ $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
+ }
+ }
+
+ return false === $oGoogle ? null : $oGoogle;
+ }
+
+ /**
+ * @return \tmhOAuth|null
+ */
+ public function TwitterConnector()
+ {
+ $oTwitter = false;
+ $oConfig = $this->oActions->Config();
+ if ($oConfig->Get('social', 'twitter_enable', false) &&
+ '' !== \trim($oConfig->Get('social', 'twitter_consumer_key', '')) &&
+ '' !== \trim($oConfig->Get('social', 'twitter_consumer_secret', '')))
+ {
+ include_once APP_VERSION_ROOT_PATH.'app/libraries/tmhOAuth/tmhOAuth.php';
+ include_once APP_VERSION_ROOT_PATH.'app/libraries/tmhOAuth/tmhUtilities.php';
+
+ $sProxy = $this->oActions->Config()->Get('labs', 'curl_proxy', '');
+ $sProxyAuth = $this->oActions->Config()->Get('labs', 'curl_proxy_auth', '');
+
+ $oTwitter = new \tmhOAuth(array(
+ 'consumer_key' => \trim($oConfig->Get('social', 'twitter_consumer_key', '')),
+ 'consumer_secret' => \trim($oConfig->Get('social', 'twitter_consumer_secret', '')),
+ 'curl_proxy' => 0 < \strlen($sProxy) ? $sProxy : false,
+ 'curl_proxyuserpwd' => 0 < \strlen($sProxyAuth) ? $sProxyAuth : false
+ ));
+ }
+
+ return false === $oTwitter ? null : $oTwitter;
+ }
+
+ /**
+ * @param \RainLoop\Model\Account|null $oAccount = null
+ * @param string $sRedirectUrl = ''
+ *
+ * @return \RainLoop\Common\RainLoopFacebookRedirectLoginHelper|null
+ */
+ public function FacebookConnector($oAccount = null, &$sRedirectUrl = '')
+ {
+ $oFacebook = false;
+ $oConfig = $this->oActions->Config();
+ $sAppID = \trim($oConfig->Get('social', 'fb_app_id', ''));
+ $sAppSecret = \trim($oConfig->Get('social', 'fb_app_secret', ''));
+
+ if (\version_compare(PHP_VERSION, '5.4.0', '>=') &&
+ $oConfig->Get('social', 'fb_enable', false) && '' !== $sAppID &&
+ '' !== \trim($oConfig->Get('social', 'fb_app_secret', '')) &&
+ \class_exists('Facebook\Facebook')
+ )
+ {
+ $sRedirectUrl = $this->oHttp->GetFullUrl().'?SocialFacebook';
+ if (0 < \strlen($this->oActions->GetSpecAuthToken()))
+ {
+ $sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken();
+ }
+ else if ($this->oHttp->HasQuery('rlah'))
+ {
+ $this->oActions->SetSpecAuthToken($this->oHttp->GetQuery('rlah', ''));
+ $sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken();
+ }
+
+ try
+ {
+ $oAccount = $this->oActions->GetAccount();
+
+ $oFacebook = new \Facebook\Facebook(array(
+ 'app_id' => $sAppID, // Replace {app-id} with your app id
+ 'app_secret' => $sAppSecret,
+ 'persistent_data_handler' => new \RainLoop\Common\FacebookRainLoopPersistentDataHandler(
+ $oAccount, \RainLoop\Utils::GetConnectionToken(), $this->oActions->StorageProvider()
+ )
+ ));
+ }
+ catch (\Exception $oException)
+ {
+ $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
+ }
+ }
+
+ return false === $oFacebook ? null : $oFacebook;
+ }
+
+ /**
+ * @return string
+ */
+ public function GoogleUserLoginStorageKey($oGoogle, $sGoogleUserId)
+ {
+ return \implode('_', array('google', \md5($oGoogle->getClientId()), $sGoogleUserId, APP_SALT));
+ }
+
+ /**
+ * @return string
+ */
+ public function FacebookUserLoginStorageKey($oFacebook, $sFacebookUserId)
+ {
+ return \implode('_', array('facebookNew', \md5($oFacebook->getApp()->getId()), $sFacebookUserId, APP_SALT));
+ }
+
+ /**
+ * @return string
+ */
+ public function TwitterUserLoginStorageKey($oTwitter, $sTwitterUserId)
+ {
+ return \implode('_', array('twitter_2', \md5($oTwitter->config['consumer_secret']), $sTwitterUserId, APP_SALT));
+ }
+
+ /**
+ * @param \RainLoop\Model\Account|null $oAccount
+ * @param string $sEmail
+ * @param string $sPassword
+ *
+ * @return int
+ */
+ private function loginProcess(&$oAccount, $sEmail, $sPassword)
+ {
+ $iErrorCode = \RainLoop\Notifications::UnknownError;
+
+ try
+ {
+ $oAccount = $this->oActions->LoginProcess($sEmail, $sPassword, '', '', false, true);
+ if ($oAccount instanceof \RainLoop\Model\Account)
+ {
+ $this->oActions->AuthToken($oAccount);
+ $iErrorCode = 0;
+ }
+ else
+ {
+ $oAccount = null;
+ $iErrorCode = \RainLoop\Notifications::AuthError;
+ }
+ }
+ catch (\RainLoop\Exceptions\ClientException $oException)
+ {
+ $iErrorCode = $oException->getCode();
+ }
+ catch (\Exception $oException)
+ {
+ unset($oException);
+ $iErrorCode = \RainLoop\Notifications::UnknownError;
+ }
+
+ return $iErrorCode;
+ }
}
\ No newline at end of file
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/RainLoop/Utils.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Utils.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/RainLoop/Utils.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/RainLoop/Utils.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Backend/AbstractBackend.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Backend/AbstractBackend.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Backend/AbstractBackend.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Backend/AbstractBackend.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Backend/BackendInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Backend/BackendInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Backend/BackendInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Backend/BackendInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Backend/NotificationSupport.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Backend/NotificationSupport.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Backend/NotificationSupport.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Backend/NotificationSupport.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Backend/PDO.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Backend/PDO.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Backend/PDO.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Backend/PDO.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Backend/SharingSupport.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Backend/SharingSupport.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Backend/SharingSupport.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Backend/SharingSupport.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Calendar.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Calendar.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Calendar.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Calendar.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/CalendarObject.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/CalendarObject.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/CalendarObject.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/CalendarObject.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/CalendarQueryParser.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/CalendarQueryParser.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/CalendarQueryParser.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/CalendarQueryParser.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/CalendarQueryValidator.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/CalendarQueryValidator.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/CalendarQueryValidator.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/CalendarQueryValidator.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/CalendarRootNode.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/CalendarRootNode.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/CalendarRootNode.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/CalendarRootNode.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Exception/InvalidComponentType.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Exception/InvalidComponentType.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Exception/InvalidComponentType.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Exception/InvalidComponentType.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/ICSExportPlugin.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/ICSExportPlugin.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/ICSExportPlugin.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/ICSExportPlugin.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/ICalendar.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/ICalendar.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/ICalendar.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/ICalendar.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/ICalendarObject.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/ICalendarObject.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/ICalendarObject.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/ICalendarObject.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/IShareableCalendar.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/IShareableCalendar.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/IShareableCalendar.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/IShareableCalendar.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/ISharedCalendar.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/ISharedCalendar.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/ISharedCalendar.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/ISharedCalendar.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/Collection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/Collection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/Collection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/Collection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/ICollection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/ICollection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/ICollection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/ICollection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/INode.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/INode.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/INode.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/INode.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/INotificationType.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/INotificationType.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/INotificationType.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/INotificationType.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/Node.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/Node.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/Node.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/Node.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/Invite.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/Invite.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/Invite.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/Invite.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/InviteReply.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/InviteReply.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/InviteReply.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/InviteReply.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/SystemStatus.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/SystemStatus.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/SystemStatus.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/SystemStatus.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Plugin.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Plugin.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Plugin.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Plugin.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Principal/Collection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/Collection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Principal/Collection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/Collection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Principal/IProxyRead.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/IProxyRead.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Principal/IProxyRead.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/IProxyRead.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Principal/IProxyWrite.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/IProxyWrite.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Principal/IProxyWrite.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/IProxyWrite.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Principal/ProxyRead.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/ProxyRead.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Principal/ProxyRead.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/ProxyRead.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Principal/ProxyWrite.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/ProxyWrite.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Principal/ProxyWrite.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/ProxyWrite.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Principal/User.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/User.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Principal/User.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Principal/User.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Property/AllowedSharingModes.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/AllowedSharingModes.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Property/AllowedSharingModes.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/AllowedSharingModes.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Property/Invite.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/Invite.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Property/Invite.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/Invite.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Property/ScheduleCalendarTransp.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/ScheduleCalendarTransp.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Property/ScheduleCalendarTransp.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/ScheduleCalendarTransp.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCalendarComponentSet.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCalendarComponentSet.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCalendarComponentSet.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCalendarComponentSet.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCalendarData.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCalendarData.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCalendarData.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCalendarData.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCollationSet.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCollationSet.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCollationSet.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCollationSet.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Schedule/IMip.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Schedule/IMip.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Schedule/IMip.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Schedule/IMip.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Schedule/IOutbox.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Schedule/IOutbox.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Schedule/IOutbox.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Schedule/IOutbox.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Schedule/Outbox.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Schedule/Outbox.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Schedule/Outbox.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Schedule/Outbox.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/ShareableCalendar.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/ShareableCalendar.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/ShareableCalendar.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/ShareableCalendar.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/SharedCalendar.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/SharedCalendar.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/SharedCalendar.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/SharedCalendar.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/SharingPlugin.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/SharingPlugin.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/SharingPlugin.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/SharingPlugin.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/UserCalendars.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/UserCalendars.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/UserCalendars.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/UserCalendars.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Version.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Version.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CalDAV/Version.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CalDAV/Version.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/AddressBook.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/AddressBook.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/AddressBook.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/AddressBook.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/AddressBookQueryParser.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/AddressBookQueryParser.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/AddressBookQueryParser.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/AddressBookQueryParser.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/AddressBookRoot.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/AddressBookRoot.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/AddressBookRoot.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/AddressBookRoot.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/Backend/AbstractBackend.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Backend/AbstractBackend.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/Backend/AbstractBackend.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Backend/AbstractBackend.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/Backend/BackendInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Backend/BackendInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/Backend/BackendInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Backend/BackendInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/Backend/PDO.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Backend/PDO.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/Backend/PDO.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Backend/PDO.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/Card.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Card.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/Card.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Card.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/IAddressBook.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/IAddressBook.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/IAddressBook.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/IAddressBook.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/ICard.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/ICard.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/ICard.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/ICard.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/IDirectory.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/IDirectory.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/IDirectory.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/IDirectory.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/Plugin.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Plugin.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/Plugin.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Plugin.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/Property/SupportedAddressData.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Property/SupportedAddressData.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/Property/SupportedAddressData.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Property/SupportedAddressData.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/UserAddressBooks.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/UserAddressBooks.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/UserAddressBooks.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/UserAddressBooks.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/VCFExportPlugin.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/VCFExportPlugin.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/VCFExportPlugin.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/VCFExportPlugin.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/Version.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Version.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/CardDAV/Version.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/CardDAV/Version.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/AbstractBasic.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/AbstractBasic.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/AbstractBasic.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/AbstractBasic.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/AbstractDigest.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/AbstractDigest.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/AbstractDigest.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/AbstractDigest.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/Apache.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/Apache.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/Apache.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/Apache.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/BackendInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/BackendInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/BackendInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/BackendInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/File.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/File.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/File.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/File.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/PDO.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/PDO.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Auth/Backend/PDO.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Backend/PDO.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Auth/Plugin.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Plugin.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Auth/Plugin.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Auth/Plugin.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Browser/GuessContentType.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/GuessContentType.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Browser/GuessContentType.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/GuessContentType.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Browser/MapGetToPropFind.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/MapGetToPropFind.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Browser/MapGetToPropFind.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/MapGetToPropFind.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Browser/Plugin.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/Plugin.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Browser/Plugin.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/Plugin.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/favicon.ico b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/favicon.ico
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/favicon.ico
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/favicon.ico
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/addressbook.png b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/addressbook.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/addressbook.png
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/addressbook.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/calendar.png b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/calendar.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/calendar.png
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/calendar.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/card.png b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/card.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/card.png
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/card.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/collection.png b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/collection.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/collection.png
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/collection.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/file.png b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/file.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/file.png
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/file.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/parent.png b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/parent.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/parent.png
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/parent.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/principal.png b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/principal.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/principal.png
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/principal.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Client.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Client.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Client.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Client.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Collection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Collection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Collection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Collection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/BadRequest.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/BadRequest.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/BadRequest.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/BadRequest.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/Conflict.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/Conflict.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/Conflict.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/Conflict.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/ConflictingLock.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/ConflictingLock.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/ConflictingLock.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/ConflictingLock.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/FileNotFound.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/FileNotFound.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/FileNotFound.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/FileNotFound.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/Forbidden.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/Forbidden.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/Forbidden.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/Forbidden.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/InsufficientStorage.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/InsufficientStorage.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/InsufficientStorage.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/InsufficientStorage.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/InvalidResourceType.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/InvalidResourceType.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/InvalidResourceType.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/InvalidResourceType.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/LockTokenMatchesRequestUri.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/LockTokenMatchesRequestUri.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/LockTokenMatchesRequestUri.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/LockTokenMatchesRequestUri.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/Locked.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/Locked.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/Locked.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/Locked.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/MethodNotAllowed.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/MethodNotAllowed.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/MethodNotAllowed.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/MethodNotAllowed.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/NotAuthenticated.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/NotAuthenticated.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/NotAuthenticated.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/NotAuthenticated.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/NotFound.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/NotFound.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/NotFound.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/NotFound.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/NotImplemented.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/NotImplemented.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/NotImplemented.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/NotImplemented.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/PaymentRequired.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/PaymentRequired.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/PaymentRequired.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/PaymentRequired.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/PreconditionFailed.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/PreconditionFailed.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/PreconditionFailed.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/PreconditionFailed.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/ReportNotSupported.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/ReportNotSupported.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/ReportNotSupported.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/ReportNotSupported.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/RequestedRangeNotSatisfiable.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/RequestedRangeNotSatisfiable.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/RequestedRangeNotSatisfiable.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/RequestedRangeNotSatisfiable.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/ServiceUnavailable.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/ServiceUnavailable.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/ServiceUnavailable.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/ServiceUnavailable.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/UnsupportedMediaType.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/UnsupportedMediaType.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Exception/UnsupportedMediaType.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Exception/UnsupportedMediaType.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/FS/Directory.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FS/Directory.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/FS/Directory.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FS/Directory.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/FS/File.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FS/File.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/FS/File.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FS/File.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/FS/Node.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FS/Node.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/FS/Node.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FS/Node.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/FSExt/Directory.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FSExt/Directory.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/FSExt/Directory.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FSExt/Directory.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/FSExt/File.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FSExt/File.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/FSExt/File.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FSExt/File.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/FSExt/Node.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FSExt/Node.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/FSExt/Node.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/FSExt/Node.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/File.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/File.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/File.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/File.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/ICollection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/ICollection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/ICollection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/ICollection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/IExtendedCollection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/IExtendedCollection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/IExtendedCollection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/IExtendedCollection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/IFile.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/IFile.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/IFile.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/IFile.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/INode.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/INode.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/INode.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/INode.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/IProperties.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/IProperties.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/IProperties.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/IProperties.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/IQuota.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/IQuota.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/IQuota.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/IQuota.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Locks/Backend/AbstractBackend.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Backend/AbstractBackend.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Locks/Backend/AbstractBackend.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Backend/AbstractBackend.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Locks/Backend/BackendInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Backend/BackendInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Locks/Backend/BackendInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Backend/BackendInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Locks/Backend/FS.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Backend/FS.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Locks/Backend/FS.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Backend/FS.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Locks/Backend/File.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Backend/File.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Locks/Backend/File.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Backend/File.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Locks/Backend/PDO.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Backend/PDO.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Locks/Backend/PDO.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Backend/PDO.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Locks/LockInfo.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/LockInfo.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Locks/LockInfo.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/LockInfo.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Locks/Plugin.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Plugin.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Locks/Plugin.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Locks/Plugin.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Mount/Plugin.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Mount/Plugin.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Mount/Plugin.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Mount/Plugin.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Node.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Node.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Node.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Node.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/ObjectTree.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/ObjectTree.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/ObjectTree.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/ObjectTree.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/PartialUpdate/IFile.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/PartialUpdate/IFile.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/PartialUpdate/IFile.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/PartialUpdate/IFile.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/PartialUpdate/Plugin.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/PartialUpdate/Plugin.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/PartialUpdate/Plugin.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/PartialUpdate/Plugin.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Property.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Property.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Property/GetLastModified.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/GetLastModified.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Property/GetLastModified.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/GetLastModified.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Property/Href.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/Href.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Property/Href.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/Href.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Property/HrefList.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/HrefList.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Property/HrefList.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/HrefList.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Property/IHref.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/IHref.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Property/IHref.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/IHref.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Property/LockDiscovery.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/LockDiscovery.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Property/LockDiscovery.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/LockDiscovery.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Property/ResourceType.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/ResourceType.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Property/ResourceType.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/ResourceType.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Property/Response.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/Response.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Property/Response.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/Response.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Property/ResponseList.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/ResponseList.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Property/ResponseList.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/ResponseList.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Property/SupportedLock.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/SupportedLock.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Property/SupportedLock.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/SupportedLock.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Property/SupportedReportSet.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/SupportedReportSet.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Property/SupportedReportSet.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Property/SupportedReportSet.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/PropertyInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/PropertyInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/PropertyInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/PropertyInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Server.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Server.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Server.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Server.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/ServerPlugin.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/ServerPlugin.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/ServerPlugin.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/ServerPlugin.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/SimpleCollection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/SimpleCollection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/SimpleCollection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/SimpleCollection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/SimpleFile.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/SimpleFile.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/SimpleFile.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/SimpleFile.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/StringUtil.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/StringUtil.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/StringUtil.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/StringUtil.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/TemporaryFileFilterPlugin.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/TemporaryFileFilterPlugin.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/TemporaryFileFilterPlugin.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/TemporaryFileFilterPlugin.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Tree.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Tree.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Tree.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Tree.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Tree/Filesystem.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Tree/Filesystem.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Tree/Filesystem.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Tree/Filesystem.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/URLUtil.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/URLUtil.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/URLUtil.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/URLUtil.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/UUIDUtil.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/UUIDUtil.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/UUIDUtil.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/UUIDUtil.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Version.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Version.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/Version.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/Version.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/XMLUtil.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/XMLUtil.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAV/XMLUtil.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAV/XMLUtil.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/AbstractPrincipalCollection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/AbstractPrincipalCollection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/AbstractPrincipalCollection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/AbstractPrincipalCollection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Exception/AceConflict.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Exception/AceConflict.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Exception/AceConflict.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Exception/AceConflict.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Exception/NeedPrivileges.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Exception/NeedPrivileges.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Exception/NeedPrivileges.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Exception/NeedPrivileges.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Exception/NoAbstract.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Exception/NoAbstract.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Exception/NoAbstract.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Exception/NoAbstract.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Exception/NotRecognizedPrincipal.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Exception/NotRecognizedPrincipal.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Exception/NotRecognizedPrincipal.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Exception/NotRecognizedPrincipal.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Exception/NotSupportedPrivilege.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Exception/NotSupportedPrivilege.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Exception/NotSupportedPrivilege.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Exception/NotSupportedPrivilege.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/IACL.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/IACL.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/IACL.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/IACL.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/IPrincipal.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/IPrincipal.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/IPrincipal.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/IPrincipal.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/IPrincipalCollection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/IPrincipalCollection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/IPrincipalCollection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/IPrincipalCollection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Plugin.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Plugin.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Plugin.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Plugin.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Principal.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Principal.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Principal.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Principal.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/AbstractBackend.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/AbstractBackend.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/AbstractBackend.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/AbstractBackend.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/BackendInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/BackendInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/BackendInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/BackendInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/PDO.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/PDO.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/PDO.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/PDO.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/PrincipalCollection.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/PrincipalCollection.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/PrincipalCollection.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/PrincipalCollection.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Property/Acl.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Property/Acl.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Property/Acl.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Property/Acl.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Property/AclRestrictions.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Property/AclRestrictions.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Property/AclRestrictions.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Property/AclRestrictions.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Property/CurrentUserPrivilegeSet.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Property/CurrentUserPrivilegeSet.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Property/CurrentUserPrivilegeSet.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Property/CurrentUserPrivilegeSet.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Property/Principal.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Property/Principal.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Property/Principal.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Property/Principal.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Property/SupportedPrivilegeSet.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Property/SupportedPrivilegeSet.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Property/SupportedPrivilegeSet.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Property/SupportedPrivilegeSet.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Version.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Version.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/DAVACL/Version.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/DAVACL/Version.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/HTTP/AWSAuth.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/AWSAuth.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/HTTP/AWSAuth.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/AWSAuth.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/HTTP/AbstractAuth.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/AbstractAuth.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/HTTP/AbstractAuth.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/AbstractAuth.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/HTTP/BasicAuth.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/BasicAuth.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/HTTP/BasicAuth.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/BasicAuth.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/HTTP/DigestAuth.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/DigestAuth.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/HTTP/DigestAuth.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/DigestAuth.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/HTTP/Request.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/Request.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/HTTP/Request.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/Request.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/HTTP/Response.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/Response.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/HTTP/Response.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/Response.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/HTTP/Util.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/Util.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/HTTP/Util.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/Util.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/HTTP/Version.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/Version.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/HTTP/Version.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/HTTP/Version.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Cli.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Cli.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Cli.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Cli.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Component.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Component.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Component/VAlarm.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VAlarm.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Component/VAlarm.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VAlarm.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Component/VCalendar.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VCalendar.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Component/VCalendar.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VCalendar.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Component/VCard.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VCard.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Component/VCard.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VCard.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Component/VEvent.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VEvent.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Component/VEvent.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VEvent.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Component/VFreeBusy.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VFreeBusy.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Component/VFreeBusy.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VFreeBusy.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Component/VJournal.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VJournal.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Component/VJournal.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VJournal.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Component/VTodo.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VTodo.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Component/VTodo.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Component/VTodo.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/DateTimeParser.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/DateTimeParser.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/DateTimeParser.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/DateTimeParser.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Document.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Document.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Document.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Document.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/ElementList.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/ElementList.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/ElementList.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/ElementList.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/EofException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/EofException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/EofException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/EofException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/FreeBusyGenerator.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/FreeBusyGenerator.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/FreeBusyGenerator.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/FreeBusyGenerator.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Node.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Node.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Node.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Node.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Parameter.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Parameter.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Parameter.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Parameter.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/ParseException.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/ParseException.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/ParseException.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/ParseException.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Parser/Json.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Parser/Json.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Parser/Json.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Parser/Json.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Parser/MimeDir.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Parser/MimeDir.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Parser/MimeDir.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Parser/MimeDir.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Parser/Parser.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Parser/Parser.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Parser/Parser.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Parser/Parser.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/Binary.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Binary.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/Binary.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Binary.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/Boolean.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Boolean.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/Boolean.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Boolean.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/FlatText.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/FlatText.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/FlatText.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/FlatText.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/Float.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Float.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/Float.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Float.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/CalAddress.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/CalAddress.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/CalAddress.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/CalAddress.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Date.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Date.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Date.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Date.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/DateTime.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/DateTime.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/DateTime.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/DateTime.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Duration.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Duration.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Duration.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Duration.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Period.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Period.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Period.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Period.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Recur.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Recur.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Recur.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Recur.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/Integer.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Integer.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/Integer.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Integer.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/Text.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Text.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/Text.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Text.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/Time.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Time.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/Time.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Time.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/Unknown.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Unknown.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/Unknown.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Unknown.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/Uri.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Uri.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/Uri.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/Uri.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/UtcOffset.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/UtcOffset.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/UtcOffset.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/UtcOffset.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/VCard/Date.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/VCard/Date.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/VCard/Date.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/VCard/Date.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/VCard/DateAndOrTime.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/VCard/DateAndOrTime.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/VCard/DateAndOrTime.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/VCard/DateAndOrTime.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/VCard/DateTime.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/VCard/DateTime.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/VCard/DateTime.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/VCard/DateTime.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/VCard/LanguageTag.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/VCard/LanguageTag.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/VCard/LanguageTag.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/VCard/LanguageTag.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/VCard/TimeStamp.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/VCard/TimeStamp.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Property/VCard/TimeStamp.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Property/VCard/TimeStamp.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Reader.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Reader.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Reader.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Reader.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/RecurrenceIterator.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/RecurrenceIterator.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/RecurrenceIterator.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/RecurrenceIterator.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Splitter/ICalendar.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Splitter/ICalendar.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Splitter/ICalendar.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Splitter/ICalendar.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Splitter/SplitterInterface.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Splitter/SplitterInterface.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Splitter/SplitterInterface.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Splitter/SplitterInterface.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Splitter/VCard.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Splitter/VCard.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Splitter/VCard.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Splitter/VCard.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/StringUtil.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/StringUtil.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/StringUtil.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/StringUtil.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/TimeZoneUtil.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/TimeZoneUtil.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/TimeZoneUtil.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/TimeZoneUtil.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/VCardConverter.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/VCardConverter.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/VCardConverter.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/VCardConverter.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Version.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Version.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/Version.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/Version.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/includes.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/includes.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/SabreForRainLoop/VObject/includes.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/SabreForRainLoop/VObject/includes.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/lessphp/LICENSE b/rainloop/app/rainloop/v/1.12.1/app/libraries/lessphp/LICENSE
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/lessphp/LICENSE
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/lessphp/LICENSE
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/lessphp/README.md b/rainloop/app/rainloop/v/1.12.1/app/libraries/lessphp/README.md
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/lessphp/README.md
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/lessphp/README.md
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/lessphp/ctype.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/lessphp/ctype.php
similarity index 93%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/lessphp/ctype.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/lessphp/ctype.php
index 74a12d147d80ce5178fa69d311a9574b7480d23c..d2bc9a0a8bea722aa878b2f2487490abd7977c9f 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/libraries/lessphp/ctype.php
+++ b/rainloop/app/rainloop/v/1.12.1/app/libraries/lessphp/ctype.php
@@ -1,40 +1,40 @@
-
- Copyright (C)
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-Also add information on how to contact you by electronic and paper mail.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the library, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the
- library `Frob' (a library for tweaking knobs) written by James Random Hacker.
-
- , 1 April 1990
- Ty Coon, President of Vice
-
-That's all there is to it!
-
-
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ , 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/pclzip/pclzip.lib.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/pclzip/pclzip.lib.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/pclzip/pclzip.lib.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/pclzip/pclzip.lib.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/pclzip/readme.txt b/rainloop/app/rainloop/v/1.12.1/app/libraries/pclzip/readme.txt
similarity index 98%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/pclzip/readme.txt
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/pclzip/readme.txt
index 6ed883947721913102281cbe9815eea3ad9ef539..d1b11e25897f11cbb3f0adf3b342bd42151bdede 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/libraries/pclzip/readme.txt
+++ b/rainloop/app/rainloop/v/1.12.1/app/libraries/pclzip/readme.txt
@@ -1,421 +1,421 @@
-// --------------------------------------------------------------------------------
-// PclZip 2.8.2 - readme.txt
-// --------------------------------------------------------------------------------
-// License GNU/LGPL - August 2009
-// Vincent Blavet - vincent@phpconcept.net
-// http://www.phpconcept.net
-// --------------------------------------------------------------------------------
-// $Id: readme.txt,v 1.60 2009/09/30 20:35:21 vblavet Exp $
-// --------------------------------------------------------------------------------
-
-
-
-0 - Sommaire
-============
- 1 - Introduction
- 2 - What's new
- 3 - Corrected bugs
- 4 - Known bugs or limitations
- 5 - License
- 6 - Warning
- 7 - Documentation
- 8 - Author
- 9 - Contribute
-
-1 - Introduction
-================
-
- PclZip is a library that allow you to manage a Zip archive.
-
- Full documentation about PclZip can be found here : http://www.phpconcept.net/pclzip
-
-2 - What's new
-==============
-
- Version 2.8.2 :
- - PCLZIP_CB_PRE_EXTRACT and PCLZIP_CB_POST_EXTRACT are now supported with
- extraction as a string (PCLZIP_OPT_EXTRACT_AS_STRING). The string
- can also be modified in the post-extract call back.
- **Bugs correction :
- - PCLZIP_OPT_REMOVE_ALL_PATH was not working correctly
- - Remove use of eval() and do direct call to callback functions
- - Correct support of 64bits systems (Thanks to WordPress team)
-
- Version 2.8.1 :
- - Move option PCLZIP_OPT_BY_EREG to PCLZIP_OPT_BY_PREG because ereg() is
- deprecated in PHP 5.3. When using option PCLZIP_OPT_BY_EREG, PclZip will
- automatically replace it by PCLZIP_OPT_BY_PREG.
-
- Version 2.8 :
- - Improve extraction of zip archive for large files by using temporary files
- This feature is working like the one defined in r2.7.
- Options are renamed : PCLZIP_OPT_TEMP_FILE_ON, PCLZIP_OPT_TEMP_FILE_OFF,
- PCLZIP_OPT_TEMP_FILE_THRESHOLD
- - Add a ratio constant PCLZIP_TEMPORARY_FILE_RATIO to configure the auto
- sense of temporary file use.
- - Bug correction : Reduce filepath in returned file list to remove ennoying
- './/' preambule in file path.
-
- Version 2.7 :
- - Improve creation of zip archive for large files :
- PclZip will now autosense the configured memory and use temporary files
- when large file is suspected.
- This feature can also ne triggered by manual options in create() and add()
- methods. 'PCLZIP_OPT_ADD_TEMP_FILE_ON' force the use of temporary files,
- 'PCLZIP_OPT_ADD_TEMP_FILE_OFF' disable the autosense technic,
- 'PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD' allow for configuration of a size
- threshold to use temporary files.
- Using "temporary files" rather than "memory" might take more time, but
- might give the ability to zip very large files :
- Tested on my win laptop with a 88Mo file :
- Zip "in-memory" : 18sec (max_execution_time=30, memory_limit=180Mo)
- Zip "tmporary-files" : 23sec (max_execution_time=30, memory_limit=30Mo)
- - Replace use of mktime() by time() to limit the E_STRICT error messages.
- - Bug correction : When adding files with full windows path (drive letter)
- PclZip is now working. Before, if the drive letter is not the default
- path, PclZip was not able to add the file.
-
- Version 2.6 :
- - Code optimisation
- - New attributes PCLZIP_ATT_FILE_COMMENT gives the ability to
- add a comment for a specific file. (Don't really know if this is usefull)
- - New attribute PCLZIP_ATT_FILE_CONTENT gives the ability to add a string
- as a file.
- - New attribute PCLZIP_ATT_FILE_MTIME modify the timestamp associated with
- a file.
- - Correct a bug. Files archived with a timestamp with 0h0m0s were extracted
- with current time
- - Add CRC value in the informations returned back for each file after an
- action.
- - Add missing closedir() statement.
- - When adding a folder, and removing the path of this folder, files were
- incorrectly added with a '/' at the beginning. Which means files are
- related to root in unix systems. Corrected.
- - Add conditional if before constant definition. This will allow users
- to redefine constants without changing the file, and then improve
- upgrade of pclzip code for new versions.
-
- Version 2.5 :
- - Introduce the ability to add file/folder with individual properties (file descriptor).
- This gives for example the ability to change the filename of a zipped file.
- . Able to add files individually
- . Able to change full name
- . Able to change short name
- . Compatible with global options
- - New attributes : PCLZIP_ATT_FILE_NAME, PCLZIP_ATT_FILE_NEW_SHORT_NAME, PCLZIP_ATT_FILE_NEW_FULL_NAME
- - New error code : PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE
- - Add a security control feature. PclZip can extract any file in any folder
- of a system. People may use this to upload a zip file and try to override
- a system file. The PCLZIP_OPT_EXTRACT_DIR_RESTRICTION will give the
- ability to forgive any directory transversal behavior.
- - New PCLZIP_OPT_EXTRACT_DIR_RESTRICTION : check extraction path
- - New error code : PCLZIP_ERR_DIRECTORY_RESTRICTION
- - Modification in PclZipUtilPathInclusion() : dir and path beginning with ./ will be prepend
- by current path (getcwd())
-
- Version 2.4 :
- - Code improvment : try to speed up the code by removing unusefull call to pack()
- - Correct bug in delete() : delete() should be called with no argument. This was not
- the case in 2.3. This is corrected in 2.4.
- - Correct a bug in path_inclusion function. When the path has several '../../', the
- result was bad.
- - Add a check for magic_quotes_runtime configuration. If enabled, PclZip will
- disable it while working and det it back to its original value.
- This resolve a lots of bad formated archive errors.
- - Bug correction : PclZip now correctly unzip file in some specific situation,
- when compressed content has same size as uncompressed content.
- - Bug correction : When selecting option 'PCLZIP_OPT_REMOVE_ALL_PATH',
- directories are not any more created.
- - Code improvment : correct unclosed opendir(), better handling of . and .. in
- loops.
-
-
- Version 2.3 :
- - Correct a bug with PHP5 : affecting the value 0xFE49FFE0 to a variable does not
- give the same result in PHP4 and PHP5 ....
-
- Version 2.2 :
- - Try development of PCLZIP_OPT_CRYPT .....
- However this becomes to a stop. To crypt/decrypt I need to multiply 2 long integers,
- the result (greater than a long) is not supported by PHP. Even the use of bcmath
- functions does not help. I did not find yet a solution ...;
- - Add missing '/' at end of directory entries
- - Check is a file is encrypted or not. Returns status 'unsupported_encryption' and/or
- error code PCLZIP_ERR_UNSUPPORTED_ENCRYPTION.
- - Corrected : Bad "version need to extract" field in local file header
- - Add private method privCheckFileHeaders() in order to check local and central
- file headers. PclZip is now supporting purpose bit flag bit 3. Purpose bit flag bit 3 gives
- the ability to have a local file header without size, compressed size and crc filled.
- - Add a generic status 'error' for file status
- - Add control of compression type. PclZip only support deflate compression method.
- Before v2.2, PclZip does not check the compression method used in an archive while
- extracting. With v2.2 PclZip returns a new error status for a file using an unsupported
- compression method. New status is "unsupported_compression". New error code is
- PCLZIP_ERR_UNSUPPORTED_COMPRESSION.
- - Add optional attribute PCLZIP_OPT_STOP_ON_ERROR. This will stop the extract of files
- when errors like 'a folder with same name exists' or 'a newer file exists' or
- 'a write protected file' exists, rather than set a status for the concerning file
- and resume the extract of the zip.
- - Add optional attribute PCLZIP_OPT_REPLACE_NEWER. This will force, during an extract' the
- replacement of the file, even if a newer version of the file exists.
- Note that today if a file with the same name already exists but is older it will be
- replaced by the extracted one.
- - Improve PclZipUtilOption()
- - Support of zip archive with trailing bytes. Before 2.2, PclZip checks that the central
- directory structure is the last data in the archive. Crypt encryption/decryption of
- zip archive put trailing 0 bytes after decryption. PclZip is now supporting this.
-
- Version 2.1 :
- - Add the ability to abort the extraction by using a user callback function.
- The user can now return the value '2' in its callback which indicates to stop the
- extraction. For a pre call-back extract is stopped before the extration of the current
- file. For a post call back, the extraction is stopped after.
- - Add the ability to extract a file (or several files) directly in the standard output.
- This is done by the new parameter PCLZIP_OPT_EXTRACT_IN_OUTPUT with method extract().
- - Add support for parameters PCLZIP_OPT_COMMENT, PCLZIP_OPT_ADD_COMMENT,
- PCLZIP_OPT_PREPEND_COMMENT. This will create, replace, add, or prepend comments
- in the zip archive.
- - When merging two archives, the comments are not any more lost, but merged, with a
- blank space separator.
- - Corrected bug : Files are not deleted when all files are asked to be deleted.
- - Corrected bug : Folders with name '0' made PclZip to abort the create or add feature.
-
-
- Version 2.0 :
- ***** Warning : Some new features may break the backward compatibility for your scripts.
- Please carefully read the readme file.
- - Add the ability to delete by Index, name and regular expression. This feature is
- performed by the method delete(), which uses the optional parameters
- PCLZIP_OPT_BY_INDEX, PCLZIP_OPT_BY_NAME, PCLZIP_OPT_BY_EREG or PCLZIP_OPT_BY_PREG.
- - Add the ability to extract by regular expression. To extract by regexp you must use the method
- extract(), with the option PCLZIP_OPT_BY_EREG or PCLZIP_OPT_BY_PREG
- (depending if you want to use ereg() or preg_match() syntax) followed by the
- regular expression pattern.
- - Add the ability to extract by index, directly with the extract() method. This is a
- code improvment of the extractByIndex() method.
- - Add the ability to extract by name. To extract by name you must use the method
- extract(), with the option PCLZIP_OPT_BY_NAME followed by the filename to
- extract or an array of filenames to extract. To extract all a folder, use the folder
- name rather than the filename with a '/' at the end.
- - Add the ability to add files without compression. This is done with a new attribute
- which is PCLZIP_OPT_NO_COMPRESSION.
- - Add the attribute PCLZIP_OPT_EXTRACT_AS_STRING, which allow to extract a file directly
- in a string without using any file (or temporary file).
- - Add constant PCLZIP_SEPARATOR for static configuration of filename separators in a single string.
- The default separator is now a comma (,) and not any more a blank space.
- THIS BREAK THE BACKWARD COMPATIBILITY : Please check if this may have an impact with
- your script.
- - Improve algorythm performance by removing the use of temporary files when adding or
- extracting files in an archive.
- - Add (correct) detection of empty filename zipping. This can occurs when the removed
- path is the same
- as a zipped dir. The dir is not zipped (['status'] = filtered), only its content.
- - Add better support for windows paths (thanks for help from manus@manusfreedom.com).
- - Corrected bug : When the archive file already exists with size=0, the add() method
- fails. Corrected in 2.0.
- - Remove the use of OS_WINDOWS constant. Use php_uname() function rather.
- - Control the order of index ranges in extract by index feature.
- - Change the internal management of folders (better handling of internal flag).
-
-
- Version 1.3 :
- - Removing the double include check. This is now done by include_once() and require_once()
- PHP directives.
- - Changing the error handling mecanism : Remove the use of an external error library.
- The former PclError...() functions are replaced by internal equivalent methods.
- By changing the environment variable PCLZIP_ERROR_EXTERNAL you can still use the former library.
- Introducing the use of constants for error codes rather than integer values. This will help
- in futur improvment.
- Introduction of error handling functions like errorCode(), errorName() and errorInfo().
- - Remove the deprecated use of calling function with arguments passed by reference.
- - Add the calling of extract(), extractByIndex(), create() and add() functions
- with variable options rather than fixed arguments.
- - Add the ability to remove all the file path while extracting or adding,
- without any need to specify the path to remove.
- This is available for extract(), extractByIndex(), create() and add() functionS by using
- the new variable options parameters :
- - PCLZIP_OPT_REMOVE_ALL_PATH : by indicating this option while calling the fct.
- - Ability to change the mode of a file after the extraction (chmod()).
- This is available for extract() and extractByIndex() functionS by using
- the new variable options parameters.
- - PCLZIP_OPT_SET_CHMOD : by setting the value of this option.
- - Ability to definition call-back options. These call-back will be called during the adding,
- or the extracting of file (extract(), extractByIndex(), create() and add() functions) :
- - PCLZIP_CB_PRE_EXTRACT : will be called before each extraction of a file. The user
- can trigerred the change the filename of the extracted file. The user can triggered the
- skip of the extraction. This is adding a 'skipped' status in the file list result value.
- - PCLZIP_CB_POST_EXTRACT : will be called after each extraction of a file.
- Nothing can be triggered from that point.
- - PCLZIP_CB_PRE_ADD : will be called before each add of a file. The user
- can trigerred the change the stored filename of the added file. The user can triggered the
- skip of the add. This is adding a 'skipped' status in the file list result value.
- - PCLZIP_CB_POST_ADD : will be called after each add of a file.
- Nothing can be triggered from that point.
- - Two status are added in the file list returned as function result : skipped & filename_too_long
- 'skipped' is used when a call-back function ask for skipping the file.
- 'filename_too_long' is used while adding a file with a too long filename to archive (the file is
- not added)
- - Adding the function PclZipUtilPathInclusion(), that check the inclusion of a path into
- a directory.
- - Add a check of the presence of the archive file before some actions (like list, ...)
- - Add the initialisation of field "index" in header array. This means that by
- default index will be -1 when not explicitly set by the methods.
-
- Version 1.2 :
- - Adding a duplicate function.
- - Adding a merge function. The merge function is a "quick merge" function,
- it just append the content of an archive at the end of the first one. There
- is no check for duplicate files or more recent files.
- - Improve the search of the central directory end.
-
- Version 1.1.2 :
-
- - Changing the license of PclZip. PclZip is now released under the GNU / LGPL license
- (see License section).
- - Adding the optional support of a static temporary directory. You will need to configure
- the constant PCLZIP_TEMPORARY_DIR if you want to use this feature.
- - Improving the rename() function. In some cases rename() does not work (different
- Filesystems), so it will be replaced by a copy() + unlink() functions.
-
- Version 1.1.1 :
-
- - Maintenance release, no new feature.
-
- Version 1.1 :
-
- - New method Add() : adding files in the archive
- - New method ExtractByIndex() : partial extract of the archive, files are identified by
- their index in the archive
- - New method DeleteByIndex() : delete some files/folder entries from the archive,
- files are identified by their index in the archive.
- - Adding a test of the zlib extension presence. If not present abort the script.
-
- Version 1.0.1 :
-
- - No new feature
-
-
-3 - Corrected bugs
-==================
-
- Corrected in Version 2.0 :
- - Corrected : During an extraction, if a call-back fucntion is used and try to skip
- a file, all the extraction process is stopped.
-
- Corrected in Version 1.3 :
- - Corrected : Support of static synopsis for method extract() is broken.
- - Corrected : invalid size of archive content field (0xFF) should be (0xFFFF).
- - Corrected : When an extract is done with a remove_path parameter, the entry for
- the directory with exactly the same path is not skipped/filtered.
- - Corrected : extractByIndex() and deleteByIndex() were not managing index in the
- right way. For example indexes '1,3-5,11' will only extract files 1 and 11. This
- is due to a sort of the index resulting table that puts 11 before 3-5 (sort on
- string and not interger). The sort is temporarilly removed, this means that
- you must provide a sorted list of index ranges.
-
- Corrected in Version 1.2 :
-
- - Nothing.
-
- Corrected in Version 1.1.2 :
-
- - Corrected : Winzip is unable to delete or add new files in a PclZip created archives.
-
- Corrected in Version 1.1.1 :
-
- - Corrected : When archived file is not compressed (0% compression), the
- extract method fails.
-
- Corrected in Version 1.1 :
-
- - Corrected : Adding a complete tree of folder may result in a bad archive
- creation.
-
- Corrected in Version 1.0.1 :
-
- - Corrected : Error while compressing files greater than PCLZIP_READ_BLOCK_SIZE (default=1024).
-
-
-4 - Known bugs or limitations
-=============================
-
- Please publish bugs reports in SourceForge :
- http://sourceforge.net/tracker/?group_id=40254&atid=427564
-
- In Version 2.x :
- - PclZip does only support file uncompressed or compressed with deflate (compression method 8)
- - PclZip does not support password protected zip archive
- - Some concern were seen when changing mtime of a file while archiving.
- Seems to be linked to Daylight Saving Time (PclTest_changing_mtime).
-
- In Version 1.2 :
-
- - merge() methods does not check for duplicate files or last date of modifications.
-
- In Version 1.1 :
-
- - Limitation : Using 'extract' fields in the file header in the zip archive is not supported.
- - WinZip is unable to delete a single file in a PclZip created archive. It is also unable to
- add a file in a PclZip created archive. (Corrected in v.1.2)
-
- In Version 1.0.1 :
-
- - Adding a complete tree of folder may result in a bad archive
- creation. (Corrected in V.1.1).
- - Path given to methods must be in the unix format (/) and not the Windows format (\).
- Workaround : Use only / directory separators.
- - PclZip is using temporary files that are sometime the name of the file with a .tmp or .gz
- added suffix. Files with these names may already exist and may be overwritten.
- Workaround : none.
- - PclZip does not check if the zlib extension is present. If it is absent, the zip
- file is not created and the lib abort without warning.
- Workaround : enable the zlib extension on the php install
-
- In Version 1.0 :
-
- - Error while compressing files greater than PCLZIP_READ_BLOCK_SIZE (default=1024).
- (Corrected in v.1.0.1)
- - Limitation : Multi-disk zip archive are not supported.
-
-
-5 - License
-===========
-
- Since version 1.1.2, PclZip Library is released under GNU/LGPL license.
- This library is free, so you can use it at no cost.
-
- HOWEVER, if you release a script, an application, a library or any kind of
- code using PclZip library (or a part of it), YOU MUST :
- - Indicate in the documentation (or a readme file), that your work
- uses PclZip Library, and make a reference to the author and the web site
- http://www.phpconcept.net
- - Gives the ability to the final user to update the PclZip libary.
-
- I will also appreciate that you send me a mail (vincent@phpconcept.net), just to
- be aware that someone is using PclZip.
-
- For more information about GNU/LGPL license : http://www.gnu.org
-
-6 - Warning
-=================
-
- This library and the associated files are non commercial, non professional work.
- It should not have unexpected results. However if any damage is caused by this software
- the author can not be responsible.
- The use of this software is at the risk of the user.
-
-7 - Documentation
-=================
- PclZip User Manuel is available in English on PhpConcept : http://www.phpconcept.net/pclzip/man/en/index.php
- A Russian translation was done by Feskov Kuzma : http://php.russofile.ru/ru/authors/unsort/zip/
-
-8 - Author
-==========
-
- This software was written by Vincent Blavet (vincent@phpconcept.net) on its leasure time.
-
-9 - Contribute
-==============
- If you want to contribute to the development of PclZip, please contact vincent@phpconcept.net.
- If you can help in financing PhpConcept hosting service, please go to
- http://www.phpconcept.net/soutien.php
+// --------------------------------------------------------------------------------
+// PclZip 2.8.2 - readme.txt
+// --------------------------------------------------------------------------------
+// License GNU/LGPL - August 2009
+// Vincent Blavet - vincent@phpconcept.net
+// http://www.phpconcept.net
+// --------------------------------------------------------------------------------
+// $Id: readme.txt,v 1.60 2009/09/30 20:35:21 vblavet Exp $
+// --------------------------------------------------------------------------------
+
+
+
+0 - Sommaire
+============
+ 1 - Introduction
+ 2 - What's new
+ 3 - Corrected bugs
+ 4 - Known bugs or limitations
+ 5 - License
+ 6 - Warning
+ 7 - Documentation
+ 8 - Author
+ 9 - Contribute
+
+1 - Introduction
+================
+
+ PclZip is a library that allow you to manage a Zip archive.
+
+ Full documentation about PclZip can be found here : http://www.phpconcept.net/pclzip
+
+2 - What's new
+==============
+
+ Version 2.8.2 :
+ - PCLZIP_CB_PRE_EXTRACT and PCLZIP_CB_POST_EXTRACT are now supported with
+ extraction as a string (PCLZIP_OPT_EXTRACT_AS_STRING). The string
+ can also be modified in the post-extract call back.
+ **Bugs correction :
+ - PCLZIP_OPT_REMOVE_ALL_PATH was not working correctly
+ - Remove use of eval() and do direct call to callback functions
+ - Correct support of 64bits systems (Thanks to WordPress team)
+
+ Version 2.8.1 :
+ - Move option PCLZIP_OPT_BY_EREG to PCLZIP_OPT_BY_PREG because ereg() is
+ deprecated in PHP 5.3. When using option PCLZIP_OPT_BY_EREG, PclZip will
+ automatically replace it by PCLZIP_OPT_BY_PREG.
+
+ Version 2.8 :
+ - Improve extraction of zip archive for large files by using temporary files
+ This feature is working like the one defined in r2.7.
+ Options are renamed : PCLZIP_OPT_TEMP_FILE_ON, PCLZIP_OPT_TEMP_FILE_OFF,
+ PCLZIP_OPT_TEMP_FILE_THRESHOLD
+ - Add a ratio constant PCLZIP_TEMPORARY_FILE_RATIO to configure the auto
+ sense of temporary file use.
+ - Bug correction : Reduce filepath in returned file list to remove ennoying
+ './/' preambule in file path.
+
+ Version 2.7 :
+ - Improve creation of zip archive for large files :
+ PclZip will now autosense the configured memory and use temporary files
+ when large file is suspected.
+ This feature can also ne triggered by manual options in create() and add()
+ methods. 'PCLZIP_OPT_ADD_TEMP_FILE_ON' force the use of temporary files,
+ 'PCLZIP_OPT_ADD_TEMP_FILE_OFF' disable the autosense technic,
+ 'PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD' allow for configuration of a size
+ threshold to use temporary files.
+ Using "temporary files" rather than "memory" might take more time, but
+ might give the ability to zip very large files :
+ Tested on my win laptop with a 88Mo file :
+ Zip "in-memory" : 18sec (max_execution_time=30, memory_limit=180Mo)
+ Zip "tmporary-files" : 23sec (max_execution_time=30, memory_limit=30Mo)
+ - Replace use of mktime() by time() to limit the E_STRICT error messages.
+ - Bug correction : When adding files with full windows path (drive letter)
+ PclZip is now working. Before, if the drive letter is not the default
+ path, PclZip was not able to add the file.
+
+ Version 2.6 :
+ - Code optimisation
+ - New attributes PCLZIP_ATT_FILE_COMMENT gives the ability to
+ add a comment for a specific file. (Don't really know if this is usefull)
+ - New attribute PCLZIP_ATT_FILE_CONTENT gives the ability to add a string
+ as a file.
+ - New attribute PCLZIP_ATT_FILE_MTIME modify the timestamp associated with
+ a file.
+ - Correct a bug. Files archived with a timestamp with 0h0m0s were extracted
+ with current time
+ - Add CRC value in the informations returned back for each file after an
+ action.
+ - Add missing closedir() statement.
+ - When adding a folder, and removing the path of this folder, files were
+ incorrectly added with a '/' at the beginning. Which means files are
+ related to root in unix systems. Corrected.
+ - Add conditional if before constant definition. This will allow users
+ to redefine constants without changing the file, and then improve
+ upgrade of pclzip code for new versions.
+
+ Version 2.5 :
+ - Introduce the ability to add file/folder with individual properties (file descriptor).
+ This gives for example the ability to change the filename of a zipped file.
+ . Able to add files individually
+ . Able to change full name
+ . Able to change short name
+ . Compatible with global options
+ - New attributes : PCLZIP_ATT_FILE_NAME, PCLZIP_ATT_FILE_NEW_SHORT_NAME, PCLZIP_ATT_FILE_NEW_FULL_NAME
+ - New error code : PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE
+ - Add a security control feature. PclZip can extract any file in any folder
+ of a system. People may use this to upload a zip file and try to override
+ a system file. The PCLZIP_OPT_EXTRACT_DIR_RESTRICTION will give the
+ ability to forgive any directory transversal behavior.
+ - New PCLZIP_OPT_EXTRACT_DIR_RESTRICTION : check extraction path
+ - New error code : PCLZIP_ERR_DIRECTORY_RESTRICTION
+ - Modification in PclZipUtilPathInclusion() : dir and path beginning with ./ will be prepend
+ by current path (getcwd())
+
+ Version 2.4 :
+ - Code improvment : try to speed up the code by removing unusefull call to pack()
+ - Correct bug in delete() : delete() should be called with no argument. This was not
+ the case in 2.3. This is corrected in 2.4.
+ - Correct a bug in path_inclusion function. When the path has several '../../', the
+ result was bad.
+ - Add a check for magic_quotes_runtime configuration. If enabled, PclZip will
+ disable it while working and det it back to its original value.
+ This resolve a lots of bad formated archive errors.
+ - Bug correction : PclZip now correctly unzip file in some specific situation,
+ when compressed content has same size as uncompressed content.
+ - Bug correction : When selecting option 'PCLZIP_OPT_REMOVE_ALL_PATH',
+ directories are not any more created.
+ - Code improvment : correct unclosed opendir(), better handling of . and .. in
+ loops.
+
+
+ Version 2.3 :
+ - Correct a bug with PHP5 : affecting the value 0xFE49FFE0 to a variable does not
+ give the same result in PHP4 and PHP5 ....
+
+ Version 2.2 :
+ - Try development of PCLZIP_OPT_CRYPT .....
+ However this becomes to a stop. To crypt/decrypt I need to multiply 2 long integers,
+ the result (greater than a long) is not supported by PHP. Even the use of bcmath
+ functions does not help. I did not find yet a solution ...;
+ - Add missing '/' at end of directory entries
+ - Check is a file is encrypted or not. Returns status 'unsupported_encryption' and/or
+ error code PCLZIP_ERR_UNSUPPORTED_ENCRYPTION.
+ - Corrected : Bad "version need to extract" field in local file header
+ - Add private method privCheckFileHeaders() in order to check local and central
+ file headers. PclZip is now supporting purpose bit flag bit 3. Purpose bit flag bit 3 gives
+ the ability to have a local file header without size, compressed size and crc filled.
+ - Add a generic status 'error' for file status
+ - Add control of compression type. PclZip only support deflate compression method.
+ Before v2.2, PclZip does not check the compression method used in an archive while
+ extracting. With v2.2 PclZip returns a new error status for a file using an unsupported
+ compression method. New status is "unsupported_compression". New error code is
+ PCLZIP_ERR_UNSUPPORTED_COMPRESSION.
+ - Add optional attribute PCLZIP_OPT_STOP_ON_ERROR. This will stop the extract of files
+ when errors like 'a folder with same name exists' or 'a newer file exists' or
+ 'a write protected file' exists, rather than set a status for the concerning file
+ and resume the extract of the zip.
+ - Add optional attribute PCLZIP_OPT_REPLACE_NEWER. This will force, during an extract' the
+ replacement of the file, even if a newer version of the file exists.
+ Note that today if a file with the same name already exists but is older it will be
+ replaced by the extracted one.
+ - Improve PclZipUtilOption()
+ - Support of zip archive with trailing bytes. Before 2.2, PclZip checks that the central
+ directory structure is the last data in the archive. Crypt encryption/decryption of
+ zip archive put trailing 0 bytes after decryption. PclZip is now supporting this.
+
+ Version 2.1 :
+ - Add the ability to abort the extraction by using a user callback function.
+ The user can now return the value '2' in its callback which indicates to stop the
+ extraction. For a pre call-back extract is stopped before the extration of the current
+ file. For a post call back, the extraction is stopped after.
+ - Add the ability to extract a file (or several files) directly in the standard output.
+ This is done by the new parameter PCLZIP_OPT_EXTRACT_IN_OUTPUT with method extract().
+ - Add support for parameters PCLZIP_OPT_COMMENT, PCLZIP_OPT_ADD_COMMENT,
+ PCLZIP_OPT_PREPEND_COMMENT. This will create, replace, add, or prepend comments
+ in the zip archive.
+ - When merging two archives, the comments are not any more lost, but merged, with a
+ blank space separator.
+ - Corrected bug : Files are not deleted when all files are asked to be deleted.
+ - Corrected bug : Folders with name '0' made PclZip to abort the create or add feature.
+
+
+ Version 2.0 :
+ ***** Warning : Some new features may break the backward compatibility for your scripts.
+ Please carefully read the readme file.
+ - Add the ability to delete by Index, name and regular expression. This feature is
+ performed by the method delete(), which uses the optional parameters
+ PCLZIP_OPT_BY_INDEX, PCLZIP_OPT_BY_NAME, PCLZIP_OPT_BY_EREG or PCLZIP_OPT_BY_PREG.
+ - Add the ability to extract by regular expression. To extract by regexp you must use the method
+ extract(), with the option PCLZIP_OPT_BY_EREG or PCLZIP_OPT_BY_PREG
+ (depending if you want to use ereg() or preg_match() syntax) followed by the
+ regular expression pattern.
+ - Add the ability to extract by index, directly with the extract() method. This is a
+ code improvment of the extractByIndex() method.
+ - Add the ability to extract by name. To extract by name you must use the method
+ extract(), with the option PCLZIP_OPT_BY_NAME followed by the filename to
+ extract or an array of filenames to extract. To extract all a folder, use the folder
+ name rather than the filename with a '/' at the end.
+ - Add the ability to add files without compression. This is done with a new attribute
+ which is PCLZIP_OPT_NO_COMPRESSION.
+ - Add the attribute PCLZIP_OPT_EXTRACT_AS_STRING, which allow to extract a file directly
+ in a string without using any file (or temporary file).
+ - Add constant PCLZIP_SEPARATOR for static configuration of filename separators in a single string.
+ The default separator is now a comma (,) and not any more a blank space.
+ THIS BREAK THE BACKWARD COMPATIBILITY : Please check if this may have an impact with
+ your script.
+ - Improve algorythm performance by removing the use of temporary files when adding or
+ extracting files in an archive.
+ - Add (correct) detection of empty filename zipping. This can occurs when the removed
+ path is the same
+ as a zipped dir. The dir is not zipped (['status'] = filtered), only its content.
+ - Add better support for windows paths (thanks for help from manus@manusfreedom.com).
+ - Corrected bug : When the archive file already exists with size=0, the add() method
+ fails. Corrected in 2.0.
+ - Remove the use of OS_WINDOWS constant. Use php_uname() function rather.
+ - Control the order of index ranges in extract by index feature.
+ - Change the internal management of folders (better handling of internal flag).
+
+
+ Version 1.3 :
+ - Removing the double include check. This is now done by include_once() and require_once()
+ PHP directives.
+ - Changing the error handling mecanism : Remove the use of an external error library.
+ The former PclError...() functions are replaced by internal equivalent methods.
+ By changing the environment variable PCLZIP_ERROR_EXTERNAL you can still use the former library.
+ Introducing the use of constants for error codes rather than integer values. This will help
+ in futur improvment.
+ Introduction of error handling functions like errorCode(), errorName() and errorInfo().
+ - Remove the deprecated use of calling function with arguments passed by reference.
+ - Add the calling of extract(), extractByIndex(), create() and add() functions
+ with variable options rather than fixed arguments.
+ - Add the ability to remove all the file path while extracting or adding,
+ without any need to specify the path to remove.
+ This is available for extract(), extractByIndex(), create() and add() functionS by using
+ the new variable options parameters :
+ - PCLZIP_OPT_REMOVE_ALL_PATH : by indicating this option while calling the fct.
+ - Ability to change the mode of a file after the extraction (chmod()).
+ This is available for extract() and extractByIndex() functionS by using
+ the new variable options parameters.
+ - PCLZIP_OPT_SET_CHMOD : by setting the value of this option.
+ - Ability to definition call-back options. These call-back will be called during the adding,
+ or the extracting of file (extract(), extractByIndex(), create() and add() functions) :
+ - PCLZIP_CB_PRE_EXTRACT : will be called before each extraction of a file. The user
+ can trigerred the change the filename of the extracted file. The user can triggered the
+ skip of the extraction. This is adding a 'skipped' status in the file list result value.
+ - PCLZIP_CB_POST_EXTRACT : will be called after each extraction of a file.
+ Nothing can be triggered from that point.
+ - PCLZIP_CB_PRE_ADD : will be called before each add of a file. The user
+ can trigerred the change the stored filename of the added file. The user can triggered the
+ skip of the add. This is adding a 'skipped' status in the file list result value.
+ - PCLZIP_CB_POST_ADD : will be called after each add of a file.
+ Nothing can be triggered from that point.
+ - Two status are added in the file list returned as function result : skipped & filename_too_long
+ 'skipped' is used when a call-back function ask for skipping the file.
+ 'filename_too_long' is used while adding a file with a too long filename to archive (the file is
+ not added)
+ - Adding the function PclZipUtilPathInclusion(), that check the inclusion of a path into
+ a directory.
+ - Add a check of the presence of the archive file before some actions (like list, ...)
+ - Add the initialisation of field "index" in header array. This means that by
+ default index will be -1 when not explicitly set by the methods.
+
+ Version 1.2 :
+ - Adding a duplicate function.
+ - Adding a merge function. The merge function is a "quick merge" function,
+ it just append the content of an archive at the end of the first one. There
+ is no check for duplicate files or more recent files.
+ - Improve the search of the central directory end.
+
+ Version 1.1.2 :
+
+ - Changing the license of PclZip. PclZip is now released under the GNU / LGPL license
+ (see License section).
+ - Adding the optional support of a static temporary directory. You will need to configure
+ the constant PCLZIP_TEMPORARY_DIR if you want to use this feature.
+ - Improving the rename() function. In some cases rename() does not work (different
+ Filesystems), so it will be replaced by a copy() + unlink() functions.
+
+ Version 1.1.1 :
+
+ - Maintenance release, no new feature.
+
+ Version 1.1 :
+
+ - New method Add() : adding files in the archive
+ - New method ExtractByIndex() : partial extract of the archive, files are identified by
+ their index in the archive
+ - New method DeleteByIndex() : delete some files/folder entries from the archive,
+ files are identified by their index in the archive.
+ - Adding a test of the zlib extension presence. If not present abort the script.
+
+ Version 1.0.1 :
+
+ - No new feature
+
+
+3 - Corrected bugs
+==================
+
+ Corrected in Version 2.0 :
+ - Corrected : During an extraction, if a call-back fucntion is used and try to skip
+ a file, all the extraction process is stopped.
+
+ Corrected in Version 1.3 :
+ - Corrected : Support of static synopsis for method extract() is broken.
+ - Corrected : invalid size of archive content field (0xFF) should be (0xFFFF).
+ - Corrected : When an extract is done with a remove_path parameter, the entry for
+ the directory with exactly the same path is not skipped/filtered.
+ - Corrected : extractByIndex() and deleteByIndex() were not managing index in the
+ right way. For example indexes '1,3-5,11' will only extract files 1 and 11. This
+ is due to a sort of the index resulting table that puts 11 before 3-5 (sort on
+ string and not interger). The sort is temporarilly removed, this means that
+ you must provide a sorted list of index ranges.
+
+ Corrected in Version 1.2 :
+
+ - Nothing.
+
+ Corrected in Version 1.1.2 :
+
+ - Corrected : Winzip is unable to delete or add new files in a PclZip created archives.
+
+ Corrected in Version 1.1.1 :
+
+ - Corrected : When archived file is not compressed (0% compression), the
+ extract method fails.
+
+ Corrected in Version 1.1 :
+
+ - Corrected : Adding a complete tree of folder may result in a bad archive
+ creation.
+
+ Corrected in Version 1.0.1 :
+
+ - Corrected : Error while compressing files greater than PCLZIP_READ_BLOCK_SIZE (default=1024).
+
+
+4 - Known bugs or limitations
+=============================
+
+ Please publish bugs reports in SourceForge :
+ http://sourceforge.net/tracker/?group_id=40254&atid=427564
+
+ In Version 2.x :
+ - PclZip does only support file uncompressed or compressed with deflate (compression method 8)
+ - PclZip does not support password protected zip archive
+ - Some concern were seen when changing mtime of a file while archiving.
+ Seems to be linked to Daylight Saving Time (PclTest_changing_mtime).
+
+ In Version 1.2 :
+
+ - merge() methods does not check for duplicate files or last date of modifications.
+
+ In Version 1.1 :
+
+ - Limitation : Using 'extract' fields in the file header in the zip archive is not supported.
+ - WinZip is unable to delete a single file in a PclZip created archive. It is also unable to
+ add a file in a PclZip created archive. (Corrected in v.1.2)
+
+ In Version 1.0.1 :
+
+ - Adding a complete tree of folder may result in a bad archive
+ creation. (Corrected in V.1.1).
+ - Path given to methods must be in the unix format (/) and not the Windows format (\).
+ Workaround : Use only / directory separators.
+ - PclZip is using temporary files that are sometime the name of the file with a .tmp or .gz
+ added suffix. Files with these names may already exist and may be overwritten.
+ Workaround : none.
+ - PclZip does not check if the zlib extension is present. If it is absent, the zip
+ file is not created and the lib abort without warning.
+ Workaround : enable the zlib extension on the php install
+
+ In Version 1.0 :
+
+ - Error while compressing files greater than PCLZIP_READ_BLOCK_SIZE (default=1024).
+ (Corrected in v.1.0.1)
+ - Limitation : Multi-disk zip archive are not supported.
+
+
+5 - License
+===========
+
+ Since version 1.1.2, PclZip Library is released under GNU/LGPL license.
+ This library is free, so you can use it at no cost.
+
+ HOWEVER, if you release a script, an application, a library or any kind of
+ code using PclZip library (or a part of it), YOU MUST :
+ - Indicate in the documentation (or a readme file), that your work
+ uses PclZip Library, and make a reference to the author and the web site
+ http://www.phpconcept.net
+ - Gives the ability to the final user to update the PclZip libary.
+
+ I will also appreciate that you send me a mail (vincent@phpconcept.net), just to
+ be aware that someone is using PclZip.
+
+ For more information about GNU/LGPL license : http://www.gnu.org
+
+6 - Warning
+=================
+
+ This library and the associated files are non commercial, non professional work.
+ It should not have unexpected results. However if any damage is caused by this software
+ the author can not be responsible.
+ The use of this software is at the risk of the user.
+
+7 - Documentation
+=================
+ PclZip User Manuel is available in English on PhpConcept : http://www.phpconcept.net/pclzip/man/en/index.php
+ A Russian translation was done by Feskov Kuzma : http://php.russofile.ru/ru/authors/unsort/zip/
+
+8 - Author
+==========
+
+ This software was written by Vincent Blavet (vincent@phpconcept.net) on its leasure time.
+
+9 - Contribute
+==============
+ If you want to contribute to the development of PclZip, please contact vincent@phpconcept.net.
+ If you can help in financing PhpConcept hosting service, please go to
+ http://www.phpconcept.net/soutien.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/AES.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/AES.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/AES.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/AES.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/Base.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Base.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/Base.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Base.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/Blowfish.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Blowfish.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/Blowfish.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Blowfish.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/DES.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/DES.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/DES.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/DES.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/Hash.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Hash.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/Hash.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Hash.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/RC2.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/RC2.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/RC2.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/RC2.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/RC4.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/RC4.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/RC4.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/RC4.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/RSA.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/RSA.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/RSA.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/RSA.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/Random.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Random.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/Random.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Random.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/Rijndael.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Rijndael.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/Rijndael.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Rijndael.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/TripleDES.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/TripleDES.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/TripleDES.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/TripleDES.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/Twofish.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Twofish.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Crypt/Twofish.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Crypt/Twofish.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/File/ANSI.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/File/ANSI.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/File/ANSI.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/File/ANSI.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/File/ASN1.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/File/ASN1.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/File/ASN1.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/File/ASN1.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/File/X509.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/File/X509.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/File/X509.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/File/X509.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Math/BigInteger.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Math/BigInteger.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Math/BigInteger.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Math/BigInteger.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Net/SCP.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SCP.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Net/SCP.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SCP.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Net/SFTP.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SFTP.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Net/SFTP.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SFTP.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Net/SFTP/Stream.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SFTP/Stream.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Net/SFTP/Stream.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SFTP/Stream.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Net/SSH1.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SSH1.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Net/SSH1.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SSH1.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Net/SSH2.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SSH2.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/Net/SSH2.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/Net/SSH2.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/System/SSH/Agent.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/System/SSH/Agent.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/System/SSH/Agent.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/System/SSH/Agent.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/System/SSH_Agent.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/System/SSH_Agent.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/System/SSH_Agent.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/System/SSH_Agent.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/openssl.cnf b/rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/openssl.cnf
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/phpseclib/openssl.cnf
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/phpseclib/openssl.cnf
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/spyc/COPYING b/rainloop/app/rainloop/v/1.12.1/app/libraries/spyc/COPYING
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/spyc/COPYING
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/spyc/COPYING
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/spyc/README.md b/rainloop/app/rainloop/v/1.12.1/app/libraries/spyc/README.md
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/spyc/README.md
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/spyc/README.md
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/spyc/Spyc.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/spyc/Spyc.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/spyc/Spyc.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/spyc/Spyc.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/spyc/composer.json b/rainloop/app/rainloop/v/1.12.1/app/libraries/spyc/composer.json
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/spyc/composer.json
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/spyc/composer.json
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/tmhOAuth/LICENSE b/rainloop/app/rainloop/v/1.12.1/app/libraries/tmhOAuth/LICENSE
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/tmhOAuth/LICENSE
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/tmhOAuth/LICENSE
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/tmhOAuth/README.md b/rainloop/app/rainloop/v/1.12.1/app/libraries/tmhOAuth/README.md
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/tmhOAuth/README.md
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/tmhOAuth/README.md
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/tmhOAuth/cacert.pem b/rainloop/app/rainloop/v/1.12.1/app/libraries/tmhOAuth/cacert.pem
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/tmhOAuth/cacert.pem
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/tmhOAuth/cacert.pem
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/tmhOAuth/tmhOAuth.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/tmhOAuth/tmhOAuth.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/tmhOAuth/tmhOAuth.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/tmhOAuth/tmhOAuth.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/libraries/tmhOAuth/tmhUtilities.php b/rainloop/app/rainloop/v/1.12.1/app/libraries/tmhOAuth/tmhUtilities.php
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/libraries/tmhOAuth/tmhUtilities.php
rename to rainloop/app/rainloop/v/1.12.1/app/libraries/tmhOAuth/tmhUtilities.php
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/README b/rainloop/app/rainloop/v/1.12.1/app/localization/README
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/README
rename to rainloop/app/rainloop/v/1.12.1/app/localization/README
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/README b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/README
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/README
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/README
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/_source.en.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/_source.en.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/_source.en.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/_source.en.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/cs_CZ.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/cs_CZ.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/cs_CZ.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/cs_CZ.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/da_DK.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/da_DK.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/da_DK.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/da_DK.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/de_DE.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/de_DE.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/de_DE.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/de_DE.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/en_US.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/en_US.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/en_US.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/en_US.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/es_ES.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/es_ES.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/es_ES.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/es_ES.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/fa_IR.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/fa_IR.yml
similarity index 98%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/fa_IR.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/fa_IR.yml
index 68f6c7a1ad49dddedb90aff815857f63faa79b26..28771b2e1667b39f468ef389a52dc1fc88966346 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/fa_IR.yml
+++ b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/fa_IR.yml
@@ -26,6 +26,7 @@ fa_IR:
LABEL_ALLOW_LANGUAGES_ON_SETTINGS: "زبان در صفحه تنظیمات قابل انتخاب باشد"
LABEL_ALLOW_THEMES_ON_SETTINGS: "پوسته در صفحه تنظیمات قابل انتخاب باشد"
LABEL_ALLOW_BACKGROUND_ON_SETTINGS: "تصویر پشت زمینه در صفحه تنظیمات قابل انتخاب باشد"
+ LABEL_NEW_FOLDER_MOVE: "دکمه جدید «انتقال به پوشه»"
LABEL_SHOW_THUMBNAILS: "اندازه کوچک را نشان بده (پیوستها)"
LABEL_ALLOW_GRAVATAR: "اجازه استفاده از آواتار"
LEGEND_MAIN: "اصلی"
@@ -33,6 +34,7 @@ fa_IR:
LABEL_ALLOW_ADDITIONAL_ACCOUNTS: "مجوز استفاده از نامهای کاربری دیگر"
LABEL_ALLOW_IDENTITIES: "اجازه استفاده از چندین شناسه"
LABEL_ALLOW_TEMPLATES: "اجازه استفاده از پوستهها"
+ ALERT_DATA_ACCESS: "شاخه data قابل دسترس هست. تنظیمات وبسرور را طوری انجام دهید این شاخه از بیرون قابل دسترس نباشد. اطلاعات بیشتر اینجا هست:"
ALERT_WARNING: "اخطار!"
HTML_ALERT_WEAK_PASSWORD: |+
شما در حال استفاده از گذرواژه پیشفرض کاربر مدیر هستید.
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/fi_FI.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/fi_FI.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/fi_FI.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/fi_FI.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/fr_FR.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/fr_FR.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/fr_FR.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/fr_FR.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/hu_HU.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/hu_HU.yml
similarity index 98%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/hu_HU.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/hu_HU.yml
index df08e6c54dd80cb8ae794ddd97cdc30f7453067a..822747b6d0a305bfa7ea65de49a70279985c6feb 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/hu_HU.yml
+++ b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/hu_HU.yml
@@ -34,6 +34,7 @@ hu_HU:
LABEL_ALLOW_ADDITIONAL_ACCOUNTS: "További fiókok engedélyezése"
LABEL_ALLOW_IDENTITIES: "Több identitás engedélyezése"
LABEL_ALLOW_TEMPLATES: "Sablonok engedélyezése"
+ ALERT_DATA_ACCESS: "A RainLoop adatmappája hozzáférhető. Kérlek állítsd be úgy a webszervert, hogy az adatmappát rejtse el a külső hozzáférés elől. További tudnivalók itt:"
ALERT_WARNING: "Figyelmeztetés!"
HTML_ALERT_WEAK_PASSWORD: |
Az alapértelmezett admin jelszót használod
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/it_IT.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/it_IT.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/it_IT.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/it_IT.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/ja_JP.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/ja_JP.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/ja_JP.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/ja_JP.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/lt_LT.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/lt_LT.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/lt_LT.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/lt_LT.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/nb_NO.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/nb_NO.yml
similarity index 99%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/nb_NO.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/nb_NO.yml
index 1d4bf2454d1a8db4e00e81aac10595a086aafcb4..2f5fcbcadc728bf80f65f4538d2b9721a8c2f190 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/nb_NO.yml
+++ b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/nb_NO.yml
@@ -34,6 +34,7 @@ nb_NO:
LABEL_ALLOW_ADDITIONAL_ACCOUNTS: "Tillat bruk av flere kontoer"
LABEL_ALLOW_IDENTITIES: "Tillat bruk av flere identiteter"
LABEL_ALLOW_TEMPLATES: "Tillat bruk av maler"
+ ALERT_DATA_ACCESS: "RainLoop-datamappa di er offentlig tiljgengelig. Sett opp webtjeneren slik at den ikke viser datamappa. Les mer her:"
ALERT_WARNING: "Advarsel!"
HTML_ALERT_WEAK_PASSWORD: |
Du bruker forvalgt admin-passord.
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/nl_NL.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/nl_NL.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/nl_NL.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/nl_NL.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/pl_PL.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/pl_PL.yml
similarity index 64%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/pl_PL.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/pl_PL.yml
index 3925ff5d774c31668b4ace2b873bdd83cce656a5..fb263596584ef6475c3b28d37eb1ef7fa1571381 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/pl_PL.yml
+++ b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/pl_PL.yml
@@ -2,7 +2,7 @@ pl_PL:
LOGIN:
LABEL_LOGIN: "Login"
LABEL_PASSWORD: "Hasło"
- BUTTON_LOGIN: "Zaloguj"
+ BUTTON_LOGIN: "Zaloguj do panelu administracjnego"
TOP_PANEL:
LABEL_PREMIUM: "Premium"
LABEL_ADMIN_PANEL: "Panel administracyjny"
@@ -17,12 +17,12 @@ pl_PL:
LABEL_PLUGINS_NAME: "Wtyczki"
LABEL_PACKAGES_NAME: "Zarządzanie wtyczkami"
LABEL_LICENSING_NAME: "Licencjonowanie"
- LABEL_ABOUT_NAME: "O skrypcie"
+ LABEL_ABOUT_NAME: "O programie"
TAB_GENERAL:
LEGEND_INTERFACE: "Interfejs"
- LABEL_LANGUAGE: "Język:"
- LABEL_LANGUAGE_ADMIN: "Język (admin):"
- LABEL_THEME: "Motyw:"
+ LABEL_LANGUAGE: "Język"
+ LABEL_LANGUAGE_ADMIN: "Język (admin)"
+ LABEL_THEME: "Motyw"
LABEL_ALLOW_LANGUAGES_ON_SETTINGS: "Zezwól użytkownikowi na wybór języka"
LABEL_ALLOW_THEMES_ON_SETTINGS: "Zezwól użytkownikowi na zmianę motywu"
LABEL_ALLOW_BACKGROUND_ON_SETTINGS: "Zezwól użytkownikowi na użycie własnego tła"
@@ -30,63 +30,64 @@ pl_PL:
LABEL_SHOW_THUMBNAILS: "Pokaż miniatury (załączniki)"
LABEL_ALLOW_GRAVATAR: "Zezwól na używanie gravatarów"
LEGEND_MAIN: "Główne"
- LABEL_ATTACHMENT_SIZE_LIMIT: "Maks. rozmiar zał.:"
+ LABEL_ATTACHMENT_SIZE_LIMIT: "Maksymalny rozmiar załącznika"
LABEL_ALLOW_ADDITIONAL_ACCOUNTS: "Zezwól na dodatkowe konta"
LABEL_ALLOW_IDENTITIES: "Zezwól na posiadanie wielu tożsamości"
LABEL_ALLOW_TEMPLATES: "Zezwól na używanie szablonów"
+ ALERT_DATA_ACCESS: "Folder data jest osiągalny z poziomu przeglądarki WWW. Zmień konfigurację serwera www, aby ukryć ten folder z zewnątrz. Więcej informacji tutaj: "
ALERT_WARNING: "Ostrzeżenie!"
HTML_ALERT_WEAK_PASSWORD: |
Korzystasz z domyślnego hasła administratora.
- Ze względów bezpieczeństwa, proszę
- zmienić hasło
+ Ze względów bezpieczeństwa
+ zmień hasło
na inne.
TAB_LOGIN:
- LEGEND_LOGIN_SCREEN: "Logowanie"
- LABEL_DEFAULT_DOMAIN: "Domyślna domena:"
+ LEGEND_LOGIN_SCREEN: "Ekran logowania"
+ LABEL_DEFAULT_DOMAIN: "Domyślna domena"
LABEL_DETERMINE_USER_DOMAIN: "Spróbuj określić domenę użytkownika"
- LABEL_ALLOW_LANGUAGES_ON_LOGIN: "Zezwól na zmianę języka podczas logowania"
+ LABEL_ALLOW_LANGUAGES_ON_LOGIN: "Zezwól na zmianę języka na ekranie logowania"
LABEL_DETERMINE_USER_LANGUAGE: "Spróbuj określić język użytkownika"
TAB_BRANDING:
LEGEND_BRANDING: "Personalizacja"
- LABEL_PAGE_TITLE: "Tytuł strony:"
- LABEL_LOADING_DESCRIPTION: "Komunikat ład. strony:"
- LABEL_FAVICON_URL: "Favicon:"
+ LABEL_PAGE_TITLE: "Tytuł strony"
+ LABEL_LOADING_DESCRIPTION: "Komunikat ładowania strony"
+ LABEL_FAVICON_URL: "Favicon"
LEGEND_LOGIN: "Login"
- LABEL_LOGIN_LOGO: "Logo:"
- LABEL_LOGIN_DESCRIPTION: "Opis:"
- LABEL_LOGIN_BACKGROUND: "Tło:"
- LABEL_LOGIN_CUSTOM_CSS: "Własny arkusz stylów:"
- LABEL_LOGIN_SHOW_POWERED_LINK: "Pokaż link: \"Powered by RainLoop\""
+ LABEL_LOGIN_LOGO: "Logo"
+ LABEL_LOGIN_DESCRIPTION: "Opis"
+ LABEL_LOGIN_BACKGROUND: "Tło"
+ LABEL_LOGIN_CUSTOM_CSS: "Własny arkusz styli CSS"
+ LABEL_LOGIN_SHOW_POWERED_LINK: "Pokaż link \"Powered by RainLoop\""
LEGEND_USER: "Użytkownik"
- LABEL_USER_LOGO: "Logo:"
- LABEL_USER_LOGO_TITLE: "Tytuł loga:"
- LABEL_USER_LOGO_MESSAGE: "Logo (widok wiad.)"
- LABEL_USER_CUSTOM_CSS: "Własny arkusz stylów:"
- LEGEND_WELCOME_PAGE: "Str. główna"
- LABEL_WELCOME_PAGE_TITLE: "Tytuł:"
- LABEL_WELCOME_PAGE_URL: "Adres URL:"
- LABEL_WELCOME_PAGE_DISPLAY: "Wyświetl:"
- OPTION_WELCOME_PAGE_DISPLAY_NONE: "nigdy"
- OPTION_WELCOME_PAGE_DISPLAY_ONCE: "raz"
- OPTION_WELCOME_PAGE_DISPLAY_ALWAYS: "zawsze"
- HTML_ALERT_PREMIUM: "Ta opcja jest dostępna tylko dla licencji Premium ."
TAB_CONTACTS:
LEGEND_CONTACTS: "Kontakty"
LEGEND_STORAGE: "Baza danych (PDO)"
LABEL_ENABLE_CONTACTS: "Włącz kontakty"
LABEL_ALLOW_SYNC: "Zezwól na synchronizację kontaktów (przy użyciu zewnętrznego serwera CardDAV)"
- LABEL_STORAGE_TYPE: "Typ:"
- LABEL_STORAGE_DSN: "Adres DSN:"
- LABEL_STORAGE_USER: "Użytkownik:"
- LABEL_STORAGE_PASSWORD: "Hasło:"
+ LABEL_STORAGE_TYPE: "Typ"
+ LABEL_STORAGE_DSN: "Adres DSN"
+ LABEL_STORAGE_USER: "Użytkownik"
+ LABEL_STORAGE_PASSWORD: "Hasło"
BUTTON_TEST: "Testuj"
ALERT_NOTICE: "Powiadomienie!"
HTML_ALERT_DO_NOT_USE_THIS_DATABASE: "Nie używaj tej bazy danych z dużą ilością aktywnych użytkowników."
HTML_ALERT_DOES_NOT_SUPPORTED: |
Twój system nie zawiera wsparcia dla obsługi kontaktów.
- Musisz zainstalować lub uruchomić na serwerze jedno z rozszerzeń PDO (SQLite / MySQL / PostgreSQL) .
+ Musisz zainstalować lub uruchomić na serwerze jedno z rozszerzeń PDO (SQLite / MySQL / PostgreSQL) .
TAB_DOMAINS:
LEGEND_DOMAINS: "Domeny"
BUTTON_ADD_DOMAIN: "Dodaj domenę"
@@ -98,42 +99,42 @@ pl_PL:
Kliknij na nazwę, aby skonfigurować domenę.
TAB_SECURITY:
LEGEND_SECURITY: "Bezpieczeństwo"
- LABEL_ALLOW_TWO_STEP: "Zezwól na dwuskładnikową autoryzację"
- LABEL_FORCE_TWO_STEP: "Wymuś dwuskładnikową autoryzację"
+ LABEL_ALLOW_TWO_STEP: "Zezwól na autoryzację 2-etapową"
+ LABEL_FORCE_TWO_STEP: "Wymuś autoryzację 2-etapową"
LABEL_USE_IMAGE_PROXY: "Użyj lokalnego serwera proxy dla zewnętrznych obrazów"
- LABEL_ALLOW_OPEN_PGP: "Zezwól na użycie OpenPGP"
+ LABEL_ALLOW_OPEN_PGP: "Zezwalaj na używanie OpenPGP"
LABEL_SHOW_PHP_INFO: "Pokaż informacje o wersji PHP"
LEGEND_ADMIN_PANEL_ACCESS_CREDENTIALS: "Dane dostępowe panelu administracyjnego"
- LABEL_CURRENT_PASSWORD: "Bieżące hasło:"
- LABEL_NEW_LOGIN: "Nowy login:"
- LABEL_NEW_PASSWORD: "Nowe hasło:"
- LABEL_REPEAT_PASSWORD: "Powtórz hasło:"
+ LABEL_CURRENT_PASSWORD: "Bieżące hasło"
+ LABEL_NEW_LOGIN: "Nowy login"
+ LABEL_NEW_PASSWORD: "Nowe hasło"
+ LABEL_REPEAT_PASSWORD: "Powtórz hasło"
BUTTON_UPDATE_PASSWORD: "Zaktualizuj hasło"
LEGEND_SSL: "SSL"
LABEL_REQUIRE_VERIFICATION: "Wymagaj sprawdzania poprawności certyfikatów SSL (IMAP/SMTP)"
- LABEL_ALLOW_SELF_SIGNED: "Zezwól na używanie certyfikatów podpisanych przez siebie"
+ LABEL_ALLOW_SELF_SIGNED: "Zezwól na używanie certyfikatów podpisanych samodzielnie"
TAB_INTEGRATIONS:
LEGEND_GOOGLE: "Google"
- LABEL_ENABLE_GOOGLE: "Włącz obsługę platformy Google"
+ LABEL_ENABLE_GOOGLE: "Włącz integrację z Google"
LABEL_GOOGLE_AUTH: "Autoryzacja"
- LABEL_GOOGLE_DRIVE: "Obsługa dysku Google (widok tworz. wiadomości)"
- LABEL_GOOGLE_PREVIEW: "Obsługa przeglądarki Google (podgląd dla plików: Microsoft Word, Excel i PowerPoint)"
- LABEL_GOOGLE_CLIENT_ID: "Identyfikator:"
- LABEL_GOOGLE_CLIENT_SECRET: "Hasło:"
- LABEL_GOOGLE_API_KEY: "Klucz API:"
- HINT_GOOGLE_API_KEY: "Wymagane dla obsługi interfejsu usługi: 'Dysk Google'"
+ LABEL_GOOGLE_DRIVE: "Obsługa dysku Google (widok tworzenia wiadomości)"
+ LABEL_GOOGLE_PREVIEW: "Obsługa przeglądarki Google (podgląd dla plików Microsoft Word, Excel i PowerPoint)"
+ LABEL_GOOGLE_CLIENT_ID: "Identyfikator klienta"
+ LABEL_GOOGLE_CLIENT_SECRET: "Hasło"
+ LABEL_GOOGLE_API_KEY: "Klucz API"
+ HINT_GOOGLE_API_KEY: "Wymagane dla obsługi interfejsu usługi 'Dysk Google'"
LEGEND_FACEBOOK: "Facebook"
- LABEL_ENABLE_FACEBOOK: "Włącz obsługę platformy Facebook (autoryzacja)"
- LABEL_FACEBOOK_APP_ID: "Identyfikator aplikacji:"
- LABEL_FACEBOOK_APP_SECRET: "Hasło aplikacji:"
+ LABEL_ENABLE_FACEBOOK: "Włącz integrację z Facebook (autoryzacja)"
+ LABEL_FACEBOOK_APP_ID: "Identyfikator aplikacji"
+ LABEL_FACEBOOK_APP_SECRET: "Hasło aplikacji"
LEGEND_TWITTER: "Twitter"
- LABEL_ENABLE_TWITTER: "Włącz obsługę platformy Twitter (autoryzacja)"
- LABEL_TWITTER_CONSUMER_KEY: "Klucz użytkownika:"
- LABEL_TWITTER_CONSUMER_SECRET: "Hasło użytkownika:"
+ LABEL_ENABLE_TWITTER: "Włącz integrację z Twitter (autoryzacja)"
+ LABEL_TWITTER_CONSUMER_KEY: "Klucz użytkownika"
+ LABEL_TWITTER_CONSUMER_SECRET: "Hasło użytkownika"
LEGEND_DROPBOX: "Dropbox"
- LABEL_ENABLE_DROPBOX: "Włącz obsługę platformy Dropbox"
- LABEL_DROPBOX_API_KEY: "Klucz API:"
- TOP_ALERT: "Szczegółowe informacje na temat obsługi platform, można znaleźść pod adresem: "
+ LABEL_ENABLE_DROPBOX: "Włącz integrację z Dropbox"
+ LABEL_DROPBOX_API_KEY: "Klucz API"
+ TOP_ALERT: "Szczegółowe informacje na temat obsługi platform, można znaleźć pod adresem "
TAB_PLUGINS:
LEGEND_PLUGINS: "Wtyczki"
LABEL_ENABLE_PLUGINS: "Włącz obsługę wtyczek"
@@ -141,53 +142,53 @@ pl_PL:
LINK_INSTALL_NEW: "Kliknij tutaj, aby zainstalować nowe wtyczki!"
HINT_CLICK_NAME: "Kliknij na nazwę, aby skonfigurować wtyczkę."
TAB_PACKAGES:
- LEGEND_AVAILABLE_FOR_UPDATE: "Aktualizacja"
- LEGEND_AVAILABLE_FOR_INSTALLATION: "Do zainstalowania"
- LEGEND_INSTALLED_PACKAGES: "Zainstalowane"
+ LEGEND_AVAILABLE_FOR_UPDATE: "Dostępna do aktualizacji"
+ LEGEND_AVAILABLE_FOR_INSTALLATION: "Dostępna do zainstalowania"
+ LEGEND_INSTALLED_PACKAGES: "Zainstalowane pakiety"
ALERT_CANNOT_ACCESS_REPOSITORY: "Nie można uzyskać dostępu do repozytorium."
TAB_LICENSING:
- LABEL_YOUR_DOMAIN: "Domena:"
- LABEL_VERSION: "Wersja:"
- LABEL_CHECKING: "sprawdzanie..."
+ LABEL_YOUR_DOMAIN: "Twoja domena"
+ LABEL_VERSION: "Wersja"
+ LABEL_CHECKING: "Sprawdzanie..."
TYPE_BASIC_HINT: "Ta domena nie jest licencjonowana do użytku komercyjnego."
TYPE_BASIC_HINT_2: "Nie można dodać licencji dla tej domeny."
- HTML_ALERT_TOP_1: "RainLoop Webmail korzysta z licencji:"
- HTML_ALERT_TOP_2: "Możesz używać tego klienta za darmo , tylko dla prywatnych (własnych) projektów."
+ HTML_ALERT_TOP_1: "RainLoop Webmail korzysta z licencji"
+ HTML_ALERT_TOP_2: "Możesz używać tego klienta za darmo , tylko do celów prywatnych ."
HTML_ALERT_TOP_3: |
- Do komercyjnego użytku (używania dodatkowych opcji) RainLoop Webmail , wymagane jest posiadanie
+ Do użytku komercyjnego (z dodatkowymi opcjami) RainLoop Webmail , wymagane jest posiadanie
ważnej subskrypcji .
TYPE_PREMIUM_LIFETIME: "Dożywotnia"
- LABEL_SUB_EXPIRES: "Subskrypcja wygasa:"
- BUTTON_ACTIVATE: "Aktywuj klucz"
+ LABEL_SUB_EXPIRES: "Subskrypcja wygasa"
+ BUTTON_ACTIVATE: "Aktywuj klucz dla tej domeny"
BUTTON_PURCHASE: "Kup klucz"
BUTTON_TRIAL: "Wersja testowa"
TAB_ABOUT:
- LEGEND_ABOUT: "O skrypcie"
+ LEGEND_ABOUT: "O programie"
LABEL_TAG_HINT: "Prosty, nowoczesny i szybki klient pocztowy"
LABEL_ALL_RIGHTS_RESERVED: "Wszystkie prawa zastrzeżone."
- HINT_READ_CHANGE_LOG: "Przed aktualizacją, proszę przeczytać listę zmian."
- HINT_IS_UP_TO_DATE: "Klient RainLoop jest aktualny."
+ HINT_READ_CHANGE_LOG: "Przed aktualizacją przeczytaj proszę listę zmian."
+ HINT_IS_UP_TO_DATE: "RainLoop jest aktualny."
HTML_NEW_VERSION: "Dostępna jest nowa wersja: %VERSION% ."
- LABEL_UPDATING: "Aktualizowanie..."
+ LABEL_UPDATING: "Aktualizacja w toku..."
LABEL_CHECKING: "Szukanie aktualizacji..."
BUTTON_UPDATE: "Zaktualizuj"
BUTTON_DOWNLOAD: "Pobierz"
BUTTON_CHANGELOG: "Lista zmian"
POPUPS_ACTIVATE:
- TITLE_ACTIVATE: "Aktywacja klucza subskrypcji"
- TITLE_ACTIVATION: "Aktywowanie..."
- LABEL_DOMAIN: "Domena:"
- LABEL_SUB_KEY: "Klucz subskrypcji:"
+ TITLE_ACTIVATE: "Czy chcesz aktywować klucz subskrypcji?"
+ TITLE_ACTIVATION: "Aktywacja w toku..."
+ LABEL_DOMAIN: "Domena"
+ LABEL_SUB_KEY: "Klucz subskrypcji"
BUTTON_ACTIVATE: "Aktywuj"
LABEL_ACTIVATED: "Aktywowano"
ERROR_INVALID_SUBS_KEY: "Niepoprawny klucz subskrypcji"
- SUBS_KEY_ACTIVATED: "Aktywowano klucz subskrypcji"
+ SUBS_KEY_ACTIVATED: "Poprawnie aktywowano klucz subskrypcji"
HTML_DESC: |
- Subskrypcja premium dla domeny: %DOMAIN% , zostanie przedłużona po aktywacji.
+ Subskrypcja premium dla domeny %DOMAIN% , zostanie przedłużona po aktywacji.
- Zwróc uwagę, że klucz subskrypcji może być aktywowany tylko dla jednej domeny.
+ Zwróć uwagę, że klucz subskrypcji może być aktywowany tylko dla jednej domeny.
- Po uruchomieniu aktywacji, nie można jej przerwac lub anulować.
+ Po uruchomieniu aktywacji, nie można jej przerwać lub anulować.
POPUPS_DOMAIN_ALIAS:
TITLE_ADD_DOMAIN_ALIAS: "Dodaj Alias"
LABEL_ALIAS: "Alias"
@@ -196,16 +197,16 @@ pl_PL:
BUTTON_ADD: "Dodaj"
POPUPS_DOMAIN:
TITLE_ADD_DOMAIN: "Dodawanie domeny"
- TITLE_ADD_DOMAIN_WITH_NAME: "Dodawanie domeny: \"%NAME%\""
- TITLE_EDIT_DOMAIN: "Edycja domeny: \"%NAME%\""
+ TITLE_ADD_DOMAIN_WITH_NAME: "Dodawanie domeny \"%NAME%\""
+ TITLE_EDIT_DOMAIN: "Edycja domeny \"%NAME%\""
LABEL_NAME: "Nazwa"
NAME_HELPER: "obsługiwany znak wieloznaczności - *"
LABEL_IMAP: "IMAP"
LABEL_SMTP: "SMTP"
LABEL_SIEVE: "SIEVE"
- LABEL_SERVER: "Serwer:"
- LABEL_PORT: "Port:"
- LABEL_SECURE: "Rodzaj połączenia:"
+ LABEL_SERVER: "Serwer"
+ LABEL_PORT: "Port"
+ LABEL_SECURE: "Rodzaj połączenia"
LABEL_WHITE_LIST: "Biała lista"
SECURE_OPTION_NONE: "Bez zabezpieczeń"
SECURE_OPTION_SSL: "SSL/TLS"
@@ -214,7 +215,7 @@ pl_PL:
LABEL_ALLOW_USER_SCRIPT: "Zezwól na spersonalizowany skrypt użytkownika"
LABEL_USE_SHORT_LOGIN: "Użyj krótkiego loginu"
LABEL_USE_AUTH: "Użyj autoryzacji"
- LABEL_USE_PHP_MAIL: "Użyj funkcji php: 'mail()'"
+ LABEL_USE_PHP_MAIL: "Użyj funkcji php 'mail()'"
BUTTON_TEST: "Test"
BUTTON_WHITE_LIST: "Biała lista"
BUTTON_SIEVE_CONFIGURATION: "Konfiguracja sieve"
@@ -223,12 +224,12 @@ pl_PL:
BUTTON_CLOSE: "Zamknij"
BUTTON_ADD: "Dodaj"
BUTTON_UPDATE: "Zaktualizuj"
- NEW_DOMAIN_DESC: "Konfiguracja tej domeny pozwala na pracę z adresami email: %NAME% "
+ NEW_DOMAIN_DESC: "Konfiguracja tej domeny pozwala na pracę z adresami e-mail: %NAME% "
WHITE_LIST_ALERT: |
- Lista użytkowników domeny, którzy mogą uzyskać dostęp poprzez tego klienta.
+ Lista użytkowników domeny, którzy mogą uzyskać dostęp z tego webmaila.
Użyj spacji do rozdzielenia.
POPUPS_PLUGIN:
- TITLE_PLUGIN: "Wtyczka: "
+ TITLE_PLUGIN: "Wtyczka"
DESC_NOTHING_TO_CONFIGURE: "Brak opcji do skonfigurowania"
BUTTON_CLOSE: "Zamknij"
BUTTON_SAVE: "Zapisz"
@@ -239,7 +240,7 @@ pl_PL:
TITLE_LANGUAGES: "Wybierz swój język"
HINTS:
BETA: "Beta"
- UNSTABLE: "Niestabilna"
+ UNSTABLE: "Niestabilne"
WARNING: "Ostrzeżenie!"
NOT_SUPPORTED: "nieobsługiwana"
REQUIRES_PHP_54: "Wymaga PHP w wersji 5.4 lub wyższej"
@@ -247,32 +248,32 @@ pl_PL:
DOMAIN_ALREADY_EXISTS: "Ta domena już istnieje"
UNKNOWN_ERROR: "Nieznany błąd"
NOTIFICATIONS:
- INVALID_TOKEN: "Nieważny token"
+ INVALID_TOKEN: "Nieprawidłowy token"
AUTH_ERROR: "Autoryzacja zakończona niepowodzeniem"
ACCESS_ERROR: "Błąd dostępu"
CONNECTION_ERROR: "Nie można połączyć się z serwerem"
CAPTCHA_ERROR: "Niepoprawny kod CAPTCHA."
- SOCIAL_FACEBOOK_LOGIN_ACCESS_DISABLE: >-
- Logowanie poprzez tą platformę, nie zostało jeszcze aktywowane dla żadnego
+ SOCIAL_FACEBOOK_LOGIN_ACCESS_DISABLE: >
+ Logowanie poprzez tą platformę nie zostało jeszcze aktywowane dla żadnego
z kont e-mail. Zaloguj się używając loginu i hasła, a następnie włącz tą funkcję
w ustawieniach konta.
- SOCIAL_TWITTER_LOGIN_ACCESS_DISABLE: >-
- Logowanie poprzez tą platformę, nie zostało jeszcze aktywowane dla żadnego
+ SOCIAL_TWITTER_LOGIN_ACCESS_DISABLE: >
+ Logowanie poprzez tą platformę nie zostało jeszcze aktywowane dla żadnego
z kont e-mail. Zaloguj się używając loginu i hasła, a następnie włącz tą funkcję
w ustawieniach konta.
- SOCIAL_GOOGLE_LOGIN_ACCESS_DISABLE: >-
- Logowanie poprzez tą platformę, nie zostało jeszcze aktywowane dla żadnego
+ SOCIAL_GOOGLE_LOGIN_ACCESS_DISABLE: >
+ Logowanie poprzez tą platformę nie zostało jeszcze aktywowane dla żadnego
z kont e-mail. Zaloguj się używając loginu i hasła, a następnie włącz tą funkcję
w ustawieniach konta.
- DOMAIN_NOT_ALLOWED: "Brak zezwolenia na użycie tej domeny"
- ACCOUNT_NOT_ALLOWED: "Brak zezwolenia dla tego konta"
- ACCOUNT_TWO_FACTOR_AUTH_REQUIRED: "Wymagana dwuskładnikowa autoryzacja"
- ACCOUNT_TWO_FACTOR_AUTH_ERROR: "Błąd autoryzacji dwuskładnikowej"
+ DOMAIN_NOT_ALLOWED: "Domena niedozwolona"
+ ACCOUNT_NOT_ALLOWED: "Konto jest niedozwolone"
+ ACCOUNT_TWO_FACTOR_AUTH_REQUIRED: "Wymagana autoryzacja dwuetapowa"
+ ACCOUNT_TWO_FACTOR_AUTH_ERROR: "Błąd autoryzacji dwuetapowej"
COULD_NOT_SAVE_NEW_PASSWORD: "Nie można było zapisać nowego hasła"
CURRENT_PASSWORD_INCORRECT: "Bieżące hasło jest niepoprawne"
NEW_PASSWORD_SHORT: "Wybrane hasło jest za krótkie"
NEW_PASSWORD_WEAK: "Wybrane hasło jest zbyt proste"
- NEW_PASSWORD_FORBIDDENT: "Wybrane hasło zawiera zakazane znaki"
+ NEW_PASSWORD_FORBIDDENT: "Wybrane hasło zawiera niedozwolone znaki"
CONTACTS_SYNC_ERROR: "Błąd synchronizacji kontaktów"
CANT_GET_MESSAGE_LIST: "Nie można pobrać listy wiadomości"
CANT_GET_MESSAGE: "Nie można pobrać wiadomości"
@@ -309,17 +310,17 @@ pl_PL:
UNKNOWN_ERROR: "Nieznany błąd"
STATIC:
BACK_LINK: "Odśwież"
- DOMAIN_LIST_DESC: "Lista domen, do których można uzyskać dostęp za pomocą tego klienta."
+ DOMAIN_LIST_DESC: "Lista domen, do których można uzyskać dostęp za pomocą tego webmaila."
PHP_EXSTENSIONS_ERROR_DESC: "Brak wymaganych rozszerzeń w konfiguracji PHP!"
- PHP_VERSION_ERROR_DESC: "Twoja wersja PHP: (%VERSION%), jest niższa niż minimalna: 5.3.0!"
- NO_SCRIPT_TITLE: "Ta aplikacja do poprawnej pracy wymaga javascript-u."
+ PHP_VERSION_ERROR_DESC: "Twoja wersja PHP (%VERSION%) jest niższa niż minimalna: 5.3.0!"
+ NO_SCRIPT_TITLE: "Ta aplikacja do poprawnej pracy wymaga JavaScript."
NO_SCRIPT_DESC: |
- Twoja przeglądarka nie obsługuje javascript-u.
- Proszę o jego włączenie i ponowną próbę.
+ Twoja przeglądarka nie obsługuje JavaScript.
+ Włącz obsługę JavaScript i spróbuj ponownie.
NO_COOKIE_TITLE: "Obsługa plików cookies jest wymagana dla poprawnego działania skryptu."
NO_COOKIE_DESC: |
Twoja przeglądarka nie obsługuje plików cookies.
- Proszę o ich włączenie i ponowną próbę.
+ Włącz obsługę cookies i spróbuj ponownie.
BAD_BROWSER_TITLE: "Posiadasz nieaktualną wersję przeglądarki."
BAD_BROWSER_DESC: |
W celu wykorzystania wszystkich funkcji tej aplikacji,
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/pt_BR.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/pt_BR.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/pt_BR.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/pt_BR.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/ru_RU.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/ru_RU.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/ru_RU.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/ru_RU.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/sk_SK.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/sk_SK.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/sk_SK.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/sk_SK.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/sl_SI.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/sl_SI.yml
similarity index 98%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/sl_SI.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/sl_SI.yml
index 13ef86afa7d8530ab75df65d775cbbc42fda43ce..f205a22b86e25b1b9d433c2344403732d0633404 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/sl_SI.yml
+++ b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/sl_SI.yml
@@ -34,6 +34,7 @@ sl_SI:
LABEL_ALLOW_ADDITIONAL_ACCOUNTS: "Dovoli dodatne račune"
LABEL_ALLOW_IDENTITIES: "Dovoli več identitet"
LABEL_ALLOW_TEMPLATES: "Dovoli predloge"
+ ALERT_DATA_ACCESS: "Mapa z RainLoop podatki je prosto ogledljiva. Prosimo, nastavite strežnik, da skrije mapo pred zunanjimi dostopi. Preberite več tukaj:"
ALERT_WARNING: "Pozor!"
HTML_ALERT_WEAK_PASSWORD: |
V uporabi je privzeto geslo administratorja
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/sv_SE.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/sv_SE.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/sv_SE.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/sv_SE.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/admin/zh_CN.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/admin/zh_CN.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/admin/zh_CN.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/admin/zh_CN.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/langs.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/langs.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/langs.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/langs.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/af.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/af.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/af.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/af.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/ar-dz.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-dz.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/ar-dz.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-dz.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/ar-kw.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-kw.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/ar-kw.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-kw.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/ar-ly.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-ly.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/ar-ly.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-ly.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/ar-ma.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-ma.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/ar-ma.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-ma.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/ar-sa.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-sa.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/ar-sa.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-sa.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/ar-tn.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-tn.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/ar-tn.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar-tn.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/ar.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/ar.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/ar.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/az.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/az.js
similarity index 98%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/az.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/az.js
index 04930726ba481c820356b26c3d0d0c3be1e23adb..578b70c557ce86b6a06b48b277fe3ae4f076f955 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/az.js
+++ b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/az.js
@@ -55,7 +55,7 @@
relativeTime : {
future : '%s sonra',
past : '%s əvvəl',
- s : 'birneçə saniyyə',
+ s : 'birneçə saniyə',
ss : '%d saniyə',
m : 'bir dəqiqə',
mm : '%d dəqiqə',
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/be.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/be.js
similarity index 98%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/be.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/be.js
index 46a2a11f85a2d2936d6b502dcddbe790c677f218..db7a3c7633aedde02d013622849c0c5e05c1c37f 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/be.js
+++ b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/be.js
@@ -41,7 +41,7 @@
weekdays : {
format: 'нядзелю_панядзелак_аўторак_сераду_чацвер_пятніцу_суботу'.split('_'),
standalone: 'нядзеля_панядзелак_аўторак_серада_чацвер_пятніца_субота'.split('_'),
- isFormat: /\[ ?[Вв] ?(?:мінулую|наступную)? ?\] ?dddd/
+ isFormat: /\[ ?[Ууў] ?(?:мінулую|наступную)? ?\] ?dddd/
},
weekdaysShort : 'нд_пн_ат_ср_чц_пт_сб'.split('_'),
weekdaysMin : 'нд_пн_ат_ср_чц_пт_сб'.split('_'),
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/bg.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/bg.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/bg.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/bg.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/bm.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/bm.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/bm.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/bm.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/bn.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/bn.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/bn.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/bn.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/bo.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/bo.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/bo.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/bo.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/br.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/br.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/br.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/br.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/bs.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/bs.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/bs.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/bs.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/ca.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ca.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/ca.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/ca.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/cs.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/cs.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/cs.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/cs.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/cv.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/cv.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/cv.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/cv.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/cy.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/cy.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/cy.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/cy.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/da.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/da.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/da.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/da.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/de-at.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/de-at.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/de-at.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/de-at.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/de-ch.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/de-ch.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/de-ch.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/de-ch.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/de.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/de.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/de.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/de.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/dv.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/dv.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/dv.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/dv.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/el.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/el.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/el.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/el.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/en-au.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-au.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/en-au.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-au.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/en-ca.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-ca.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/en-ca.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-ca.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/en-gb.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-gb.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/en-gb.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-gb.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/en-ie.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-ie.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/en-ie.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-ie.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/en-il.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-il.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/en-il.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-il.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/en-nz.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-nz.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/en-nz.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/en-nz.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/eo.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/eo.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/eo.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/eo.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/es-do.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/es-do.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/es-do.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/es-do.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/es-us.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/es-us.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/es-us.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/es-us.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/es.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/es.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/es.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/es.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/et.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/et.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/et.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/et.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/eu.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/eu.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/eu.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/eu.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/fa.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/fa.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/fa.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/fa.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/fi.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/fi.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/fi.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/fi.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/fo.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/fo.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/fo.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/fo.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/fr-ca.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/fr-ca.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/fr-ca.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/fr-ca.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/fr-ch.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/fr-ch.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/fr-ch.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/fr-ch.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/fr.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/fr.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/fr.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/fr.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/fy.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/fy.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/fy.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/fy.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/gd.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/gd.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/gd.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/gd.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/gl.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/gl.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/gl.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/gl.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/gom-latn.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/gom-latn.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/gom-latn.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/gom-latn.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/gu.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/gu.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/gu.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/gu.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/he.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/he.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/he.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/he.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/hi.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/hi.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/hi.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/hi.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/hr.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/hr.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/hr.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/hr.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/hu.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/hu.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/hu.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/hu.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/hy-am.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/hy-am.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/hy-am.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/hy-am.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/id.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/id.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/id.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/id.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/is.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/is.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/is.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/is.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/it.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/it.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/it.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/it.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/ja.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ja.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/ja.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/ja.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/jv.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/jv.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/jv.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/jv.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/ka.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ka.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/ka.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/ka.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/kk.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/kk.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/kk.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/kk.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/km.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/km.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/km.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/km.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/kn.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/kn.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/kn.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/kn.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/ko.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ko.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/ko.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/ko.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/ky.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ky.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/ky.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/ky.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/lb.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/lb.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/lb.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/lb.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/lo.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/lo.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/lo.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/lo.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/lt.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/lt.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/lt.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/lt.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/lv.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/lv.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/lv.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/lv.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/me.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/me.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/me.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/me.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/mi.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/mi.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/mi.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/mi.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/mk.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/mk.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/mk.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/mk.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/ml.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ml.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/ml.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/ml.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/mn.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/mn.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/mn.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/mn.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/mr.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/mr.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/mr.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/mr.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/ms-my.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ms-my.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/ms-my.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/ms-my.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/ms.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ms.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/ms.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/ms.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/mt.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/mt.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/mt.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/mt.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/my.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/my.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/my.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/my.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/nb.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/nb.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/nb.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/nb.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/ne.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ne.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/ne.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/ne.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/nl-be.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/nl-be.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/nl-be.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/nl-be.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/nl.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/nl.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/nl.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/nl.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/nn.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/nn.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/nn.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/nn.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/pa-in.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/pa-in.js
similarity index 98%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/pa-in.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/pa-in.js
index f17b8dd9ba07c849ca9dc14ad0ba4150878457ae..63f4f44ea304017b48e25a67e678c78a9b06736b 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/pa-in.js
+++ b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/pa-in.js
@@ -51,7 +51,7 @@
calendar : {
sameDay : '[ਅਜ] LT',
nextDay : '[ਕਲ] LT',
- nextWeek : 'dddd, LT',
+ nextWeek : '[ਅਗਲਾ] dddd, LT',
lastDay : '[ਕਲ] LT',
lastWeek : '[ਪਿਛਲੇ] dddd, LT',
sameElse : 'L'
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/pl.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/pl.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/pl.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/pl.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/pt-br.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/pt-br.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/pt-br.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/pt-br.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/pt.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/pt.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/pt.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/pt.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/ro.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ro.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/ro.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/ro.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/ru.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ru.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/ru.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/ru.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/sd.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/sd.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/sd.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/sd.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/se.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/se.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/se.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/se.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/si.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/si.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/si.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/si.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/sk.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/sk.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/sk.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/sk.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/sl.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/sl.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/sl.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/sl.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/sq.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/sq.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/sq.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/sq.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/sr-cyrl.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/sr-cyrl.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/sr-cyrl.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/sr-cyrl.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/sr.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/sr.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/sr.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/sr.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/ss.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ss.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/ss.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/ss.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/sv.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/sv.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/sv.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/sv.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/sw.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/sw.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/sw.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/sw.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/ta.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ta.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/ta.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/ta.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/te.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/te.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/te.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/te.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/tet.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/tet.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/tet.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/tet.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/tg.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/tg.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/tg.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/tg.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/th.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/th.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/th.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/th.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/tl-ph.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/tl-ph.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/tl-ph.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/tl-ph.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/tlh.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/tlh.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/tlh.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/tlh.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/tr.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/tr.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/tr.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/tr.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/tzl.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/tzl.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/tzl.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/tzl.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/tzm-latn.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/tzm-latn.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/tzm-latn.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/tzm-latn.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/tzm.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/tzm.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/tzm.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/tzm.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/ug-cn.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ug-cn.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/ug-cn.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/ug-cn.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/uk.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/uk.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/uk.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/uk.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/ur.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/ur.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/ur.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/ur.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/uz-latn.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/uz-latn.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/uz-latn.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/uz-latn.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/uz.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/uz.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/uz.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/uz.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/vi.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/vi.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/vi.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/vi.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/x-pseudo.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/x-pseudo.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/x-pseudo.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/x-pseudo.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/yo.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/yo.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/yo.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/yo.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/zh-cn.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/zh-cn.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/zh-cn.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/zh-cn.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/zh-hk.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/zh-hk.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/zh-hk.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/zh-hk.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/moment/zh-tw.js b/rainloop/app/rainloop/v/1.12.1/app/localization/moment/zh-tw.js
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/moment/zh-tw.js
rename to rainloop/app/rainloop/v/1.12.1/app/localization/moment/zh-tw.js
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/README b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/README
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/README
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/README
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/_source.en.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/_source.en.yml
similarity index 97%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/_source.en.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/_source.en.yml
index f4f17c6092f93012db7ba2c2a40c5a6e36b95328..6cb01cb9095ab437b93bb375aa479ec21286dfc7 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/_source.en.yml
+++ b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/_source.en.yml
@@ -1,400 +1,400 @@
-en:
- LOGIN:
- LABEL_EMAIL: "Email"
- LABEL_LOGIN: "Login"
- LABEL_PASSWORD: "Password"
- LABEL_SIGN_ME: "Remember Me"
- LABEL_VERIFICATION_CODE: "Verification Code"
- LABEL_DONT_ASK_VERIFICATION_CODE: "Don't ask for the code for 2 weeks"
- BUTTON_SIGN_IN: "Sign In"
- TITLE_SIGN_IN_GOOGLE: "Sign In using Google"
- TITLE_SIGN_IN_FACEBOOK: "Sign In using Facebook"
- TITLE_SIGN_IN_TWITTER: "Sign In using Twitter"
- LABEL_FORGOT_PASSWORD: "Forgot password"
- LABEL_REGISTRATION: "Registration"
- TOP_TOOLBAR:
- BUTTON_ADD_ACCOUNT: "Add Account"
- BUTTON_SETTINGS: "Settings"
- BUTTON_HELP: "Help"
- BUTTON_LOGOUT: "Logout"
- MOBILE:
- BUTTON_MOBILE_VERSION: "Mobile version"
- BUTTON_DESKTOP_VERSION: "Desktop version"
- SEARCH:
- MAIN_INPUT_PLACEHOLDER: "Search"
- TITLE_ADV: "Advanced Search"
- LABEL_ADV_FROM: "From"
- LABEL_ADV_TO: "To"
- LABEL_ADV_SUBJECT: "Subject"
- LABEL_ADV_TEXT: "Text"
- LABEL_ADV_HAS_ATTACHMENT: "Has attachment"
- LABEL_ADV_HAS_ATTACHMENTS: "Has attachments"
- LABEL_ADV_FLAGGED: "Flagged"
- LABEL_ADV_UNSEEN: "Unseen"
- LABEL_ADV_DATE: "Date"
- LABEL_ADV_DATE_ALL: "All"
- LABEL_ADV_DATE_3_DAYS: "Up to 3 days old"
- LABEL_ADV_DATE_7_DAYS: "Up to 1 week old"
- LABEL_ADV_DATE_MONTH: "Up to 1 month old"
- LABEL_ADV_DATE_3_MONTHS: "Up to 3 months old"
- LABEL_ADV_DATE_6_MONTHS: "Up to 6 months old"
- LABEL_ADV_DATE_YEAR: "Up to 1 year old"
- BUTTON_ADV_SEARCH: "Search"
- PREVIEW_POPUP:
- FULLSCREEN: "Toggle fullscreen"
- ZOOM: "Zoom in/out"
- CLOSE: "Close (Esc)"
- LOADING: "Loading..."
- GALLERY_PREV: "Previous (arrow left)"
- GALLERY_NEXT: "Next (arrow right)"
- GALLERY_COUNTER: "%curr% of %total%"
- IMAGE_ERROR: "The image could not be loaded."
- AJAX_ERROR: "The content could not be loaded."
- FOLDER_LIST:
- BUTTON_COMPOSE: "Compose"
- BUTTON_CONTACTS: "Contacts"
- BUTTON_NEW_MESSAGE: "New message"
- INBOX_NAME: "Inbox"
- SENT_NAME: "Sent"
- DRAFTS_NAME: "Drafts"
- SPAM_NAME: "Spam"
- TRASH_NAME: "Trash"
- ARCHIVE_NAME: "Archive"
- QUOTA:
- TITLE: "Quota usage"
- MESSAGE_LIST:
- BUTTON_RELOAD: "Reload Message List"
- BUTTON_MOVE_TO: "Move To"
- BUTTON_DELETE: "Delete"
- BUTTON_ARCHIVE: "Archive"
- BUTTON_SPAM: "Spam"
- BUTTON_NOT_SPAM: "Not Spam"
- BUTTON_EMPTY_FOLDER: "Clear Folder"
- BUTTON_MULTY_FORWARD: "Forward as attachment(s)"
- BUTTON_DELETE_WITHOUT_MOVE: "Delete permanently"
- BUTTON_MORE: "More"
- MENU_SET_SEEN: "Mark as read"
- MENU_SET_ALL_SEEN: "Mark all as read"
- MENU_UNSET_SEEN: "Mark as unread"
- MENU_SET_FLAG: "Flag"
- MENU_UNSET_FLAG: "Unflag"
- MENU_SELECT_ALL: "All"
- MENU_SELECT_NONE: "None"
- MENU_SELECT_INVERT: "Invert"
- MENU_SELECT_UNSEEN: "Unread"
- MENU_SELECT_SEEN: "Read"
- MENU_SELECT_FLAGGED: "Flagged"
- MENU_SELECT_UNFLAGGED: "Unflagged"
- EMPTY_LIST: "Empty list."
- EMPTY_SEARCH_LIST: "No messages matched your search."
- SEARCH_RESULT_FOR: "Search results for \"%SEARCH%\""
- BACK_TO_MESSAGE_LIST: "back to message list"
- LIST_LOADING: "Loading"
- EMPTY_SUBJECT_TEXT: "(No subject)"
- PUT_MESSAGE_HERE: "Drop message here to view it in the list"
- TODAY_AT: "today at %TIME%"
- YESTERDAY_AT: "yesterday at %TIME%"
- SEARCH_PLACEHOLDER: "Search"
- NEW_MESSAGE_NOTIFICATION: "You have %COUNT% new messages!"
- QUOTA_SIZE: "Using %SIZE% (%PROC%%) of your %LIMIT% "
- MESSAGE:
- BUTTON_EDIT: "Edit"
- BUTTON_BACK: "Back"
- BUTTON_CLOSE: "Close"
- BUTTON_DELETE: "Delete"
- BUTTON_UNSUBSCRIBE: "Unsubscribe from this list"
- BUTTON_ARCHIVE: "Archive"
- BUTTON_SPAM: "Spam"
- BUTTON_NOT_SPAM: "Not Spam"
- BUTTON_MOVE_TO: "Move To"
- BUTTON_MORE: "More"
- BUTTON_REPLY: "Reply"
- BUTTON_REPLY_ALL: "Reply All"
- BUTTON_FORWARD: "Forward"
- BUTTON_FORWARD_AS_ATTACHMENT: "Forward as attachment"
- BUTTON_EDIT_AS_NEW: "Edit as New"
- BUTTON_SHOW_IMAGES: "Display external images"
- BUTTON_NOTIFY_READ_RECEIPT: "The sender has asked to be notified when you read this message."
- BUTTON_IN_NEW_WINDOW: "View in separate window"
- BUTTON_THREAD_LIST: "Thread list"
- BUTTON_THREAD_PREV: "Previous"
- BUTTON_THREAD_NEXT: "Next"
- BUTTON_THREAD_MORE: "More messages"
- MENU_HEADERS: "Show message headers"
- MENU_VIEW_ORIGINAL: "Show Source"
- MENU_DOWNLOAD_ORIGINAL: "Download as .eml file"
- MENU_FILTER_SIMILAR: "Filter messages like this"
- MENU_PRINT: "Print"
- EMPTY_SUBJECT_TEXT: "(No subject)"
- LABEL_SUBJECT: "Subject"
- LABEL_DATE: "Date"
- LABEL_FROM: "From"
- LABEL_FROM_SHORT: "from"
- LABEL_TO: "To"
- LABEL_TO_SHORT: "to"
- LABEL_CC: "CC"
- LABEL_BCC: "BCC"
- LABEL_REPLY_TO: "Reply-To"
- PRINT_LABEL_FROM: "From"
- PRINT_LABEL_TO: "To"
- PRINT_LABEL_CC: "CC"
- PRINT_LABEL_BCC: "BCC"
- PRINT_LABEL_REPLY_TO: "Reply-To"
- PRINT_LABEL_DATE: "Date"
- PRINT_LABEL_SUBJECT: "Subject"
- PRINT_LABEL_ATTACHMENTS: "Attachments"
- MESSAGE_LOADING: "Loading"
- MESSAGE_VIEW_DESC: "Select any message in the list to view it here."
- MESSAGE_VIEW_MOVE_DESC: "Click folder name in the left panel to select the destination."
- PGP_PASSWORD_INPUT_PLACEHOLDER: "Password"
- PGP_SIGNED_MESSAGE_DESC: "OpenPGP signed message (click to verify)"
- PGP_ENCRYPTED_MESSAGE_DESC: "OpenPGP encrypted message (click to decrypt)"
- LINK_DOWNLOAD_AS_ZIP: "Download as zip"
- LINK_SAVE_TO_OWNCLOUD: "Save to ownCloud"
- LINK_SAVE_TO_CLOUD: "Save to Cloud"
- LINK_SAVE_TO_DROPBOX: "Save to Dropbox"
- READ_RECEIPT:
- SUBJECT: "Return Receipt (displayed) - %SUBJECT%"
+en:
+ LOGIN:
+ LABEL_EMAIL: "Email"
+ LABEL_LOGIN: "Login"
+ LABEL_PASSWORD: "Password"
+ LABEL_SIGN_ME: "Remember Me"
+ LABEL_VERIFICATION_CODE: "Verification Code"
+ LABEL_DONT_ASK_VERIFICATION_CODE: "Don't ask for the code for 2 weeks"
+ BUTTON_SIGN_IN: "Sign In"
+ TITLE_SIGN_IN_GOOGLE: "Sign In using Google"
+ TITLE_SIGN_IN_FACEBOOK: "Sign In using Facebook"
+ TITLE_SIGN_IN_TWITTER: "Sign In using Twitter"
+ LABEL_FORGOT_PASSWORD: "Forgot password"
+ LABEL_REGISTRATION: "Registration"
+ TOP_TOOLBAR:
+ BUTTON_ADD_ACCOUNT: "Add Account"
+ BUTTON_SETTINGS: "Settings"
+ BUTTON_HELP: "Help"
+ BUTTON_LOGOUT: "Logout"
+ MOBILE:
+ BUTTON_MOBILE_VERSION: "Mobile version"
+ BUTTON_DESKTOP_VERSION: "Desktop version"
+ SEARCH:
+ MAIN_INPUT_PLACEHOLDER: "Search"
+ TITLE_ADV: "Advanced Search"
+ LABEL_ADV_FROM: "From"
+ LABEL_ADV_TO: "To"
+ LABEL_ADV_SUBJECT: "Subject"
+ LABEL_ADV_TEXT: "Text"
+ LABEL_ADV_HAS_ATTACHMENT: "Has attachment"
+ LABEL_ADV_HAS_ATTACHMENTS: "Has attachments"
+ LABEL_ADV_FLAGGED: "Flagged"
+ LABEL_ADV_UNSEEN: "Unseen"
+ LABEL_ADV_DATE: "Date"
+ LABEL_ADV_DATE_ALL: "All"
+ LABEL_ADV_DATE_3_DAYS: "Up to 3 days old"
+ LABEL_ADV_DATE_7_DAYS: "Up to 1 week old"
+ LABEL_ADV_DATE_MONTH: "Up to 1 month old"
+ LABEL_ADV_DATE_3_MONTHS: "Up to 3 months old"
+ LABEL_ADV_DATE_6_MONTHS: "Up to 6 months old"
+ LABEL_ADV_DATE_YEAR: "Up to 1 year old"
+ BUTTON_ADV_SEARCH: "Search"
+ PREVIEW_POPUP:
+ FULLSCREEN: "Toggle fullscreen"
+ ZOOM: "Zoom in/out"
+ CLOSE: "Close (Esc)"
+ LOADING: "Loading..."
+ GALLERY_PREV: "Previous (arrow left)"
+ GALLERY_NEXT: "Next (arrow right)"
+ GALLERY_COUNTER: "%curr% of %total%"
+ IMAGE_ERROR: "The image could not be loaded."
+ AJAX_ERROR: "The content could not be loaded."
+ FOLDER_LIST:
+ BUTTON_COMPOSE: "Compose"
+ BUTTON_CONTACTS: "Contacts"
+ BUTTON_NEW_MESSAGE: "New message"
+ INBOX_NAME: "Inbox"
+ SENT_NAME: "Sent"
+ DRAFTS_NAME: "Drafts"
+ SPAM_NAME: "Spam"
+ TRASH_NAME: "Trash"
+ ARCHIVE_NAME: "Archive"
+ QUOTA:
+ TITLE: "Quota usage"
+ MESSAGE_LIST:
+ BUTTON_RELOAD: "Reload Message List"
+ BUTTON_MOVE_TO: "Move To"
+ BUTTON_DELETE: "Delete"
+ BUTTON_ARCHIVE: "Archive"
+ BUTTON_SPAM: "Spam"
+ BUTTON_NOT_SPAM: "Not Spam"
+ BUTTON_EMPTY_FOLDER: "Clear Folder"
+ BUTTON_MULTY_FORWARD: "Forward as attachment(s)"
+ BUTTON_DELETE_WITHOUT_MOVE: "Delete permanently"
+ BUTTON_MORE: "More"
+ MENU_SET_SEEN: "Mark as read"
+ MENU_SET_ALL_SEEN: "Mark all as read"
+ MENU_UNSET_SEEN: "Mark as unread"
+ MENU_SET_FLAG: "Flag"
+ MENU_UNSET_FLAG: "Unflag"
+ MENU_SELECT_ALL: "All"
+ MENU_SELECT_NONE: "None"
+ MENU_SELECT_INVERT: "Invert"
+ MENU_SELECT_UNSEEN: "Unread"
+ MENU_SELECT_SEEN: "Read"
+ MENU_SELECT_FLAGGED: "Flagged"
+ MENU_SELECT_UNFLAGGED: "Unflagged"
+ EMPTY_LIST: "Empty list."
+ EMPTY_SEARCH_LIST: "No messages matched your search."
+ SEARCH_RESULT_FOR: "Search results for \"%SEARCH%\""
+ BACK_TO_MESSAGE_LIST: "back to message list"
+ LIST_LOADING: "Loading"
+ EMPTY_SUBJECT_TEXT: "(No subject)"
+ PUT_MESSAGE_HERE: "Drop message here to view it in the list"
+ TODAY_AT: "today at %TIME%"
+ YESTERDAY_AT: "yesterday at %TIME%"
+ SEARCH_PLACEHOLDER: "Search"
+ NEW_MESSAGE_NOTIFICATION: "You have %COUNT% new messages!"
+ QUOTA_SIZE: "Using %SIZE% (%PROC%%) of your %LIMIT% "
+ MESSAGE:
+ BUTTON_EDIT: "Edit"
+ BUTTON_BACK: "Back"
+ BUTTON_CLOSE: "Close"
+ BUTTON_DELETE: "Delete"
+ BUTTON_UNSUBSCRIBE: "Unsubscribe from this list"
+ BUTTON_ARCHIVE: "Archive"
+ BUTTON_SPAM: "Spam"
+ BUTTON_NOT_SPAM: "Not Spam"
+ BUTTON_MOVE_TO: "Move To"
+ BUTTON_MORE: "More"
+ BUTTON_REPLY: "Reply"
+ BUTTON_REPLY_ALL: "Reply All"
+ BUTTON_FORWARD: "Forward"
+ BUTTON_FORWARD_AS_ATTACHMENT: "Forward as attachment"
+ BUTTON_EDIT_AS_NEW: "Edit as New"
+ BUTTON_SHOW_IMAGES: "Display external images"
+ BUTTON_NOTIFY_READ_RECEIPT: "The sender has asked to be notified when you read this message."
+ BUTTON_IN_NEW_WINDOW: "View in separate window"
+ BUTTON_THREAD_LIST: "Thread list"
+ BUTTON_THREAD_PREV: "Previous"
+ BUTTON_THREAD_NEXT: "Next"
+ BUTTON_THREAD_MORE: "More messages"
+ MENU_HEADERS: "Show message headers"
+ MENU_VIEW_ORIGINAL: "Show Source"
+ MENU_DOWNLOAD_ORIGINAL: "Download as .eml file"
+ MENU_FILTER_SIMILAR: "Filter messages like this"
+ MENU_PRINT: "Print"
+ EMPTY_SUBJECT_TEXT: "(No subject)"
+ LABEL_SUBJECT: "Subject"
+ LABEL_DATE: "Date"
+ LABEL_FROM: "From"
+ LABEL_FROM_SHORT: "from"
+ LABEL_TO: "To"
+ LABEL_TO_SHORT: "to"
+ LABEL_CC: "CC"
+ LABEL_BCC: "BCC"
+ LABEL_REPLY_TO: "Reply-To"
+ PRINT_LABEL_FROM: "From"
+ PRINT_LABEL_TO: "To"
+ PRINT_LABEL_CC: "CC"
+ PRINT_LABEL_BCC: "BCC"
+ PRINT_LABEL_REPLY_TO: "Reply-To"
+ PRINT_LABEL_DATE: "Date"
+ PRINT_LABEL_SUBJECT: "Subject"
+ PRINT_LABEL_ATTACHMENTS: "Attachments"
+ MESSAGE_LOADING: "Loading"
+ MESSAGE_VIEW_DESC: "Select any message in the list to view it here."
+ MESSAGE_VIEW_MOVE_DESC: "Click folder name in the left panel to select the destination."
+ PGP_PASSWORD_INPUT_PLACEHOLDER: "Password"
+ PGP_SIGNED_MESSAGE_DESC: "OpenPGP signed message (click to verify)"
+ PGP_ENCRYPTED_MESSAGE_DESC: "OpenPGP encrypted message (click to decrypt)"
+ LINK_DOWNLOAD_AS_ZIP: "Download as zip"
+ LINK_SAVE_TO_OWNCLOUD: "Save to ownCloud"
+ LINK_SAVE_TO_CLOUD: "Save to Cloud"
+ LINK_SAVE_TO_DROPBOX: "Save to Dropbox"
+ READ_RECEIPT:
+ SUBJECT: "Return Receipt (displayed) - %SUBJECT%"
BODY: |
This is a Return Receipt for the mail that you sent to %READ-RECEIPT%.
Note: "This Return Receipt only acknowledges that the message was displayed on the recipient's computer."
There is no guarantee that the recipient has read or understood the message contents.
- SUGGESTIONS:
- SEARCHING_DESC: "Searching..."
- CONTACTS:
- LEGEND_CONTACTS: "Contacts"
- SEARCH_INPUT_PLACEHOLDER: "Search"
- BUTTON_ADD_CONTACT: "Add Contact"
- BUTTON_CREATE_CONTACT: "Create"
- BUTTON_UPDATE_CONTACT: "Update"
- BUTTON_IMPORT: "Import (csv, vcf, vCard)"
- BUTTON_EXPORT_VCARD: "Export (vcf, vCard)"
- BUTTON_EXPORT_CSV: "Export (csv)"
- ERROR_IMPORT_FILE: "Import error (invalid file format)"
- LIST_LOADING: "Loading"
- EMPTY_LIST: "No contacts here"
- EMPTY_SEARCH: "No contacts found"
- CLEAR_SEARCH: "Clear search"
- CONTACT_VIEW_DESC: "Select contact in the list to view it here."
- LABEL_DISPLAY_NAME: "Display name"
- LABEL_EMAIL: "Email"
- LABEL_PHONE: "Phone"
- LABEL_WEB: "Web"
- LABEL_BIRTHDAY: "Birthday"
- LINK_ADD_EMAIL: "Add an email address"
- LINK_ADD_PHONE: "Add a phone"
- LINK_BIRTHDAY: "Birthday"
- PLACEHOLDER_ENTER_DISPLAY_NAME: "Enter display name"
- PLACEHOLDER_ENTER_LAST_NAME: "Enter last name"
- PLACEHOLDER_ENTER_FIRST_NAME: "Enter first name"
- PLACEHOLDER_ENTER_NICK_NAME: "Enter nickname"
- LABEL_READ_ONLY: "Read only"
- LABEL_SHARE: "Share"
- ADD_MENU_LABEL: "Add"
- ADD_MENU_NICKNAME: "Nickname"
- ADD_MENU_NOTES: "Notes"
- ADD_MENU_EMAIL: "Email"
- ADD_MENU_PHONE: "Phone"
- ADD_MENU_URL: "URL"
- ADD_MENU_ADDRESS: "Address"
- ADD_MENU_BIRTHDAY: "Birthday"
- ADD_MENU_TAGS: "Tags"
- BUTTON_SHARE_NONE: "None"
- BUTTON_SHARE_ALL: "Everyone"
- BUTTON_SYNC: "Synchronization (CardDAV)"
- COMPOSE:
- TITLE_FROM: "From"
- TITLE_TO: "To"
- TITLE_CC: "CC"
- TITLE_BCC: "BCC"
- TITLE_REPLY_TO: "Reply-To"
- TITLE_SUBJECT: "Subject"
- LINK_SHOW_INPUTS: "show all fields"
- BUTTON_SEND: "Send"
- BUTTON_SAVE: "Save"
- BUTTON_DELETE: "Delete"
- BUTTON_CANCEL: "Cancel"
- BUTTON_MINIMIZE: "Minimize"
- SAVED_TIME: "Saved at %TIME%"
- SAVED_ERROR_ON_SEND: "Message was sent but not saved to sent items folder"
- DISCARD_UNSAVED_DATA: "Discard unsaved data?"
- ATTACH_FILES: "Attach files"
- ATTACH_DROP_FILES_DESC: "Drop files here"
- ATTACH_ITEM_CANCEL: "Cancel"
- DROPBOX: "Dropbox"
- GOOGLE_DRIVE: "Google Drive"
- REPLY_MESSAGE_TITLE: "%DATETIME%, %EMAIL% wrote"
- FORWARD_MESSAGE_TOP_TITLE: "-------- Forwarded message -------"
- FORWARD_MESSAGE_TOP_FROM: "From"
- FORWARD_MESSAGE_TOP_TO: "To"
- FORWARD_MESSAGE_TOP_CC: "CC"
- FORWARD_MESSAGE_TOP_SENT: "Sent"
- FORWARD_MESSAGE_TOP_SUBJECT: "Subject"
- EMPTY_TO_ERROR_DESC: "Please specify at least one recipient"
- NO_ATTACHMENTS_HERE_DESC: "No attachments here."
- ATTACHMENTS_ERROR_DESC: "Warning! Not all attachments have been uploaded."
- ATTACHMENTS_UPLOAD_ERROR_DESC: "Not all attachments have been uploaded yet."
- BUTTON_REQUEST_READ_RECEIPT: "Request a read receipt"
- BUTTON_MARK_AS_IMPORTANT: "Mark as important"
- BUTTON_OPEN_PGP: "OpenPGP (Plain Text Only)"
- BUTTON_REQUEST_DSN: "Request a delivery receipt"
- POPUPS_WELCOME_PAGE:
- BUTTON_CLOSE: "Close"
- POPUPS_ASK:
- BUTTON_YES: "Yes"
- BUTTON_NO: "No"
- DESC_WANT_CLOSE_THIS_WINDOW: "Are you sure you want to close this window?"
- DESC_WANT_DELETE_MESSAGES: "Are you sure you want to delete the message(s)?"
- POPUPS_LANGUAGES:
- TITLE_LANGUAGES: "Choose your language"
- POPUPS_ADD_ACCOUNT:
- TITLE_ADD_ACCOUNT: "Add Account?"
- BUTTON_ADD_ACCOUNT: "Add"
- TITLE_UPDATE_ACCOUNT: "Update Account?"
- BUTTON_UPDATE_ACCOUNT: "Update"
- POPUPS_IDENTITY:
- TITLE_ADD_IDENTITY: "Add Identity?"
- TITLE_UPDATE_IDENTITY: "Update Identity?"
- BUTTON_ADD_IDENTITY: "Add"
- BUTTON_UPDATE_IDENTITY: "Update"
- LABEL_EMAIL: "Email"
- LABEL_NAME: "Name"
- LABEL_REPLY_TO: "Reply-To"
- LABEL_SIGNATURE: "Signature"
- LABEL_CC: "Cc"
- LABEL_BCC: "Bcc"
- LABEL_SIGNATURE_INSERT_BEFORE: "Insert this signature before quoted text in replies"
- POPUPS_CREATE_FOLDER:
- TITLE_CREATE_FOLDER: "Create a folder?"
- LABEL_NAME: "Folder name"
- LABEL_PARENT: "Parent folder"
- BUTTON_CREATE: "Create"
- BUTTON_CANCEL: "Cancel"
- BUTTON_CLOSE: "Close"
- TITLE_CREATING_PROCESS: "Creating a folder"
- POPUPS_CLEAR_FOLDER:
- TITLE_CLEAR_FOLDER: "Purge all messages from the folder?"
- BUTTON_CLEAR: "Clear"
- BUTTON_CANCEL: "Cancel"
- BUTTON_CLOSE: "Close"
- DANGER_DESC_WARNING: "Warning!"
- DANGER_DESC_HTML_1: "This action will result in removing all mails from %FOLDER% folder completely."
- DANGER_DESC_HTML_2: "Once started, the process cannot be aborted or cancelled."
- TITLE_CLEARING_PROCESS: "Purging the folder..."
- POPUPS_IMPORT_OPEN_PGP_KEY:
- TITLE_IMPORT_OPEN_PGP_KEY: "Import OpenPGP key"
- BUTTON_IMPORT_OPEN_PGP_KEY: "Import"
- POPUPS_VIEW_OPEN_PGP_KEY:
- TITLE_VIEW_OPEN_PGP_KEY: "View OpenPGP key"
- BUTTON_SELECT: "Select"
- BUTTON_CLOSE: "Close"
- POPUPS_GENERATE_OPEN_PGP_KEYS:
- TITLE_GENERATE_OPEN_PGP_KEYS: "Generate OpenPGP keys"
- LABEL_EMAIL: "Email"
- LABEL_NAME: "Name"
- LABEL_PASSWORD: "Password"
- LABEL_KEY_BIT_LENGTH: "Key length"
- BUTTON_GENERATE_OPEN_PGP_KEYS: "Generate"
- POPUPS_COMPOSE_OPEN_PGP:
- TITLE_COMPOSE_OPEN_PGP: "OpenPGP Sign/Encrypt"
- LABEL_SIGN: "Sign"
- LABEL_ENCRYPT: "Encrypt"
- LABEL_PASSWORD: "Password"
- BUTTON_SIGN: "Sign"
- BUTTON_ENCRYPT: "Encrypt"
- BUTTON_SIGN_AND_ENCRYPT: "Sign and encrypt"
- POPUPS_MESSAGE_OPEN_PGP:
- TITLE_MESSAGE_OPEN_PGP: "OpenPGP Decrypt"
- LABEL_KEY: "Private Key"
- LABEL_PASSWORD: "Password"
- BUTTON_DECRYPT: "Decrypt"
- POPUPS_TWO_FACTOR_TEST:
- TITLE_TEST_CODE: "2-Step verification test"
- LABEL_CODE: "Code"
- BUTTON_TEST: "Test"
- POPUPS_FILTER:
- TITLE_CREATE_FILTER: "Create a filter?"
- TITLE_EDIT_FILTER: "Update filter?"
- FILTER_NAME: "Name"
- LEGEND_CONDITIONS: "Conditions"
- LEGEND_ACTIONS: "Actions"
- BUTTON_DONE: "Done"
- BUTTON_ADD_CONDITION: "Add a Condition"
- SELECT_ACTION_NONE: "None"
- SELECT_ACTION_MOVE_TO: "Move to"
- SELECT_ACTION_FORWARD_TO: "Forward to"
- SELECT_ACTION_REJECT: "Reject"
- SELECT_ACTION_VACATION_MESSAGE: "Vacation message"
- SELECT_ACTION_DISCARD: "Discard"
- SELECT_FIELD_FROM: "From"
- SELECT_FIELD_RECIPIENTS: "Recipients (To or CC)"
- SELECT_FIELD_SUBJECT: "Subject"
- SELECT_FIELD_HEADER: "Header"
- SELECT_FIELD_SIZE: "Size"
- SELECT_TYPE_CONTAINS: "Contains"
- SELECT_TYPE_NOT_CONTAINS: "Not Contains"
- SELECT_TYPE_MATCHES: "Matches (* and ? supported)"
- SELECT_TYPE_NOT_MATCHES: "Not Matches (* and ? supported)"
- SELECT_TYPE_REGEXP: "Regexp"
- SELECT_TYPE_NOT_REGEXP: "Not Regexp"
- SELECT_TYPE_EQUAL_TO: "Equal To"
- SELECT_TYPE_NOT_EQUAL_TO: "Not Equal To"
- SELECT_TYPE_OVER: "Over"
- SELECT_TYPE_UNDER: "Under"
- SELECT_MATCH_ANY: "Matching ANY of the following rules"
- SELECT_MATCH_ALL: "Matching ALL of the following rules"
- MARK_AS_READ_LABEL: "Mark as read"
- REPLY_INTERVAL_LABEL: "Reply interval (days)"
- KEEP_LABEL: "Keep"
- STOP_LABEL: "Don't stop processing rules"
- EMAIL_LABEL: "Email"
- VACATION_SUBJECT_LABEL: "Subject (optional)"
- VACATION_MESSAGE_LABEL: "Message"
- VACATION_RECIPIENTS_LABEL: "Recipients (comma separated)"
- REJECT_MESSAGE_LABEL: "Reject message"
- ALL_INCOMING_MESSAGES_DESC: "All incoming messages"
- POPUPS_SYSTEM_FOLDERS:
- TITLE_SYSTEM_FOLDERS: "Select system folders"
- SELECT_CHOOSE_ONE: "Choose one"
- SELECT_UNUSE_NAME: "Do not use"
- LABEL_SENT: "Sent"
- LABEL_DRAFTS: "Drafts"
- LABEL_SPAM: "Spam"
- LABEL_TRASH: "Trash"
- LABEL_ARCHIVE: "Archive"
- BUTTON_CANCEL: "Cancel"
- BUTTON_CLOSE: "Close"
+ SUGGESTIONS:
+ SEARCHING_DESC: "Searching..."
+ CONTACTS:
+ LEGEND_CONTACTS: "Contacts"
+ SEARCH_INPUT_PLACEHOLDER: "Search"
+ BUTTON_ADD_CONTACT: "Add Contact"
+ BUTTON_CREATE_CONTACT: "Create"
+ BUTTON_UPDATE_CONTACT: "Update"
+ BUTTON_IMPORT: "Import (csv, vcf, vCard)"
+ BUTTON_EXPORT_VCARD: "Export (vcf, vCard)"
+ BUTTON_EXPORT_CSV: "Export (csv)"
+ ERROR_IMPORT_FILE: "Import error (invalid file format)"
+ LIST_LOADING: "Loading"
+ EMPTY_LIST: "No contacts here"
+ EMPTY_SEARCH: "No contacts found"
+ CLEAR_SEARCH: "Clear search"
+ CONTACT_VIEW_DESC: "Select contact in the list to view it here."
+ LABEL_DISPLAY_NAME: "Display name"
+ LABEL_EMAIL: "Email"
+ LABEL_PHONE: "Phone"
+ LABEL_WEB: "Web"
+ LABEL_BIRTHDAY: "Birthday"
+ LINK_ADD_EMAIL: "Add an email address"
+ LINK_ADD_PHONE: "Add a phone"
+ LINK_BIRTHDAY: "Birthday"
+ PLACEHOLDER_ENTER_DISPLAY_NAME: "Enter display name"
+ PLACEHOLDER_ENTER_LAST_NAME: "Enter last name"
+ PLACEHOLDER_ENTER_FIRST_NAME: "Enter first name"
+ PLACEHOLDER_ENTER_NICK_NAME: "Enter nickname"
+ LABEL_READ_ONLY: "Read only"
+ LABEL_SHARE: "Share"
+ ADD_MENU_LABEL: "Add"
+ ADD_MENU_NICKNAME: "Nickname"
+ ADD_MENU_NOTES: "Notes"
+ ADD_MENU_EMAIL: "Email"
+ ADD_MENU_PHONE: "Phone"
+ ADD_MENU_URL: "URL"
+ ADD_MENU_ADDRESS: "Address"
+ ADD_MENU_BIRTHDAY: "Birthday"
+ ADD_MENU_TAGS: "Tags"
+ BUTTON_SHARE_NONE: "None"
+ BUTTON_SHARE_ALL: "Everyone"
+ BUTTON_SYNC: "Synchronization (CardDAV)"
+ COMPOSE:
+ TITLE_FROM: "From"
+ TITLE_TO: "To"
+ TITLE_CC: "CC"
+ TITLE_BCC: "BCC"
+ TITLE_REPLY_TO: "Reply-To"
+ TITLE_SUBJECT: "Subject"
+ LINK_SHOW_INPUTS: "show all fields"
+ BUTTON_SEND: "Send"
+ BUTTON_SAVE: "Save"
+ BUTTON_DELETE: "Delete"
+ BUTTON_CANCEL: "Cancel"
+ BUTTON_MINIMIZE: "Minimize"
+ SAVED_TIME: "Saved at %TIME%"
+ SAVED_ERROR_ON_SEND: "Message was sent but not saved to sent items folder"
+ DISCARD_UNSAVED_DATA: "Discard unsaved data?"
+ ATTACH_FILES: "Attach files"
+ ATTACH_DROP_FILES_DESC: "Drop files here"
+ ATTACH_ITEM_CANCEL: "Cancel"
+ DROPBOX: "Dropbox"
+ GOOGLE_DRIVE: "Google Drive"
+ REPLY_MESSAGE_TITLE: "%DATETIME%, %EMAIL% wrote"
+ FORWARD_MESSAGE_TOP_TITLE: "-------- Forwarded message -------"
+ FORWARD_MESSAGE_TOP_FROM: "From"
+ FORWARD_MESSAGE_TOP_TO: "To"
+ FORWARD_MESSAGE_TOP_CC: "CC"
+ FORWARD_MESSAGE_TOP_SENT: "Sent"
+ FORWARD_MESSAGE_TOP_SUBJECT: "Subject"
+ EMPTY_TO_ERROR_DESC: "Please specify at least one recipient"
+ NO_ATTACHMENTS_HERE_DESC: "No attachments here."
+ ATTACHMENTS_ERROR_DESC: "Warning! Not all attachments have been uploaded."
+ ATTACHMENTS_UPLOAD_ERROR_DESC: "Not all attachments have been uploaded yet."
+ BUTTON_REQUEST_READ_RECEIPT: "Request a read receipt"
+ BUTTON_MARK_AS_IMPORTANT: "Mark as important"
+ BUTTON_OPEN_PGP: "OpenPGP (Plain Text Only)"
+ BUTTON_REQUEST_DSN: "Request a delivery receipt"
+ POPUPS_WELCOME_PAGE:
+ BUTTON_CLOSE: "Close"
+ POPUPS_ASK:
+ BUTTON_YES: "Yes"
+ BUTTON_NO: "No"
+ DESC_WANT_CLOSE_THIS_WINDOW: "Are you sure you want to close this window?"
+ DESC_WANT_DELETE_MESSAGES: "Are you sure you want to delete the message(s)?"
+ POPUPS_LANGUAGES:
+ TITLE_LANGUAGES: "Choose your language"
+ POPUPS_ADD_ACCOUNT:
+ TITLE_ADD_ACCOUNT: "Add Account?"
+ BUTTON_ADD_ACCOUNT: "Add"
+ TITLE_UPDATE_ACCOUNT: "Update Account?"
+ BUTTON_UPDATE_ACCOUNT: "Update"
+ POPUPS_IDENTITY:
+ TITLE_ADD_IDENTITY: "Add Identity?"
+ TITLE_UPDATE_IDENTITY: "Update Identity?"
+ BUTTON_ADD_IDENTITY: "Add"
+ BUTTON_UPDATE_IDENTITY: "Update"
+ LABEL_EMAIL: "Email"
+ LABEL_NAME: "Name"
+ LABEL_REPLY_TO: "Reply-To"
+ LABEL_SIGNATURE: "Signature"
+ LABEL_CC: "Cc"
+ LABEL_BCC: "Bcc"
+ LABEL_SIGNATURE_INSERT_BEFORE: "Insert this signature before quoted text in replies"
+ POPUPS_CREATE_FOLDER:
+ TITLE_CREATE_FOLDER: "Create a folder?"
+ LABEL_NAME: "Folder name"
+ LABEL_PARENT: "Parent folder"
+ BUTTON_CREATE: "Create"
+ BUTTON_CANCEL: "Cancel"
+ BUTTON_CLOSE: "Close"
+ TITLE_CREATING_PROCESS: "Creating a folder"
+ POPUPS_CLEAR_FOLDER:
+ TITLE_CLEAR_FOLDER: "Purge all messages from the folder?"
+ BUTTON_CLEAR: "Clear"
+ BUTTON_CANCEL: "Cancel"
+ BUTTON_CLOSE: "Close"
+ DANGER_DESC_WARNING: "Warning!"
+ DANGER_DESC_HTML_1: "This action will result in removing all mails from %FOLDER% folder completely."
+ DANGER_DESC_HTML_2: "Once started, the process cannot be aborted or cancelled."
+ TITLE_CLEARING_PROCESS: "Purging the folder..."
+ POPUPS_IMPORT_OPEN_PGP_KEY:
+ TITLE_IMPORT_OPEN_PGP_KEY: "Import OpenPGP key"
+ BUTTON_IMPORT_OPEN_PGP_KEY: "Import"
+ POPUPS_VIEW_OPEN_PGP_KEY:
+ TITLE_VIEW_OPEN_PGP_KEY: "View OpenPGP key"
+ BUTTON_SELECT: "Select"
+ BUTTON_CLOSE: "Close"
+ POPUPS_GENERATE_OPEN_PGP_KEYS:
+ TITLE_GENERATE_OPEN_PGP_KEYS: "Generate OpenPGP keys"
+ LABEL_EMAIL: "Email"
+ LABEL_NAME: "Name"
+ LABEL_PASSWORD: "Password"
+ LABEL_KEY_BIT_LENGTH: "Key length"
+ BUTTON_GENERATE_OPEN_PGP_KEYS: "Generate"
+ POPUPS_COMPOSE_OPEN_PGP:
+ TITLE_COMPOSE_OPEN_PGP: "OpenPGP Sign/Encrypt"
+ LABEL_SIGN: "Sign"
+ LABEL_ENCRYPT: "Encrypt"
+ LABEL_PASSWORD: "Password"
+ BUTTON_SIGN: "Sign"
+ BUTTON_ENCRYPT: "Encrypt"
+ BUTTON_SIGN_AND_ENCRYPT: "Sign and encrypt"
+ POPUPS_MESSAGE_OPEN_PGP:
+ TITLE_MESSAGE_OPEN_PGP: "OpenPGP Decrypt"
+ LABEL_KEY: "Private Key"
+ LABEL_PASSWORD: "Password"
+ BUTTON_DECRYPT: "Decrypt"
+ POPUPS_TWO_FACTOR_TEST:
+ TITLE_TEST_CODE: "2-Step verification test"
+ LABEL_CODE: "Code"
+ BUTTON_TEST: "Test"
+ POPUPS_FILTER:
+ TITLE_CREATE_FILTER: "Create a filter?"
+ TITLE_EDIT_FILTER: "Update filter?"
+ FILTER_NAME: "Name"
+ LEGEND_CONDITIONS: "Conditions"
+ LEGEND_ACTIONS: "Actions"
+ BUTTON_DONE: "Done"
+ BUTTON_ADD_CONDITION: "Add a Condition"
+ SELECT_ACTION_NONE: "None"
+ SELECT_ACTION_MOVE_TO: "Move to"
+ SELECT_ACTION_FORWARD_TO: "Forward to"
+ SELECT_ACTION_REJECT: "Reject"
+ SELECT_ACTION_VACATION_MESSAGE: "Vacation message"
+ SELECT_ACTION_DISCARD: "Discard"
+ SELECT_FIELD_FROM: "From"
+ SELECT_FIELD_RECIPIENTS: "Recipients (To or CC)"
+ SELECT_FIELD_SUBJECT: "Subject"
+ SELECT_FIELD_HEADER: "Header"
+ SELECT_FIELD_SIZE: "Size"
+ SELECT_TYPE_CONTAINS: "Contains"
+ SELECT_TYPE_NOT_CONTAINS: "Not Contains"
+ SELECT_TYPE_MATCHES: "Matches (* and ? supported)"
+ SELECT_TYPE_NOT_MATCHES: "Not Matches (* and ? supported)"
+ SELECT_TYPE_REGEXP: "Regexp"
+ SELECT_TYPE_NOT_REGEXP: "Not Regexp"
+ SELECT_TYPE_EQUAL_TO: "Equal To"
+ SELECT_TYPE_NOT_EQUAL_TO: "Not Equal To"
+ SELECT_TYPE_OVER: "Over"
+ SELECT_TYPE_UNDER: "Under"
+ SELECT_MATCH_ANY: "Matching ANY of the following rules"
+ SELECT_MATCH_ALL: "Matching ALL of the following rules"
+ MARK_AS_READ_LABEL: "Mark as read"
+ REPLY_INTERVAL_LABEL: "Reply interval (days)"
+ KEEP_LABEL: "Keep"
+ STOP_LABEL: "Don't stop processing rules"
+ EMAIL_LABEL: "Email"
+ VACATION_SUBJECT_LABEL: "Subject (optional)"
+ VACATION_MESSAGE_LABEL: "Message"
+ VACATION_RECIPIENTS_LABEL: "Recipients (comma separated)"
+ REJECT_MESSAGE_LABEL: "Reject message"
+ ALL_INCOMING_MESSAGES_DESC: "All incoming messages"
+ POPUPS_SYSTEM_FOLDERS:
+ TITLE_SYSTEM_FOLDERS: "Select system folders"
+ SELECT_CHOOSE_ONE: "Choose one"
+ SELECT_UNUSE_NAME: "Do not use"
+ LABEL_SENT: "Sent"
+ LABEL_DRAFTS: "Drafts"
+ LABEL_SPAM: "Spam"
+ LABEL_TRASH: "Trash"
+ LABEL_ARCHIVE: "Archive"
+ BUTTON_CANCEL: "Cancel"
+ BUTTON_CLOSE: "Close"
NOTIFICATION_SENT: |
You haven't selected "Sent" system folder messages are put to after sending.
If you don't want to save sent message, please select "Do not use" option.
- NOTIFICATION_DRAFTS: "You haven't selected \"Drafts\" system folder messages are saved to while composing."
+ NOTIFICATION_DRAFTS: "You haven't selected \"Drafts\" system folder messages are saved to while composing."
NOTIFICATION_SPAM: |
You haven't selected "Spam" system folder spamed messages are placed to.
If you wish to remove messages permanently, please select "Do not use" option.
NOTIFICATION_TRASH: |
You haven't selected "Trash" system folder deleted messages are placed to.
If you wish to remove messages permanently, please select "Do not use" option.
- NOTIFICATION_ARCHIVE: "You haven't selected \"Archive\" system folder achived messages are placed to."
- POPUPS_TWO_FACTOR_CFG:
- LEGEND_TWO_FACTOR_AUTH: "2-Step Verification (TOTP)"
- LABEL_ENABLE_TWO_FACTOR: "Enable 2-Step verification"
- LABEL_TWO_FACTOR_USER: "User"
- LABEL_TWO_FACTOR_STATUS: "Status"
- LABEL_TWO_FACTOR_SECRET: "Secret"
- LABEL_TWO_FACTOR_BACKUP_CODES: "Backup codes"
- BUTTON_CREATE: "Create a secret"
- BUTTON_ACTIVATE: "Activate"
- BUTTON_CLEAR: "Clear"
- BUTTON_LOGOUT: "Logout"
- BUTTON_DONE: "Done"
- BUTTON_TEST: "Test"
- LINK_TEST: "test"
- BUTTON_SHOW_SECRET: "Show Secret"
- BUTTON_HIDE_SECRET: "Hide Secret"
- TWO_FACTOR_REQUIRE_DESC: "Your account requires 2-Step verification configuration."
- TWO_FACTOR_SECRET_CONFIGURED_DESC: "Configured"
- TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC: "Not configured"
+ NOTIFICATION_ARCHIVE: "You haven't selected \"Archive\" system folder achived messages are placed to."
+ POPUPS_TWO_FACTOR_CFG:
+ LEGEND_TWO_FACTOR_AUTH: "2-Step Verification (TOTP)"
+ LABEL_ENABLE_TWO_FACTOR: "Enable 2-Step verification"
+ LABEL_TWO_FACTOR_USER: "User"
+ LABEL_TWO_FACTOR_STATUS: "Status"
+ LABEL_TWO_FACTOR_SECRET: "Secret"
+ LABEL_TWO_FACTOR_BACKUP_CODES: "Backup codes"
+ BUTTON_CREATE: "Create a secret"
+ BUTTON_ACTIVATE: "Activate"
+ BUTTON_CLEAR: "Clear"
+ BUTTON_LOGOUT: "Logout"
+ BUTTON_DONE: "Done"
+ BUTTON_TEST: "Test"
+ LINK_TEST: "test"
+ BUTTON_SHOW_SECRET: "Show Secret"
+ BUTTON_HIDE_SECRET: "Hide Secret"
+ TWO_FACTOR_REQUIRE_DESC: "Your account requires 2-Step verification configuration."
+ TWO_FACTOR_SECRET_CONFIGURED_DESC: "Configured"
+ TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC: "Not configured"
TWO_FACTOR_SECRET_DESC: >
Import this info into your Google Authenticator client (or other TOTP client)
using the provided QR code below or by entering the code manually.
@@ -402,246 +402,246 @@ en:
If you can't receive codes via Google Authenticator (or other TOTP client),
you can use backup codes to sign in. After you’ve used a backup code to sign
in, it will become inactive.
- TWO_FACTOR_SECRET_TEST_BEFORE_DESC: "You can't change this setting before test."
- TITLES:
- LOADING: "Loading"
- LOGIN: "Login"
- MAILBOX: "MailBox"
- SETTINGS: "Settings"
- COMPOSE: "Compose"
- UPLOAD:
- ERROR_FILE_IS_TOO_BIG: "File is too big"
- ERROR_FILE_PARTIALLY_UPLOADED: "File was partially uploaded due to unknown error"
- ERROR_NO_FILE_UPLOADED: "No file uploaded"
- ERROR_MISSING_TEMP_FOLDER: "The temporary file is missing"
- ERROR_ON_SAVING_FILE: "An unknown file upload error occurred"
- ERROR_FILE_TYPE: "Invalid file type"
- ERROR_UNKNOWN: "An unknown file upload error occurred"
- EDITOR:
- TEXT_SWITCHER_PLAINT_TEXT: "HTML <-> TEXT"
- TEXT_SWITCHER_RICH_FORMATTING: "Rich formatting"
- TEXT_SWITCHER_CONFIRM: "Text formatting and images will be lost. Are you sure you want to continue?"
- SETTINGS_LABELS:
- LABEL_PERSONAL_NAME: "Personal"
- LABEL_GENERAL_NAME: "General"
- LABEL_CONTACTS_NAME: "Contacts"
- LABEL_FOLDERS_NAME: "Folders"
- LABEL_ACCOUNTS_NAME: "Accounts"
- LABEL_IDENTITY_NAME: "Identity"
- LABEL_IDENTITIES_NAME: "Identities"
- LABEL_FILTERS_NAME: "Filters"
- LABEL_TEMPLATES_NAME: "Templates"
- LABEL_SECURITY_NAME: "Security"
- LABEL_SOCIAL_NAME: "Social"
- LABEL_THEMES_NAME: "Themes"
- LABEL_CHANGE_PASSWORD_NAME: "Password"
- LABEL_OPEN_PGP_NAME: "OpenPGP"
- BUTTON_BACK: "Back"
- SETTINGS_FILTERS:
- LEGEND_FILTERS: "Filters"
- BUTTON_SAVE: "Save"
- BUTTON_ADD_FILTER: "Add a Filter"
- BUTTON_DELETE: "Delete"
- BUTTON_RAW_SCRIPT: "Use Custom User Script"
- SUBNAME_NONE: "None"
- SUBNAME_MOVE_TO: "Move to \"%FOLDER%\""
- SUBNAME_FORWARD_TO: "Forward to \"%EMAIL%\""
- SUBNAME_REJECT: "Reject"
- SUBNAME_VACATION_MESSAGE: "Vacation message"
- SUBNAME_DISCARD: "Discard"
- CAPABILITY_LABEL: "Capability"
- LOADING_PROCESS: "Updating filter list"
- DELETING_ASK: "Are you sure?"
- CHACHES_NEED_TO_BE_SAVED_DESC: "These changes need to be saved to the server."
- SETTINGS_IDENTITY:
- LEGEND_IDENTITY: "Identity"
- LABEL_DISPLAY_NAME: "Name"
- LABEL_REPLY_TO: "Reply-To"
- LABEL_SIGNATURE: "Signature"
- LABEL_ADD_SIGNATURE_TO_ALL: "Add your signature to all the outgoing messages"
- SETTINGS_SECURITY:
- LEGEND_SECURITY: "Security"
- LABEL_CONFIGURE_TWO_FACTOR: "Configure 2-Step verification"
- LABEL_AUTOLOGOUT: "Auto Logout"
- AUTOLOGIN_NEVER_OPTION_NAME: "Never"
- AUTOLOGIN_MINUTES_OPTION_NAME: "%MINUTES% minute(s)"
- AUTOLOGIN_HOURS_OPTION_NAME: "%HOURS% hour(s)"
- SETTINGS_GENERAL:
- LEGEND_GENERAL: "General"
- LABEL_LANGUAGE: "Language"
- LABEL_IDENTITY: "Identity"
- LABEL_LAYOUT: "Layout"
- LABEL_LAYOUT_NO_SPLIT: "No Split"
- LABEL_LAYOUT_VERTICAL_SPLIT: "Vertical Split"
- LABEL_LAYOUT_HORIZONTAL_SPLIT: "Horizontal Split"
- LABEL_EDITOR: "Default text editor"
- LABEL_EDITOR_HTML: "Html"
- LABEL_EDITOR_PLAIN: "Plain"
- LABEL_EDITOR_HTML_FORCED: "Html (forced)"
- LABEL_EDITOR_PLAIN_FORCED: "Plain (forced)"
- LABEL_ANIMATION: "Interface animation"
- LABEL_ANIMATION_FULL: "Full"
- LABEL_ANIMATION_NORMAL: "Normal"
- LABEL_ANIMATION_NONE: "None"
- LABEL_VIEW_OPTIONS: "View options"
- LABEL_USE_PREVIEW_PANE: "Use preview pane"
- LABEL_USE_CHECKBOXES_IN_LIST: "Display checkboxes in list"
- LABEL_USE_THREADS: "Use threads"
- LABEL_REPLY_SAME_FOLDER: "Place replies in the folder of the message being replied to"
- LABEL_SHOW_IMAGES: "Always display external images in message body"
- LABEL_SHOW_ANIMATION: "Show animation"
- LABEL_MESSAGE_PER_PAGE: "Messages on page"
- LABEL_NOTIFICATIONS: "Notifications"
- LABEL_SOUND_NOTIFICATION: "Sound notification"
- LABEL_CHROME_NOTIFICATION_DESC: "Show new messages notification popups"
- LABEL_CHROME_NOTIFICATION_DESC_DENIED: "(Blocked by the browser)"
- SETTINGS_CONTACTS:
- LEGEND_CONTACTS: "Contacts"
- LABEL_CONTACTS_AUTOSAVE: "Automatically add recipients to your address book"
- LEGEND_CONTACTS_SYNC: "Remote Synchronization (CardDAV)"
- LABEL_CONTACTS_SYNC_ENABLE: "Enable remote synchronization"
- LABEL_CONTACTS_SYNC_SERVER: "Server"
- LABEL_CONTACTS_SYNC_AB_URL: "Addressbook URL"
- LABEL_CONTACTS_SYNC_USER: "User"
- LABEL_CONTACTS_SYNC_PASSWORD: "Password"
- SETTINGS_THEMES:
- LEGEND_THEMES: "Themes"
- LEGEND_THEMES_CUSTOM: "Custom Theme Configuration"
- LABEL_CUSTOM_TYPE: "Type"
- LABEL_CUSTOM_TYPE_LIGHT: "Light"
- LABEL_CUSTOM_TYPE_DARK: "Dark"
- LABEL_CUSTOM_BACKGROUND_IMAGE: "Background"
- BUTTON_UPLOAD_BACKGROUND_IMAGE: "Upload background image (JPG, PNG)"
- ERROR_FILE_IS_TOO_BIG: "File is too big"
- ERROR_FILE_TYPE_ERROR: "Invalid file type (JPG and PNG only)"
- ERROR_UNKNOWN: "An unknown file upload error occurred"
- SETTINGS_SOCIAL:
- LEGEND_GOOGLE: "Google"
- BUTTON_GOOGLE_CONNECT: "Connect Google"
- BUTTON_GOOGLE_DISCONNECT: "Disconnect Google"
- MAIN_GOOGLE_DESC: "After enabling login via Google, you can log into this account using Google button on the login screen."
- LEGEND_FACEBOOK: "Facebook"
- BUTTON_FACEBOOK_CONNECT: "Connect Facebook"
- BUTTON_FACEBOOK_DISCONNECT: "Disconnect Facebook"
- MAIN_FACEBOOK_DESC: "After enabling login via Facebook, you can log into this account using Facebook button on the login screen."
- LEGEND_TWITTER: "Twitter"
- BUTTON_TWITTER_CONNECT: "Connect Twitter"
- BUTTON_TWITTER_DISCONNECT: "Disconnect Twitter"
- MAIN_TWITTER_DESC: "After enabling login via Twitter, you can log into this account using Twitter button on the login screen."
- SETTINGS_FOLDERS:
- LEGEND_FOLDERS: "Folder List"
- BUTTON_CREATE: "Create Folder"
- BUTTON_SYSTEM: "System Folders"
- BUTTON_DELETE: "Delete"
- BUTTON_SUBSCRIBE: "Subscribe"
- BUTTON_UNSUBSCRIBE: "Unsubscribe"
- LOADING_PROCESS: "Updating folder list"
- CREATING_PROCESS: "Creating a folder"
- DELETING_PROCESS: "Deleting a folder"
- RENAMING_PROCESS: "Renaming a folder"
- DELETING_ASK: "Are you sure?"
- TO_MANY_FOLDERS_DESC_1: "You have too many folders!"
- TO_MANY_FOLDERS_DESC_2: "We have shown only a part of them, to avoid performance problems."
- HELP_DELETE_FOLDER: "Delete folder"
- HELP_SHOW_HIDE_FOLDER: "Show/hide folder"
- HELP_CHECK_FOR_NEW_MESSAGES: "Check/don't check for new messages"
- SETTINGS_ACCOUNTS:
- LEGEND_ACCOUNTS: "Accounts"
- LEGEND_IDENTITIES: "Identities"
- LEGEND_ACCOUNTS_AND_IDENTITIES: "Accounts and Identities"
- BUTTON_ADD_ACCOUNT: "Add an Account"
- BUTTON_ADD_IDENTITY: "Add an Identity"
- BUTTON_DELETE: "Delete"
- LOADING_PROCESS: "Updating..."
- DELETING_ASK: "Are you sure?"
- DEFAULT_IDENTITY_LABEL: "default"
- SETTINGS_IDENTITIES:
- LEGEND_IDENTITY: "Identity"
- LEGEND_IDENTITIES: "Additional Identities"
- LABEL_DEFAULT: "Default"
- LABEL_DISPLAY_NAME: "Name"
- LABEL_REPLY_TO: "Reply-To"
- LABEL_SIGNATURE: "Signature"
- LABEL_ADD_SIGNATURE_TO_ALL: "Add your signature to all the outgoing messages"
- BUTTON_ADD_IDENTITY: "Add Identity"
- BUTTON_DELETE: "Delete"
- LOADING_PROCESS: "Updating identity list"
- DELETING_ASK: "Are you sure?"
- SETTINGS_CHANGE_PASSWORD:
- LEGEND_CHANGE_PASSWORD: "Change Password"
- LABEL_CURRENT_PASSWORD: "Current password"
- LABEL_NEW_PASSWORD: "New password"
- LABEL_REPEAT_PASSWORD: "Confirm New Password"
- BUTTON_UPDATE_PASSWORD: "Set New Password"
- ERROR_PASSWORD_MISMATCH: "Passwords do not match, please try again"
- SETTINGS_OPEN_PGP:
- LEGEND_OPEN_PGP: "OpenPGP"
- BUTTON_ADD_OPEN_PGP_KEY: "Import OpenPGP Key"
- BUTTON_GENERATE_OPEN_PGP_KEYS: "Generate OpenPGP Keys"
- TITLE_PRIVATE: "Private"
- TITLE_PUBLIC: "Public"
- DELETING_ASK: "Are you sure?"
- GENERATE_ONLY_HTTPS: "HTTPS only"
- LABEL_ALLOW_DRAFT_AUTOSAVE: "Automatically save draft"
- SHORTCUTS_HELP:
- LEGEND_SHORTCUTS_HELP: "Keyboard shortcuts help"
- TAB_MAILBOX: "Mailbox"
- TAB_MESSAGE_LIST: "Message list"
- TAB_MESSAGE_VIEW: "Message view"
- TAB_COMPOSE: "Compose"
- LABEL_OPEN_USER_DROPDOWN: "Open user dropdown"
- LABEL_REPLY: "Reply"
- LABEL_REPLY_ALL: "Reply All"
- LABEL_FORWARD: "Forward"
- LABEL_FORWARD_MULTIPLY: "Forward as attachment(s)"
- LABEL_HELP: "Help"
- LABEL_CHECK_ALL: "Select all messages"
- LABEL_ARCHIVE: "Archive"
- LABEL_DELETE: "Delete"
- LABEL_OPEN_THREAD: "Open selected thread"
- LABEL_MOVE: "Move"
- LABEL_READ: "Read selected messages"
- LABEL_UNREAD: "Unread selected messages"
- LABEL_IMPORTANT: "Important, flag selected messages"
- LABEL_SEARCH: "Search"
- LABEL_CANCEL_SEARCH: "Cancel search"
- LABEL_FULLSCREEN_ENTER: "Fullscreen (Preview pane layout)"
- LABEL_VIEW_MESSAGE_ENTER: "View message (No preview pane layout)"
- LABEL_SWITCH_TO_MESSAGE: "Switch focus to selected message"
- LABEL_SWITCH_TO_FOLDER_LIST: "Switch focus to folder list"
- LABEL_FULLSCREEN_TOGGLE: "Toggle fullscreen mode"
- LABEL_BLOCKQUOTES_TOGGLE: "Toggle message blockquotes"
- LABEL_THREAD_NEXT: "Next message in thread"
- LABEL_THREAD_PREV: "Previous message in thread"
- LABEL_PRINT: "Print"
- LABEL_EXIT_FULLSCREEN: "Exit fullscreen mode"
- LABEL_CLOSE_MESSAGE: "Close message (No preview pane layout)"
- LABEL_SWITCH_TO_LIST: "Switch focus back to message list"
- LABEL_OPEN_COMPOSE_POPUP: "Open compose popup"
- LABEL_MINIMIZE_COMPOSE_POPUP: "Minimize compose popup"
- LABEL_OPEN_IDENTITIES_DROPDOWN: "Open identities dropdown"
- LABEL_SAVE_MESSAGE: "Save message"
- LABEL_SEND_MESSAGE: "Send message"
- LABEL_CLOSE_COMPOSE: "Close compose"
- PGP_NOTIFICATIONS:
- NO_PUBLIC_KEYS_FOUND: "No public keys found"
- NO_PUBLIC_KEYS_FOUND_FOR: "No public keys found for \"%EMAIL%\" email"
- NO_PRIVATE_KEY_FOUND: "No private key found"
- NO_PRIVATE_KEY_FOUND_FOR: "No private key found for \"%EMAIL%\" email"
- ADD_A_PUBLICK_KEY: "Add a public key"
- SELECT_A_PRIVATE_KEY: "Select a private key"
- UNVERIFIRED_SIGNATURE: "Unverified signature"
- DECRYPTION_ERROR: "OpenPGP decryption error"
- GOOD_SIGNATURE: "Good signature from %USER%"
- PGP_ERROR: "OpenPGP error: %ERROR%"
- SPECIFY_FROM_EMAIL: "Please specify FROM email address"
- SPECIFY_AT_LEAST_ONE_RECIPIENT: "Please specify at least one recipient"
- NOTIFICATIONS:
- INVALID_TOKEN: "Invalid token"
- AUTH_ERROR: "Authentication failed"
- ACCESS_ERROR: "Access error"
- CONNECTION_ERROR: "Can't connect to server"
- CAPTCHA_ERROR: "Incorrect CAPTCHA."
+ TWO_FACTOR_SECRET_TEST_BEFORE_DESC: "You can't change this setting before test."
+ TITLES:
+ LOADING: "Loading"
+ LOGIN: "Login"
+ MAILBOX: "MailBox"
+ SETTINGS: "Settings"
+ COMPOSE: "Compose"
+ UPLOAD:
+ ERROR_FILE_IS_TOO_BIG: "File is too big"
+ ERROR_FILE_PARTIALLY_UPLOADED: "File was partially uploaded due to unknown error"
+ ERROR_NO_FILE_UPLOADED: "No file uploaded"
+ ERROR_MISSING_TEMP_FOLDER: "The temporary file is missing"
+ ERROR_ON_SAVING_FILE: "An unknown file upload error occurred"
+ ERROR_FILE_TYPE: "Invalid file type"
+ ERROR_UNKNOWN: "An unknown file upload error occurred"
+ EDITOR:
+ TEXT_SWITCHER_PLAINT_TEXT: "HTML <-> TEXT"
+ TEXT_SWITCHER_RICH_FORMATTING: "Rich formatting"
+ TEXT_SWITCHER_CONFIRM: "Text formatting and images will be lost. Are you sure you want to continue?"
+ SETTINGS_LABELS:
+ LABEL_PERSONAL_NAME: "Personal"
+ LABEL_GENERAL_NAME: "General"
+ LABEL_CONTACTS_NAME: "Contacts"
+ LABEL_FOLDERS_NAME: "Folders"
+ LABEL_ACCOUNTS_NAME: "Accounts"
+ LABEL_IDENTITY_NAME: "Identity"
+ LABEL_IDENTITIES_NAME: "Identities"
+ LABEL_FILTERS_NAME: "Filters"
+ LABEL_TEMPLATES_NAME: "Templates"
+ LABEL_SECURITY_NAME: "Security"
+ LABEL_SOCIAL_NAME: "Social"
+ LABEL_THEMES_NAME: "Themes"
+ LABEL_CHANGE_PASSWORD_NAME: "Password"
+ LABEL_OPEN_PGP_NAME: "OpenPGP"
+ BUTTON_BACK: "Back"
+ SETTINGS_FILTERS:
+ LEGEND_FILTERS: "Filters"
+ BUTTON_SAVE: "Save"
+ BUTTON_ADD_FILTER: "Add a Filter"
+ BUTTON_DELETE: "Delete"
+ BUTTON_RAW_SCRIPT: "Use Custom User Script"
+ SUBNAME_NONE: "None"
+ SUBNAME_MOVE_TO: "Move to \"%FOLDER%\""
+ SUBNAME_FORWARD_TO: "Forward to \"%EMAIL%\""
+ SUBNAME_REJECT: "Reject"
+ SUBNAME_VACATION_MESSAGE: "Vacation message"
+ SUBNAME_DISCARD: "Discard"
+ CAPABILITY_LABEL: "Capability"
+ LOADING_PROCESS: "Updating filter list"
+ DELETING_ASK: "Are you sure?"
+ CHACHES_NEED_TO_BE_SAVED_DESC: "These changes need to be saved to the server."
+ SETTINGS_IDENTITY:
+ LEGEND_IDENTITY: "Identity"
+ LABEL_DISPLAY_NAME: "Name"
+ LABEL_REPLY_TO: "Reply-To"
+ LABEL_SIGNATURE: "Signature"
+ LABEL_ADD_SIGNATURE_TO_ALL: "Add your signature to all the outgoing messages"
+ SETTINGS_SECURITY:
+ LEGEND_SECURITY: "Security"
+ LABEL_CONFIGURE_TWO_FACTOR: "Configure 2-Step verification"
+ LABEL_AUTOLOGOUT: "Auto Logout"
+ AUTOLOGIN_NEVER_OPTION_NAME: "Never"
+ AUTOLOGIN_MINUTES_OPTION_NAME: "%MINUTES% minute(s)"
+ AUTOLOGIN_HOURS_OPTION_NAME: "%HOURS% hour(s)"
+ SETTINGS_GENERAL:
+ LEGEND_GENERAL: "General"
+ LABEL_LANGUAGE: "Language"
+ LABEL_IDENTITY: "Identity"
+ LABEL_LAYOUT: "Layout"
+ LABEL_LAYOUT_NO_SPLIT: "No Split"
+ LABEL_LAYOUT_VERTICAL_SPLIT: "Vertical Split"
+ LABEL_LAYOUT_HORIZONTAL_SPLIT: "Horizontal Split"
+ LABEL_EDITOR: "Default text editor"
+ LABEL_EDITOR_HTML: "Html"
+ LABEL_EDITOR_PLAIN: "Plain"
+ LABEL_EDITOR_HTML_FORCED: "Html (forced)"
+ LABEL_EDITOR_PLAIN_FORCED: "Plain (forced)"
+ LABEL_ANIMATION: "Interface animation"
+ LABEL_ANIMATION_FULL: "Full"
+ LABEL_ANIMATION_NORMAL: "Normal"
+ LABEL_ANIMATION_NONE: "None"
+ LABEL_VIEW_OPTIONS: "View options"
+ LABEL_USE_PREVIEW_PANE: "Use preview pane"
+ LABEL_USE_CHECKBOXES_IN_LIST: "Display checkboxes in list"
+ LABEL_USE_THREADS: "Use threads"
+ LABEL_REPLY_SAME_FOLDER: "Place replies in the folder of the message being replied to"
+ LABEL_SHOW_IMAGES: "Always display external images in message body"
+ LABEL_SHOW_ANIMATION: "Show animation"
+ LABEL_MESSAGE_PER_PAGE: "Messages on page"
+ LABEL_NOTIFICATIONS: "Notifications"
+ LABEL_SOUND_NOTIFICATION: "Sound notification"
+ LABEL_CHROME_NOTIFICATION_DESC: "Show new messages notification popups"
+ LABEL_CHROME_NOTIFICATION_DESC_DENIED: "(Blocked by the browser)"
+ SETTINGS_CONTACTS:
+ LEGEND_CONTACTS: "Contacts"
+ LABEL_CONTACTS_AUTOSAVE: "Automatically add recipients to your address book"
+ LEGEND_CONTACTS_SYNC: "Remote Synchronization (CardDAV)"
+ LABEL_CONTACTS_SYNC_ENABLE: "Enable remote synchronization"
+ LABEL_CONTACTS_SYNC_SERVER: "Server"
+ LABEL_CONTACTS_SYNC_AB_URL: "Addressbook URL"
+ LABEL_CONTACTS_SYNC_USER: "User"
+ LABEL_CONTACTS_SYNC_PASSWORD: "Password"
+ SETTINGS_THEMES:
+ LEGEND_THEMES: "Themes"
+ LEGEND_THEMES_CUSTOM: "Custom Theme Configuration"
+ LABEL_CUSTOM_TYPE: "Type"
+ LABEL_CUSTOM_TYPE_LIGHT: "Light"
+ LABEL_CUSTOM_TYPE_DARK: "Dark"
+ LABEL_CUSTOM_BACKGROUND_IMAGE: "Background"
+ BUTTON_UPLOAD_BACKGROUND_IMAGE: "Upload background image (JPG, PNG)"
+ ERROR_FILE_IS_TOO_BIG: "File is too big"
+ ERROR_FILE_TYPE_ERROR: "Invalid file type (JPG and PNG only)"
+ ERROR_UNKNOWN: "An unknown file upload error occurred"
+ SETTINGS_SOCIAL:
+ LEGEND_GOOGLE: "Google"
+ BUTTON_GOOGLE_CONNECT: "Connect Google"
+ BUTTON_GOOGLE_DISCONNECT: "Disconnect Google"
+ MAIN_GOOGLE_DESC: "After enabling login via Google, you can log into this account using Google button on the login screen."
+ LEGEND_FACEBOOK: "Facebook"
+ BUTTON_FACEBOOK_CONNECT: "Connect Facebook"
+ BUTTON_FACEBOOK_DISCONNECT: "Disconnect Facebook"
+ MAIN_FACEBOOK_DESC: "After enabling login via Facebook, you can log into this account using Facebook button on the login screen."
+ LEGEND_TWITTER: "Twitter"
+ BUTTON_TWITTER_CONNECT: "Connect Twitter"
+ BUTTON_TWITTER_DISCONNECT: "Disconnect Twitter"
+ MAIN_TWITTER_DESC: "After enabling login via Twitter, you can log into this account using Twitter button on the login screen."
+ SETTINGS_FOLDERS:
+ LEGEND_FOLDERS: "Folder List"
+ BUTTON_CREATE: "Create Folder"
+ BUTTON_SYSTEM: "System Folders"
+ BUTTON_DELETE: "Delete"
+ BUTTON_SUBSCRIBE: "Subscribe"
+ BUTTON_UNSUBSCRIBE: "Unsubscribe"
+ LOADING_PROCESS: "Updating folder list"
+ CREATING_PROCESS: "Creating a folder"
+ DELETING_PROCESS: "Deleting a folder"
+ RENAMING_PROCESS: "Renaming a folder"
+ DELETING_ASK: "Are you sure?"
+ TO_MANY_FOLDERS_DESC_1: "You have too many folders!"
+ TO_MANY_FOLDERS_DESC_2: "We have shown only a part of them, to avoid performance problems."
+ HELP_DELETE_FOLDER: "Delete folder"
+ HELP_SHOW_HIDE_FOLDER: "Show/hide folder"
+ HELP_CHECK_FOR_NEW_MESSAGES: "Check/don't check for new messages"
+ SETTINGS_ACCOUNTS:
+ LEGEND_ACCOUNTS: "Accounts"
+ LEGEND_IDENTITIES: "Identities"
+ LEGEND_ACCOUNTS_AND_IDENTITIES: "Accounts and Identities"
+ BUTTON_ADD_ACCOUNT: "Add an Account"
+ BUTTON_ADD_IDENTITY: "Add an Identity"
+ BUTTON_DELETE: "Delete"
+ LOADING_PROCESS: "Updating..."
+ DELETING_ASK: "Are you sure?"
+ DEFAULT_IDENTITY_LABEL: "default"
+ SETTINGS_IDENTITIES:
+ LEGEND_IDENTITY: "Identity"
+ LEGEND_IDENTITIES: "Additional Identities"
+ LABEL_DEFAULT: "Default"
+ LABEL_DISPLAY_NAME: "Name"
+ LABEL_REPLY_TO: "Reply-To"
+ LABEL_SIGNATURE: "Signature"
+ LABEL_ADD_SIGNATURE_TO_ALL: "Add your signature to all the outgoing messages"
+ BUTTON_ADD_IDENTITY: "Add Identity"
+ BUTTON_DELETE: "Delete"
+ LOADING_PROCESS: "Updating identity list"
+ DELETING_ASK: "Are you sure?"
+ SETTINGS_CHANGE_PASSWORD:
+ LEGEND_CHANGE_PASSWORD: "Change Password"
+ LABEL_CURRENT_PASSWORD: "Current password"
+ LABEL_NEW_PASSWORD: "New password"
+ LABEL_REPEAT_PASSWORD: "Confirm New Password"
+ BUTTON_UPDATE_PASSWORD: "Set New Password"
+ ERROR_PASSWORD_MISMATCH: "Passwords do not match, please try again"
+ SETTINGS_OPEN_PGP:
+ LEGEND_OPEN_PGP: "OpenPGP"
+ BUTTON_ADD_OPEN_PGP_KEY: "Import OpenPGP Key"
+ BUTTON_GENERATE_OPEN_PGP_KEYS: "Generate OpenPGP Keys"
+ TITLE_PRIVATE: "Private"
+ TITLE_PUBLIC: "Public"
+ DELETING_ASK: "Are you sure?"
+ GENERATE_ONLY_HTTPS: "HTTPS only"
+ LABEL_ALLOW_DRAFT_AUTOSAVE: "Automatically save draft"
+ SHORTCUTS_HELP:
+ LEGEND_SHORTCUTS_HELP: "Keyboard shortcuts help"
+ TAB_MAILBOX: "Mailbox"
+ TAB_MESSAGE_LIST: "Message list"
+ TAB_MESSAGE_VIEW: "Message view"
+ TAB_COMPOSE: "Compose"
+ LABEL_OPEN_USER_DROPDOWN: "Open user dropdown"
+ LABEL_REPLY: "Reply"
+ LABEL_REPLY_ALL: "Reply All"
+ LABEL_FORWARD: "Forward"
+ LABEL_FORWARD_MULTIPLY: "Forward as attachment(s)"
+ LABEL_HELP: "Help"
+ LABEL_CHECK_ALL: "Select all messages"
+ LABEL_ARCHIVE: "Archive"
+ LABEL_DELETE: "Delete"
+ LABEL_OPEN_THREAD: "Open selected thread"
+ LABEL_MOVE: "Move"
+ LABEL_READ: "Read selected messages"
+ LABEL_UNREAD: "Unread selected messages"
+ LABEL_IMPORTANT: "Important, flag selected messages"
+ LABEL_SEARCH: "Search"
+ LABEL_CANCEL_SEARCH: "Cancel search"
+ LABEL_FULLSCREEN_ENTER: "Fullscreen (Preview pane layout)"
+ LABEL_VIEW_MESSAGE_ENTER: "View message (No preview pane layout)"
+ LABEL_SWITCH_TO_MESSAGE: "Switch focus to selected message"
+ LABEL_SWITCH_TO_FOLDER_LIST: "Switch focus to folder list"
+ LABEL_FULLSCREEN_TOGGLE: "Toggle fullscreen mode"
+ LABEL_BLOCKQUOTES_TOGGLE: "Toggle message blockquotes"
+ LABEL_THREAD_NEXT: "Next message in thread"
+ LABEL_THREAD_PREV: "Previous message in thread"
+ LABEL_PRINT: "Print"
+ LABEL_EXIT_FULLSCREEN: "Exit fullscreen mode"
+ LABEL_CLOSE_MESSAGE: "Close message (No preview pane layout)"
+ LABEL_SWITCH_TO_LIST: "Switch focus back to message list"
+ LABEL_OPEN_COMPOSE_POPUP: "Open compose popup"
+ LABEL_MINIMIZE_COMPOSE_POPUP: "Minimize compose popup"
+ LABEL_OPEN_IDENTITIES_DROPDOWN: "Open identities dropdown"
+ LABEL_SAVE_MESSAGE: "Save message"
+ LABEL_SEND_MESSAGE: "Send message"
+ LABEL_CLOSE_COMPOSE: "Close compose"
+ PGP_NOTIFICATIONS:
+ NO_PUBLIC_KEYS_FOUND: "No public keys found"
+ NO_PUBLIC_KEYS_FOUND_FOR: "No public keys found for \"%EMAIL%\" email"
+ NO_PRIVATE_KEY_FOUND: "No private key found"
+ NO_PRIVATE_KEY_FOUND_FOR: "No private key found for \"%EMAIL%\" email"
+ ADD_A_PUBLICK_KEY: "Add a public key"
+ SELECT_A_PRIVATE_KEY: "Select a private key"
+ UNVERIFIRED_SIGNATURE: "Unverified signature"
+ DECRYPTION_ERROR: "OpenPGP decryption error"
+ GOOD_SIGNATURE: "Good signature from %USER%"
+ PGP_ERROR: "OpenPGP error: %ERROR%"
+ SPECIFY_FROM_EMAIL: "Please specify FROM email address"
+ SPECIFY_AT_LEAST_ONE_RECIPIENT: "Please specify at least one recipient"
+ NOTIFICATIONS:
+ INVALID_TOKEN: "Invalid token"
+ AUTH_ERROR: "Authentication failed"
+ ACCESS_ERROR: "Access error"
+ CONNECTION_ERROR: "Can't connect to server"
+ CAPTCHA_ERROR: "Incorrect CAPTCHA."
SOCIAL_FACEBOOK_LOGIN_ACCESS_DISABLE: >
This social ID is not assigned for any email account yet. Log in using email
credentials and enable this feature in account settings.
@@ -651,63 +651,63 @@ en:
SOCIAL_GOOGLE_LOGIN_ACCESS_DISABLE: >
This social ID is not assigned for any email account yet. Log in using email
credentials and enable this feature in account settings.
- DOMAIN_NOT_ALLOWED: "Domain is not allowed"
- ACCOUNT_NOT_ALLOWED: "Account is not allowed"
- ACCOUNT_TWO_FACTOR_AUTH_REQUIRED: "Two factor verification required"
- ACCOUNT_TWO_FACTOR_AUTH_ERROR: "Two factor verification error"
- COULD_NOT_SAVE_NEW_PASSWORD: "Could not save new password"
- CURRENT_PASSWORD_INCORRECT: "Current password incorrect"
- NEW_PASSWORD_SHORT: "Password is too short"
- NEW_PASSWORD_WEAK: "Password is too easy"
- NEW_PASSWORD_FORBIDDENT: "Password contains forbidden characters"
- CONTACTS_SYNC_ERROR: "Contacts synchronization error"
- CANT_GET_MESSAGE_LIST: "Can't get message list"
- CANT_GET_MESSAGE: "Can't get message"
- CANT_DELETE_MESSAGE: "Can't delete message"
- CANT_MOVE_MESSAGE: "Can't move message"
- CANT_SAVE_MESSAGE: "Can't save message"
- CANT_SEND_MESSAGE: "Can't send message"
- INVALID_RECIPIENTS: "Invalid recipients"
- CANT_SAVE_FILTERS: "Can't save filters"
- CANT_GET_FILTERS: "Can't get filters"
- FILTERS_ARE_NOT_CORRECT: "Filters are not correct"
- CANT_CREATE_FOLDER: "Can't create folder"
- CANT_RENAME_FOLDER: "Can't rename folder"
- CANT_DELETE_FOLDER: "Can't delete folder"
- CANT_DELETE_NON_EMPTY_FOLDER: "Can't delete non-empty directory"
- CANT_SUBSCRIBE_FOLDER: "Can't subscribe folder"
- CANT_UNSUBSCRIBE_FOLDER: "Can't unsubscribe folder"
- CANT_SAVE_SETTINGS: "Can't save settings"
- CANT_SAVE_PLUGIN_SETTINGS: "Can't save settings"
- DOMAIN_ALREADY_EXISTS: "Domain already exists"
- CANT_INSTALL_PACKAGE: "Failed to install package"
- CANT_DELETE_PACKAGE: "Failed to remove package"
- INVALID_PLUGIN_PACKAGE: "Invalid plugin package"
- UNSUPPORTED_PLUGIN_PACKAGE: "Unsupported plugin package"
- LICENSING_SERVER_IS_UNAVAILABLE: "Subscription server is unvailable"
- LICENSING_DOMAIN_EXPIRED: "Subscription for this domain has expired."
- LICENSING_DOMAIN_BANNED: "Subscription for this domain is banned."
- DEMO_SEND_MESSAGE_ERROR: "For security purposes, this account is not allowed to send messages to external e-mail addresses!"
- DEMO_ACCOUNT_ERROR: "For security purposes, this account is not allowed for this action!"
- ACCOUNT_ALREADY_EXISTS: "Account already exists"
- ACCOUNT_DOES_NOT_EXIST: "Account doesn't exist"
- MAIL_SERVER_ERROR: "An error has occured while accessing mail server"
- INVALID_INPUT_ARGUMENT: "Invalid input argument"
- UNKNOWN_ERROR: "Unknown error"
- STATIC:
- BACK_LINK: "Reload"
- DOMAIN_LIST_DESC: "List of domains webmail is allowed to access."
- PHP_EXSTENSIONS_ERROR_DESC: "Required PHP extension are not available in your PHP configuration!"
- PHP_VERSION_ERROR_DESC: "Your PHP version (%VERSION%) is lower than the minimal required 5.3.0!"
- NO_SCRIPT_TITLE: "JavaScript is required for this application."
+ DOMAIN_NOT_ALLOWED: "Domain is not allowed"
+ ACCOUNT_NOT_ALLOWED: "Account is not allowed"
+ ACCOUNT_TWO_FACTOR_AUTH_REQUIRED: "Two factor verification required"
+ ACCOUNT_TWO_FACTOR_AUTH_ERROR: "Two factor verification error"
+ COULD_NOT_SAVE_NEW_PASSWORD: "Could not save new password"
+ CURRENT_PASSWORD_INCORRECT: "Current password incorrect"
+ NEW_PASSWORD_SHORT: "Password is too short"
+ NEW_PASSWORD_WEAK: "Password is too easy"
+ NEW_PASSWORD_FORBIDDENT: "Password contains forbidden characters"
+ CONTACTS_SYNC_ERROR: "Contacts synchronization error"
+ CANT_GET_MESSAGE_LIST: "Can't get message list"
+ CANT_GET_MESSAGE: "Can't get message"
+ CANT_DELETE_MESSAGE: "Can't delete message"
+ CANT_MOVE_MESSAGE: "Can't move message"
+ CANT_SAVE_MESSAGE: "Can't save message"
+ CANT_SEND_MESSAGE: "Can't send message"
+ INVALID_RECIPIENTS: "Invalid recipients"
+ CANT_SAVE_FILTERS: "Can't save filters"
+ CANT_GET_FILTERS: "Can't get filters"
+ FILTERS_ARE_NOT_CORRECT: "Filters are not correct"
+ CANT_CREATE_FOLDER: "Can't create folder"
+ CANT_RENAME_FOLDER: "Can't rename folder"
+ CANT_DELETE_FOLDER: "Can't delete folder"
+ CANT_DELETE_NON_EMPTY_FOLDER: "Can't delete non-empty directory"
+ CANT_SUBSCRIBE_FOLDER: "Can't subscribe folder"
+ CANT_UNSUBSCRIBE_FOLDER: "Can't unsubscribe folder"
+ CANT_SAVE_SETTINGS: "Can't save settings"
+ CANT_SAVE_PLUGIN_SETTINGS: "Can't save settings"
+ DOMAIN_ALREADY_EXISTS: "Domain already exists"
+ CANT_INSTALL_PACKAGE: "Failed to install package"
+ CANT_DELETE_PACKAGE: "Failed to remove package"
+ INVALID_PLUGIN_PACKAGE: "Invalid plugin package"
+ UNSUPPORTED_PLUGIN_PACKAGE: "Unsupported plugin package"
+ LICENSING_SERVER_IS_UNAVAILABLE: "Subscription server is unvailable"
+ LICENSING_DOMAIN_EXPIRED: "Subscription for this domain has expired."
+ LICENSING_DOMAIN_BANNED: "Subscription for this domain is banned."
+ DEMO_SEND_MESSAGE_ERROR: "For security purposes, this account is not allowed to send messages to external e-mail addresses!"
+ DEMO_ACCOUNT_ERROR: "For security purposes, this account is not allowed for this action!"
+ ACCOUNT_ALREADY_EXISTS: "Account already exists"
+ ACCOUNT_DOES_NOT_EXIST: "Account doesn't exist"
+ MAIL_SERVER_ERROR: "An error has occured while accessing mail server"
+ INVALID_INPUT_ARGUMENT: "Invalid input argument"
+ UNKNOWN_ERROR: "Unknown error"
+ STATIC:
+ BACK_LINK: "Reload"
+ DOMAIN_LIST_DESC: "List of domains webmail is allowed to access."
+ PHP_EXSTENSIONS_ERROR_DESC: "Required PHP extension are not available in your PHP configuration!"
+ PHP_VERSION_ERROR_DESC: "Your PHP version (%VERSION%) is lower than the minimal required 5.3.0!"
+ NO_SCRIPT_TITLE: "JavaScript is required for this application."
NO_SCRIPT_DESC: |
JavaScript support is not available in your browser.
Please enable JavaScript support in your browser settings and retry.
- NO_COOKIE_TITLE: "Cookies support is required for this application."
+ NO_COOKIE_TITLE: "Cookies support is required for this application."
NO_COOKIE_DESC: |
Cookies support is not available in your browser.
Please enable Cookie support in your browser settings and retry.
- BAD_BROWSER_TITLE: "Your browser is outdated."
+ BAD_BROWSER_TITLE: "Your browser is outdated."
BAD_BROWSER_DESC: |
To use all the features of the application,
download and install one of these browsers:
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/ar_SA.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/ar_SA.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/ar_SA.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/ar_SA.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/bg_BG.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/bg_BG.yml
similarity index 99%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/bg_BG.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/bg_BG.yml
index 53bbc3df1355af3b1818d979b08bcc642f77c30d..90fd99ac42812bacebcdca08894cd6f59d704523 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/bg_BG.yml
+++ b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/bg_BG.yml
@@ -314,7 +314,7 @@ bg_BG:
LABEL_CODE: "Код"
BUTTON_TEST: "Тест"
POPUPS_FILTER:
- TITLE_CREATE_FILTER: "Въздай филтър?"
+ TITLE_CREATE_FILTER: "Създай филтър?"
TITLE_EDIT_FILTER: "Обнови филтъра?"
FILTER_NAME: "Име"
LEGEND_CONDITIONS: "Условия"
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/cs_CZ.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/cs_CZ.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/cs_CZ.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/cs_CZ.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/da_DK.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/da_DK.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/da_DK.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/da_DK.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/de_DE.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/de_DE.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/de_DE.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/de_DE.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/el_GR.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/el_GR.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/el_GR.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/el_GR.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/en_GB.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/en_GB.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/en_GB.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/en_GB.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/en_US.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/en_US.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/en_US.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/en_US.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/es_ES.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/es_ES.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/es_ES.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/es_ES.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/et_EE.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/et_EE.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/et_EE.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/et_EE.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/fa_IR.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/fa_IR.yml
similarity index 99%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/fa_IR.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/fa_IR.yml
index 76c95e25da2b18d3ffb2252441e95fdc134df94b..63429dbebdbfe0188b407314ceeb26d17a82098e 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/fa_IR.yml
+++ b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/fa_IR.yml
@@ -145,11 +145,13 @@ fa_IR:
PRINT_LABEL_ATTACHMENTS: "پیوستها"
MESSAGE_LOADING: "در حال بارگذاری"
MESSAGE_VIEW_DESC: "پیام را در لیست جهت مشاهده انتخاب کنید"
+ MESSAGE_VIEW_MOVE_DESC: "بر روی نام شاخه در پنل سمت راست جهت انتخاب مقصد کلیک کنید"
PGP_PASSWORD_INPUT_PLACEHOLDER: "گذرواژه"
PGP_SIGNED_MESSAGE_DESC: "پیام توسط OpenPGP امضاء شد (برای بررسی کلیک کنید)"
PGP_ENCRYPTED_MESSAGE_DESC: "پیام توسط OpenPGP رمزنگاری شد (برای خارج شدن از حالت رمز کلیک کنید)"
LINK_DOWNLOAD_AS_ZIP: "دریافت با پسوند zip"
LINK_SAVE_TO_OWNCLOUD: "ذخیره در OwnCloud"
+ LINK_SAVE_TO_CLOUD: "در فضای ابری ذخیره کن"
LINK_SAVE_TO_DROPBOX: "ذخیره در Dropbox"
READ_RECEIPT:
SUBJECT: "برگرداندن گیرنده (نمایش داده شد) - %SUBJECT%"
@@ -580,6 +582,7 @@ fa_IR:
TITLE_PUBLIC: "عمومی"
DELETING_ASK: "اطمینان دارید؟"
GENERATE_ONLY_HTTPS: "تنها HTTPS"
+ LABEL_ALLOW_DRAFT_AUTOSAVE: "ذخیره خودکار پیشنویس"
SHORTCUTS_HELP:
LEGEND_SHORTCUTS_HELP: "راهنمای میانبرهای کیبرد"
TAB_MAILBOX: "صندوق پستی"
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/fi_FI.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/fi_FI.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/fi_FI.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/fi_FI.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/fr_FR.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/fr_FR.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/fr_FR.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/fr_FR.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/hu_HU.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/hu_HU.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/hu_HU.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/hu_HU.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/id_ID.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/id_ID.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/id_ID.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/id_ID.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/is_IS.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/is_IS.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/is_IS.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/is_IS.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/it_IT.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/it_IT.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/it_IT.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/it_IT.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/ja_JP.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/ja_JP.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/ja_JP.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/ja_JP.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/ko_KR.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/ko_KR.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/ko_KR.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/ko_KR.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/lt_LT.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/lt_LT.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/lt_LT.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/lt_LT.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/lv_LV.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/lv_LV.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/lv_LV.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/lv_LV.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/nb_NO.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/nb_NO.yml
similarity index 99%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/nb_NO.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/nb_NO.yml
index ea528954dcae9678a00dbb93bc72df79765745f7..ec62d4253706d6ddd01700869c26f8ad30f1843b 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/nb_NO.yml
+++ b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/nb_NO.yml
@@ -673,7 +673,7 @@ nb_NO:
CANT_CREATE_FOLDER: "Klarte ikke å lage mappe"
CANT_RENAME_FOLDER: "Klarte ikke å endre navn på mappe"
CANT_DELETE_FOLDER: "Klarte ikke å slette mappe"
- CANT_DELETE_NON_EMPTY_FOLDER: "Klarte ikke å slette mappe med innhold"
+ CANT_DELETE_NON_EMPTY_FOLDER: "Du må slette mappeinnholdet før du kan slette mappa"
CANT_SUBSCRIBE_FOLDER: "Klarte ikke å abonnere på mappe"
CANT_UNSUBSCRIBE_FOLDER: "Klarte ikke å avslutte abonnement"
CANT_SAVE_SETTINGS: "Klarte ikke å lagre innstillinger"
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/nl_NL.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/nl_NL.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/nl_NL.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/nl_NL.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/pl_PL.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/pl_PL.yml
similarity index 63%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/pl_PL.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/pl_PL.yml
index 5fa1378ac4761ab8165f0e8279c16f6b348fe44b..0592e8efbd8099e7f5b110edc55abeed86249376 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/pl_PL.yml
+++ b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/pl_PL.yml
@@ -5,12 +5,12 @@ pl_PL:
LABEL_PASSWORD: "Hasło"
LABEL_SIGN_ME: "Zapamiętaj mnie"
LABEL_VERIFICATION_CODE: "Kod weryfikujący"
- LABEL_DONT_ASK_VERIFICATION_CODE: "Nie pytaj o kod przez 2 tygodnie"
+ LABEL_DONT_ASK_VERIFICATION_CODE: "Nie pytaj o kod przez kolejne 2 tygodnie"
BUTTON_SIGN_IN: "Zaloguj"
TITLE_SIGN_IN_GOOGLE: "Zaloguj się przez Google"
TITLE_SIGN_IN_FACEBOOK: "Zaloguj się przez Facebook"
TITLE_SIGN_IN_TWITTER: "Zaloguj się przez Twitter"
- LABEL_FORGOT_PASSWORD: "Zapomniałem hasło"
+ LABEL_FORGOT_PASSWORD: "Zapomniałem(-am) hasło"
LABEL_REGISTRATION: "Rejestracja"
TOP_TOOLBAR:
BUTTON_ADD_ACCOUNT: "Dodaj konto"
@@ -23,16 +23,16 @@ pl_PL:
SEARCH:
MAIN_INPUT_PLACEHOLDER: "Szukaj"
TITLE_ADV: "Wyszukiwanie zaawansowane"
- LABEL_ADV_FROM: "Od:"
- LABEL_ADV_TO: "Do:"
- LABEL_ADV_SUBJECT: "Temat:"
- LABEL_ADV_TEXT: "Tekst:"
- LABEL_ADV_HAS_ATTACHMENT: "Załącznik"
- LABEL_ADV_HAS_ATTACHMENTS: "Ma załączniki"
+ LABEL_ADV_FROM: "Od"
+ LABEL_ADV_TO: "Do"
+ LABEL_ADV_SUBJECT: "Temat"
+ LABEL_ADV_TEXT: "Tekst"
+ LABEL_ADV_HAS_ATTACHMENT: "Posiada załącznik"
+ LABEL_ADV_HAS_ATTACHMENTS: "Posiada załączniki"
LABEL_ADV_FLAGGED: "Oznaczona"
LABEL_ADV_UNSEEN: "Nieprzeczytana"
- LABEL_ADV_DATE: "Data:"
- LABEL_ADV_DATE_ALL: "wszystkie"
+ LABEL_ADV_DATE: "Data"
+ LABEL_ADV_DATE_ALL: "Wszystkie"
LABEL_ADV_DATE_3_DAYS: "do 3 dni"
LABEL_ADV_DATE_7_DAYS: "do tygodnia"
LABEL_ADV_DATE_MONTH: "do miesiąca"
@@ -47,7 +47,7 @@ pl_PL:
LOADING: "Ładowanie..."
GALLERY_PREV: "Poprzedni (strzałka w lewo)"
GALLERY_NEXT: "Następny (strzałka w prawo)"
- GALLERY_COUNTER: "%curr% z: %total%"
+ GALLERY_COUNTER: "%curr% z %total%"
IMAGE_ERROR: "Nie można załadować obrazu ."
AJAX_ERROR: "Nie można załadować zawartości ."
FOLDER_LIST:
@@ -56,22 +56,22 @@ pl_PL:
BUTTON_NEW_MESSAGE: "Nowa wiadomość"
INBOX_NAME: "Odebrane"
SENT_NAME: "Wysłane"
- DRAFTS_NAME: "Wersje robocze"
- SPAM_NAME: "Wiadomości śmieci - SPAM"
+ DRAFTS_NAME: "Szkice"
+ SPAM_NAME: "Spam"
TRASH_NAME: "Kosz"
ARCHIVE_NAME: "Archiwum"
QUOTA:
- TITLE: "Wykorzystanie miejsca"
+ TITLE: "Wykorzystane miejsce"
MESSAGE_LIST:
- BUTTON_RELOAD: "Odśwież"
- BUTTON_MOVE_TO: "Przenieś"
+ BUTTON_RELOAD: "Odśwież listę wiadomości"
+ BUTTON_MOVE_TO: "Przenieś do"
BUTTON_DELETE: "Usuń"
BUTTON_ARCHIVE: "Archiwizuj"
BUTTON_SPAM: "Oznacz jako SPAM"
BUTTON_NOT_SPAM: "Oznacz jako pożądane"
BUTTON_EMPTY_FOLDER: "Usuń zawartość folderu"
- BUTTON_MULTY_FORWARD: "Przekaż dalej"
- BUTTON_DELETE_WITHOUT_MOVE: "Usuń (pernamentnie)"
+ BUTTON_MULTY_FORWARD: "Przekaż dalej jako załącznik(i)"
+ BUTTON_DELETE_WITHOUT_MOVE: "Usuń permanentnie"
BUTTON_MORE: "Więcej"
MENU_SET_SEEN: "Oznacz jako przeczytane"
MENU_SET_ALL_SEEN: "Oznacz wszystkie jako przeczytane"
@@ -85,18 +85,18 @@ pl_PL:
MENU_SELECT_SEEN: "Przeczytane"
MENU_SELECT_FLAGGED: "Oznaczone jako ważne"
MENU_SELECT_UNFLAGGED: "Oznaczone jako nieważne"
- EMPTY_LIST: "Pusta lista"
- EMPTY_SEARCH_LIST: "Brak wiadomości spełniających kryteria wyszukiwania"
- SEARCH_RESULT_FOR: "Wyniki wyszukiwania dla: \"%SEARCH%\""
+ EMPTY_LIST: "Brak wiadomości."
+ EMPTY_SEARCH_LIST: "Brak wiadomości spełniających kryteria wyszukiwania."
+ SEARCH_RESULT_FOR: "Wyniki wyszukiwania dla \"%SEARCH%\""
BACK_TO_MESSAGE_LIST: "powrót do listy wiadomości"
LIST_LOADING: "Ładowanie..."
EMPTY_SUBJECT_TEXT: "(Brak tematu)"
- PUT_MESSAGE_HERE: "Przeciągnij tutaj wiadomość, żeby zobaczyć ją na liście"
- TODAY_AT: "dzisiaj: %TIME%"
- YESTERDAY_AT: "wczoraj: %TIME%"
+ PUT_MESSAGE_HERE: "Przeciągnij wiadomość tutaj, żeby zobaczyć ją na liście"
+ TODAY_AT: "dzisiaj o %TIME%"
+ YESTERDAY_AT: "wczoraj o %TIME%"
SEARCH_PLACEHOLDER: "Szukaj"
NEW_MESSAGE_NOTIFICATION: "Masz: %COUNT% now(-ą,-e,-ych) wiadomości!"
- QUOTA_SIZE: "Wykorzystano: %SIZE% (%PROC%%) z: %LIMIT% "
+ QUOTA_SIZE: "Wykorzystano %SIZE% (%PROC%%) z %LIMIT% "
MESSAGE:
BUTTON_EDIT: "Edytuj"
BUTTON_BACK: "Wstecz"
@@ -106,22 +106,22 @@ pl_PL:
BUTTON_ARCHIVE: "Archiwizuj"
BUTTON_SPAM: "Oznacz jako niechcianą"
BUTTON_NOT_SPAM: "Oznacz jako pożądaną"
- BUTTON_MOVE_TO: "Przenieś"
+ BUTTON_MOVE_TO: "Przenieś do"
BUTTON_MORE: "Więcej"
BUTTON_REPLY: "Odpowiedz"
BUTTON_REPLY_ALL: "Odpowiedz wszystkim"
BUTTON_FORWARD: "Przekaż dalej"
- BUTTON_FORWARD_AS_ATTACHMENT: "Przekaż jako załącznik"
+ BUTTON_FORWARD_AS_ATTACHMENT: "Przekaż dalej jako załącznik"
BUTTON_EDIT_AS_NEW: "Zredaguj jako nową wiadomość"
- BUTTON_SHOW_IMAGES: "Wyświetl obrazy"
- BUTTON_NOTIFY_READ_RECEIPT: "Nadawca prosi o potwierdzenie odczytania tej wiadomości"
+ BUTTON_SHOW_IMAGES: "Wyświetl zewnętrzne obrazy"
+ BUTTON_NOTIFY_READ_RECEIPT: "Nadawca prosi o potwierdzenie odczytania tej wiadomości."
BUTTON_IN_NEW_WINDOW: "Wyświetl w osobnym oknie"
BUTTON_THREAD_LIST: "Lista wątków"
BUTTON_THREAD_PREV: "Poprzedni"
BUTTON_THREAD_NEXT: "Następny"
BUTTON_THREAD_MORE: "Więcej wiadomości"
MENU_HEADERS: "Pokaż nagłówki wiadomości"
- MENU_VIEW_ORIGINAL: "Pokaż zródło"
+ MENU_VIEW_ORIGINAL: "Pokaż źródło"
MENU_DOWNLOAD_ORIGINAL: "Pobierz jako plik eml"
MENU_FILTER_SIMILAR: "Filtruj podobne wiadomości"
MENU_PRINT: "Drukuj"
@@ -129,32 +129,34 @@ pl_PL:
LABEL_SUBJECT: "Temat"
LABEL_DATE: "Data"
LABEL_FROM: "Od"
- LABEL_FROM_SHORT: "Od"
+ LABEL_FROM_SHORT: "od"
LABEL_TO: "Do"
- LABEL_TO_SHORT: "Do"
+ LABEL_TO_SHORT: "do"
LABEL_CC: "Kopia"
- LABEL_BCC: "Ukr. kopia"
- LABEL_REPLY_TO: "Zwrot do"
+ LABEL_BCC: "Kopia ukryta"
+ LABEL_REPLY_TO: "Odpisz do"
PRINT_LABEL_FROM: "Od"
PRINT_LABEL_TO: "Do"
PRINT_LABEL_CC: "Kopia"
- PRINT_LABEL_BCC: "Ukr. kopia"
- PRINT_LABEL_REPLY_TO: "Zwrot do"
+ PRINT_LABEL_BCC: "Kopia ukryta"
+ PRINT_LABEL_REPLY_TO: "Odpisz do"
PRINT_LABEL_DATE: "Data"
PRINT_LABEL_SUBJECT: "Temat"
PRINT_LABEL_ATTACHMENTS: "Załączniki"
MESSAGE_LOADING: "Ładowanie wiadomości..."
- MESSAGE_VIEW_DESC: "Wybierz wiadomość do wyświetlenia"
+ MESSAGE_VIEW_DESC: "Wybierz wiadomość do wyświetlenia."
+ MESSAGE_VIEW_MOVE_DESC: "Kliknij nazwę folderu w lewym panelu, aby wybrać folder docelowy."
PGP_PASSWORD_INPUT_PLACEHOLDER: "Hasło"
- PGP_SIGNED_MESSAGE_DESC: "Podpisana"
- PGP_ENCRYPTED_MESSAGE_DESC: "Zaszyfrowana"
+ PGP_SIGNED_MESSAGE_DESC: "Wiadomość podpisana OpenPGP (kliknij aby zweryfikować)"
+ PGP_ENCRYPTED_MESSAGE_DESC: "Wiadomość zaszyfrowana OpenPGP (kliknij aby odszyfrować)"
LINK_DOWNLOAD_AS_ZIP: "Pobierz jako plik zip"
LINK_SAVE_TO_OWNCLOUD: "Zapisz w ownCloud"
+ LINK_SAVE_TO_CLOUD: "Zapisz w chmurze"
LINK_SAVE_TO_DROPBOX: "Zapisz w Dropbox-ie"
READ_RECEIPT:
- SUBJECT: "Potwierdzenie wyświetlenia wiadomości o tytule: %SUBJECT%"
+ SUBJECT: "Żądaj potwierdzenia wyświetlenia wiadomości - %SUBJECT%"
BODY: |
- Potwierdzenie wyświetlenia wiadomości wysłanej na adres: %READ-RECEIPT%.
+ Potwierdzenie wyświetlenia wiadomości wysłanej na adres %READ-RECEIPT%.
Uwaga: Otrzymanie tego potwierdzenia jest dowodem na to, że wiadomość została wyświetlona na komputerze odbiorcy.
Nie ma jednak żadnej gwarancji, że odbiorca faktycznie zapoznał się z jej treścią.
@@ -175,15 +177,15 @@ pl_PL:
EMPTY_SEARCH: "Nie znaleziono żadnych kontaktów"
CLEAR_SEARCH: "Wyczyść wyniki"
CONTACT_VIEW_DESC: "Wybierz kontakt do wyświetlenia"
- LABEL_DISPLAY_NAME: "Nazwa:"
- LABEL_EMAIL: "Adres e-mail:"
- LABEL_PHONE: "Telefon:"
- LABEL_WEB: "Strona WWW:"
- LABEL_BIRTHDAY: "Urodziny:"
+ LABEL_DISPLAY_NAME: "Nazwa wyświetlana"
+ LABEL_EMAIL: "Adres e-mail"
+ LABEL_PHONE: "Telefon"
+ LABEL_WEB: "Strona WWW"
+ LABEL_BIRTHDAY: "Urodziny"
LINK_ADD_EMAIL: "Dodaj adres e-mail"
LINK_ADD_PHONE: "Dodaj nr telefonu"
LINK_BIRTHDAY: "Urodziny"
- PLACEHOLDER_ENTER_DISPLAY_NAME: "Nazwa"
+ PLACEHOLDER_ENTER_DISPLAY_NAME: "Nazwa wyświetlana"
PLACEHOLDER_ENTER_LAST_NAME: "Nazwisko"
PLACEHOLDER_ENTER_FIRST_NAME: "Imię"
PLACEHOLDER_ENTER_NICK_NAME: "Pseudonim"
@@ -194,7 +196,7 @@ pl_PL:
ADD_MENU_NOTES: "Notatki"
ADD_MENU_EMAIL: "Adres e-mail"
ADD_MENU_PHONE: "Telefon"
- ADD_MENU_URL: "Adres www"
+ ADD_MENU_URL: "Adres URL"
ADD_MENU_ADDRESS: "Adres"
ADD_MENU_BIRTHDAY: "Urodziny"
ADD_MENU_TAGS: "Tagi"
@@ -205,8 +207,8 @@ pl_PL:
TITLE_FROM: "Od"
TITLE_TO: "Do"
TITLE_CC: "Kopia"
- TITLE_BCC: "Ukr. kopia"
- TITLE_REPLY_TO: "Zwrot do"
+ TITLE_BCC: "Kopia ukryta"
+ TITLE_REPLY_TO: "Odpisz do"
TITLE_SUBJECT: "Temat"
LINK_SHOW_INPUTS: "Pokaż wszystkie pola"
BUTTON_SEND: "Wyślij"
@@ -214,185 +216,185 @@ pl_PL:
BUTTON_DELETE: "Usuń"
BUTTON_CANCEL: "Anuluj"
BUTTON_MINIMIZE: "Minimalizuj"
- SAVED_TIME: "Zapisane: %TIME%"
- SAVED_ERROR_ON_SEND: "Wiadomość została wysłana, ale nie została zapisana w folderze: Wysłane"
+ SAVED_TIME: "Zapisano o %TIME%"
+ SAVED_ERROR_ON_SEND: "Wiadomość została wysłana, ale nie została zapisana w folderze Wysłane"
DISCARD_UNSAVED_DATA: "Odrzucić niezapisane dane?"
ATTACH_FILES: "Dodaj załącznik"
ATTACH_DROP_FILES_DESC: "Przeciągnij pliki tutaj"
ATTACH_ITEM_CANCEL: "Anuluj"
DROPBOX: "Dropbox"
GOOGLE_DRIVE: "Dysk Google"
- REPLY_MESSAGE_TITLE: "%DATETIME% - %EMAIL%"
- FORWARD_MESSAGE_TOP_TITLE: "-------- Przekierowana wiadomość -------"
- FORWARD_MESSAGE_TOP_FROM: "Od:"
- FORWARD_MESSAGE_TOP_TO: "Do:"
- FORWARD_MESSAGE_TOP_CC: "Kopia do:"
- FORWARD_MESSAGE_TOP_SENT: "Wysłany:"
- FORWARD_MESSAGE_TOP_SUBJECT: "Temat:"
+ REPLY_MESSAGE_TITLE: "%DATETIME%, %EMAIL%"
+ FORWARD_MESSAGE_TOP_TITLE: "-------- Wiadomość przekazana -------"
+ FORWARD_MESSAGE_TOP_FROM: "Od"
+ FORWARD_MESSAGE_TOP_TO: "Do"
+ FORWARD_MESSAGE_TOP_CC: "Kopia do"
+ FORWARD_MESSAGE_TOP_SENT: "Wysłano"
+ FORWARD_MESSAGE_TOP_SUBJECT: "Temat"
EMPTY_TO_ERROR_DESC: "Wprowadź co najmniej jednego odbiorcę"
- NO_ATTACHMENTS_HERE_DESC: "Brak załączników"
- ATTACHMENTS_ERROR_DESC: "Ostrzeżenie! Nie wszystkie załaczniki zostały przesłane"
- ATTACHMENTS_UPLOAD_ERROR_DESC: "Nie przesłano jeszcze wszystkich załączników"
- BUTTON_REQUEST_READ_RECEIPT: "Potwierdzenie wyświetlenia wiadomości"
+ NO_ATTACHMENTS_HERE_DESC: "Brak załączników."
+ ATTACHMENTS_ERROR_DESC: "Ostrzeżenie! Nie wszystkie załączniki zostały przesłane na serwer."
+ ATTACHMENTS_UPLOAD_ERROR_DESC: "Jeszcze nie wszystkie załączniki zostały przesłane na serwer."
+ BUTTON_REQUEST_READ_RECEIPT: "Żądaj potwierdzenia wyświetlenia wiadomości"
BUTTON_MARK_AS_IMPORTANT: "Oznacz jako ważną"
BUTTON_OPEN_PGP: "OpenPGP (tylko wiadomości tekstowe)"
- BUTTON_REQUEST_DSN: "Potwierdzenie dostarczenia wiadomości"
+ BUTTON_REQUEST_DSN: "Żądaj potwierdzenia dostarczenia wiadomości"
POPUPS_WELCOME_PAGE:
BUTTON_CLOSE: "Zamknij"
POPUPS_ASK:
BUTTON_YES: "Tak"
BUTTON_NO: "Nie"
DESC_WANT_CLOSE_THIS_WINDOW: "Na pewno zamknąć to okno?"
- DESC_WANT_DELETE_MESSAGES: "Na pewno usunąć wiadomość(-i)?"
+ DESC_WANT_DELETE_MESSAGES: "Na pewno usunąć wiadomość(-ci)?"
POPUPS_LANGUAGES:
TITLE_LANGUAGES: "Wybierz język"
POPUPS_ADD_ACCOUNT:
- TITLE_ADD_ACCOUNT: "Dodawanie konta"
+ TITLE_ADD_ACCOUNT: "Czy dodać konto?"
BUTTON_ADD_ACCOUNT: "Dodaj"
- TITLE_UPDATE_ACCOUNT: "Aktualizacja konta"
+ TITLE_UPDATE_ACCOUNT: "Czy zaktualizować konto?"
BUTTON_UPDATE_ACCOUNT: "Aktualizuj"
POPUPS_IDENTITY:
- TITLE_ADD_IDENTITY: "Dodawanie tożsamości"
- TITLE_UPDATE_IDENTITY: "Aktualizacja tożsamości"
+ TITLE_ADD_IDENTITY: "Czy dodać tożsamość?"
+ TITLE_UPDATE_IDENTITY: "Czy zaktualizować tożsamość?"
BUTTON_ADD_IDENTITY: "Dodaj"
BUTTON_UPDATE_IDENTITY: "Aktualizuj"
- LABEL_EMAIL: "Adres e-mail:"
- LABEL_NAME: "Nazwa:"
- LABEL_REPLY_TO: "Zwrot do"
- LABEL_SIGNATURE: "Podpis:"
+ LABEL_EMAIL: "Adres e-mail"
+ LABEL_NAME: "Nazwa"
+ LABEL_REPLY_TO: "Odpisz do"
+ LABEL_SIGNATURE: "Podpis"
LABEL_CC: "Kopia"
- LABEL_BCC: "Ukr. kopia"
- LABEL_SIGNATURE_INSERT_BEFORE: "Umieść podpis przed cytowanym tekstem"
+ LABEL_BCC: "Kopia ukryta"
+ LABEL_SIGNATURE_INSERT_BEFORE: "Umieszczaj ten podpis przed cytowanym tekstem w odpowiedziach"
POPUPS_CREATE_FOLDER:
- TITLE_CREATE_FOLDER: "Tworzenie folderu"
- LABEL_NAME: "Nazwa folderu:"
- LABEL_PARENT: "Folder nadrzędny:"
+ TITLE_CREATE_FOLDER: "Czy stworzyć folder?"
+ LABEL_NAME: "Nazwa folderu"
+ LABEL_PARENT: "Folder nadrzędny"
BUTTON_CREATE: "Utwórz"
BUTTON_CANCEL: "Anuluj"
BUTTON_CLOSE: "Zamknij"
TITLE_CREATING_PROCESS: "Tworzenie folderu"
POPUPS_CLEAR_FOLDER:
- TITLE_CLEAR_FOLDER: "Usuwanie wszystkich wiadomości z folderu"
+ TITLE_CLEAR_FOLDER: "Czy usunąć wszystkie wiadomości z folderu?"
BUTTON_CLEAR: "Usuń wszystkie"
BUTTON_CANCEL: "Anuluj"
BUTTON_CLOSE: "Zamknij"
DANGER_DESC_WARNING: "Ostrzeżenie!"
- DANGER_DESC_HTML_1: "Wszystkie wiadomości w folderze: %FOLDER% , zostaną bezpowrotnie usunięte!"
- DANGER_DESC_HTML_2: "Po rozpoczęciu, nie można przerwać lub anulować zadania."
+ DANGER_DESC_HTML_1: "Wszystkie wiadomości w folderze %FOLDER% zostaną bezpowrotnie usunięte!"
+ DANGER_DESC_HTML_2: "Po rozpoczęciu nie będzie możliwe przerwanie lub anulowanie zadania."
TITLE_CLEARING_PROCESS: "Trwa usuwanie wszystkich wiadomości z folderu..."
POPUPS_IMPORT_OPEN_PGP_KEY:
TITLE_IMPORT_OPEN_PGP_KEY: "Importowanie klucza OpenPGP"
BUTTON_IMPORT_OPEN_PGP_KEY: "Importuj"
POPUPS_VIEW_OPEN_PGP_KEY:
- TITLE_VIEW_OPEN_PGP_KEY: "Klucz OpenPGP"
+ TITLE_VIEW_OPEN_PGP_KEY: "Podgląd klucza OpenPGP"
BUTTON_SELECT: "Zaznacz"
BUTTON_CLOSE: "Zamknij"
POPUPS_GENERATE_OPEN_PGP_KEYS:
TITLE_GENERATE_OPEN_PGP_KEYS: "Generowanie klucza OpenPGP"
- LABEL_EMAIL: "Adres e-mail:"
- LABEL_NAME: "Imię i nazwisko:"
- LABEL_PASSWORD: "Hasło:"
- LABEL_KEY_BIT_LENGTH: "Długość klucza:"
+ LABEL_EMAIL: "Adres e-mail"
+ LABEL_NAME: "Nazwa"
+ LABEL_PASSWORD: "Hasło"
+ LABEL_KEY_BIT_LENGTH: "Długość klucza"
BUTTON_GENERATE_OPEN_PGP_KEYS: "Generuj"
POPUPS_COMPOSE_OPEN_PGP:
- TITLE_COMPOSE_OPEN_PGP: "Podpisywanie/szyfrowanie"
+ TITLE_COMPOSE_OPEN_PGP: "Podpisywanie/szyfrowanie OpenPGP"
LABEL_SIGN: "Podpisz"
- LABEL_ENCRYPT: "Szyfruj"
- LABEL_PASSWORD: "Hasło:"
+ LABEL_ENCRYPT: "Zaszyfruj"
+ LABEL_PASSWORD: "Hasło"
BUTTON_SIGN: "Podpisz"
- BUTTON_ENCRYPT: "Szyfruj"
- BUTTON_SIGN_AND_ENCRYPT: "Podpisz i szyfruj"
+ BUTTON_ENCRYPT: "Zaszyfruj"
+ BUTTON_SIGN_AND_ENCRYPT: "Podpisz i zaszyfruj"
POPUPS_MESSAGE_OPEN_PGP:
- TITLE_MESSAGE_OPEN_PGP: "OpenPGP Decrypt"
+ TITLE_MESSAGE_OPEN_PGP: "Odszyfrowywanie OpenPGP"
LABEL_KEY: "Klucz prywatny"
LABEL_PASSWORD: "Password"
- BUTTON_DECRYPT: "Decrypt"
+ BUTTON_DECRYPT: "Odszyfruj"
POPUPS_TWO_FACTOR_TEST:
- TITLE_TEST_CODE: "Test autoryzacji dwuskładnikowej"
+ TITLE_TEST_CODE: "Test autoryzacji 2-etapowej"
LABEL_CODE: "Kod"
BUTTON_TEST: "Testuj"
POPUPS_FILTER:
- TITLE_CREATE_FILTER: "Tworzenie filtra"
- TITLE_EDIT_FILTER: "Aktualizacja filtra"
+ TITLE_CREATE_FILTER: "Czy stworzyć filtr?"
+ TITLE_EDIT_FILTER: "Czy zaktualizować filtr?"
FILTER_NAME: "Nazwa"
LEGEND_CONDITIONS: "Warunki"
LEGEND_ACTIONS: "Działania"
BUTTON_DONE: "Gotowe"
BUTTON_ADD_CONDITION: "Dodaj warunek"
SELECT_ACTION_NONE: "Brak"
- SELECT_ACTION_MOVE_TO: "Przenieś"
+ SELECT_ACTION_MOVE_TO: "Przenieś do"
SELECT_ACTION_FORWARD_TO: "Prześlij dalej"
SELECT_ACTION_REJECT: "Odrzuć"
SELECT_ACTION_VACATION_MESSAGE: "Wiadomość urlopowa"
- SELECT_ACTION_DISCARD: "Usuń"
- SELECT_FIELD_FROM: "Pole 'Od'"
- SELECT_FIELD_RECIPIENTS: "Pole 'Kopia' lub 'Ukr. kopia'"
- SELECT_FIELD_SUBJECT: "Pole 'Temat'"
+ SELECT_ACTION_DISCARD: "Porzuć"
+ SELECT_FIELD_FROM: "Od"
+ SELECT_FIELD_RECIPIENTS: "Adresaci (Do lub DW)"
+ SELECT_FIELD_SUBJECT: "Temat"
SELECT_FIELD_HEADER: "Nagłówek"
SELECT_FIELD_SIZE: "Rozmiar"
SELECT_TYPE_CONTAINS: "zawiera"
SELECT_TYPE_NOT_CONTAINS: "nie zawiera"
- SELECT_TYPE_MATCHES: "zawiera (*,?)"
- SELECT_TYPE_NOT_MATCHES: "nie zawiera (*,?)"
- SELECT_TYPE_REGEXP: "Wyrażenie regularne:"
- SELECT_TYPE_NOT_REGEXP: "Niepoprawne wyrażenie regularne:"
- SELECT_TYPE_EQUAL_TO: "Zawiera:"
- SELECT_TYPE_NOT_EQUAL_TO: "Nie zawiera:"
+ SELECT_TYPE_MATCHES: "zawiera (*, ?)"
+ SELECT_TYPE_NOT_MATCHES: "nie zawiera (*, ?)"
+ SELECT_TYPE_REGEXP: "Wyrażenie regularne"
+ SELECT_TYPE_NOT_REGEXP: "Niepoprawne wyrażenie regularne"
+ SELECT_TYPE_EQUAL_TO: "równy"
+ SELECT_TYPE_NOT_EQUAL_TO: "nierówny"
SELECT_TYPE_OVER: "powyżej"
SELECT_TYPE_UNDER: "poniżej"
SELECT_MATCH_ANY: "Spełnia dowolny z warunków"
SELECT_MATCH_ALL: "Spełnia wszystkie warunki"
MARK_AS_READ_LABEL: "Oznacz jako przeczytane"
- REPLY_INTERVAL_LABEL: "Liczba dni, po których wysłać odp."
+ REPLY_INTERVAL_LABEL: "Interwał odpowiedzi (dni)"
KEEP_LABEL: "Zachowaj"
STOP_LABEL: "Nie zatrzymuj przetwarzania reguł"
EMAIL_LABEL: "Adres e-mail"
VACATION_SUBJECT_LABEL: "Temat (opcjonalnie)"
VACATION_MESSAGE_LABEL: "Wiadomość"
VACATION_RECIPIENTS_LABEL: "Odbiorcy (rodzielone przecinkami)"
- REJECT_MESSAGE_LABEL: "Powód odrzucenia"
+ REJECT_MESSAGE_LABEL: "Odrzuć wiadomość"
ALL_INCOMING_MESSAGES_DESC: "Wszystkie przychodzące wiadomości"
POPUPS_SYSTEM_FOLDERS:
- TITLE_SYSTEM_FOLDERS: "Wybieranie folderów systemowych"
- SELECT_CHOOSE_ONE: "wybierz"
+ TITLE_SYSTEM_FOLDERS: "Wybierz foldery systemowe"
+ SELECT_CHOOSE_ONE: "Wybierz"
SELECT_UNUSE_NAME: "nie używaj"
- LABEL_SENT: "Wysłane:"
- LABEL_DRAFTS: "Wersje robocze:"
- LABEL_SPAM: "Niechciane:"
- LABEL_TRASH: "Kosz:"
- LABEL_ARCHIVE: "Archiwum:"
+ LABEL_SENT: "Wysłane"
+ LABEL_DRAFTS: "Szkice"
+ LABEL_SPAM: "Spam"
+ LABEL_TRASH: "Kosz"
+ LABEL_ARCHIVE: "Archiwum"
BUTTON_CANCEL: "Anuluj"
BUTTON_CLOSE: "Zamknij"
NOTIFICATION_SENT: |
- Nie wybrano folderu: "Wysłane", do którego przenoszone są wysłane wiadomości.
- Jeżeli wysyłane wiadomości nie mają być przechowywane, proszę zaznaczyć opcję: "Nie używaj".
- NOTIFICATION_DRAFTS: "Nie wybrano folderu: \"Wersje robocze\", do którego są zapisywane wiadomości w trakcie ich tworzenia."
+ Nie wybrano folderu systemowego "Wysłane", do którego przenoszone są wysłane wiadomości.
+ Jeżeli wysyłane wiadomości nie mają być przechowywane, proszę zaznaczyć opcję "Nie używaj".
+ NOTIFICATION_DRAFTS: "Nie wybrano folderu \"Wersje robocze\", do którego są zapisywane wiadomości w trakcie ich tworzenia."
NOTIFICATION_SPAM: |
- Nie wybrano folderu: "Niechciane", do którego przenoszone są niepożadane wiadomości.
- Jeżeli niechciane wiadomości mają być usuwane na stałe, proszę o zaznaczenie opcji: "Nie używaj".
+ Nie wybrano folderu "Spam", do którego przenoszone są niepożądane wiadomości.
+ Jeżeli niechciane wiadomości mają być usuwane na stałe, proszę o zaznaczenie opcji "Nie używaj".
NOTIFICATION_TRASH: |
- Nie wybrano folderu: "Kosz", do którego przenoszone są wszystkie usunięte wiadomości.
- Jeżeli wiadomości mają być usuwane na stałe, proszę o zaznaczenie opcji: "Nie używaj".
+ Nie wybrano folderu "Kosz", do którego przenoszone są wszystkie usunięte wiadomości.
+ Jeżeli wiadomości mają być usuwane na stałe, proszę o zaznaczenie opcji "Nie używaj".
NOTIFICATION_ARCHIVE: "Nie został wybrany folder \"Archiwum\", zostanie użyty systemowy folder archiwizacji wiadomości."
POPUPS_TWO_FACTOR_CFG:
- LEGEND_TWO_FACTOR_AUTH: "Dwuskładnikowa autoryzacja"
- LABEL_ENABLE_TWO_FACTOR: "Włącz dwuskładnikową autoryzację"
- LABEL_TWO_FACTOR_USER: "Użytkownik:"
- LABEL_TWO_FACTOR_STATUS: "Status:"
- LABEL_TWO_FACTOR_SECRET: "Tajna fraza:"
- LABEL_TWO_FACTOR_BACKUP_CODES: "Kody zapasowe:"
+ LEGEND_TWO_FACTOR_AUTH: "Autoryzacja 2-etapowa (TOTP)"
+ LABEL_ENABLE_TWO_FACTOR: "Włącz autoryzację 2-etapową"
+ LABEL_TWO_FACTOR_USER: "Użytkownik"
+ LABEL_TWO_FACTOR_STATUS: "Status"
+ LABEL_TWO_FACTOR_SECRET: "Tajna fraza"
+ LABEL_TWO_FACTOR_BACKUP_CODES: "Kody zapasowe"
BUTTON_CREATE: "Utwórz nową frazę"
BUTTON_ACTIVATE: "Aktywuj"
BUTTON_CLEAR: "Wyczyść"
BUTTON_LOGOUT: "Wyloguj"
BUTTON_DONE: "Zamknij"
BUTTON_TEST: "Testuj"
- LINK_TEST: "Test"
+ LINK_TEST: "test"
BUTTON_SHOW_SECRET: "Pokaż frazę"
BUTTON_HIDE_SECRET: "Ukryj frazę"
- TWO_FACTOR_REQUIRE_DESC: "Twoje konto wymaga skonfigurowania dwuskładnikowej autoryzacji ."
- TWO_FACTOR_SECRET_CONFIGURED_DESC: "Skonfigurowana"
- TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC: "Nie skonfigurowana"
+ TWO_FACTOR_REQUIRE_DESC: "Twoje konto wymaga skonfigurowania autoryzacji 2-etapowej."
+ TWO_FACTOR_SECRET_CONFIGURED_DESC: "Skonfigurowano"
+ TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC: "Nie skonfigurowano"
TWO_FACTOR_SECRET_DESC: >-
Użyj tych informacji w usłudze Google Authenticator (lub innym kliencie TOTP),
używając poniższego kodu QR lub wpisując kod ręcznie.
@@ -403,17 +405,17 @@ pl_PL:
TITLES:
LOADING: "Ładowanie..."
LOGIN: "Login"
- MAILBOX: "Skrzynka Pocztowa"
+ MAILBOX: "Skrzynka Odbiorcza"
SETTINGS: "Ustawienia"
COMPOSE: "Utwórz"
UPLOAD:
ERROR_FILE_IS_TOO_BIG: "Plik jest za duży"
- ERROR_FILE_PARTIALLY_UPLOADED: "Z powodu nieokreślonego błędu, plik nie został przesłany w całości"
- ERROR_NO_FILE_UPLOADED: "Nie przesłano żadnego pliku"
- ERROR_MISSING_TEMP_FOLDER: "Brakuje pliku tymczasowego"
- ERROR_ON_SAVING_FILE: "Wystąpił nieoczekiwany błąd w trakcie przesyłania pliku"
+ ERROR_FILE_PARTIALLY_UPLOADED: "Z powodu nieokreślonego błędu plik nie został przesłany w całości"
+ ERROR_NO_FILE_UPLOADED: "Nie przesłano żadnego pliku na serwer"
+ ERROR_MISSING_TEMP_FOLDER: "Brak pliku tymczasowego"
+ ERROR_ON_SAVING_FILE: "Wystąpił nieoczekiwany błąd w trakcie przesyłania pliku na serwer"
ERROR_FILE_TYPE: "Nieprawidłowy typ pliku"
- ERROR_UNKNOWN: "Wystąpił nieznany błąd w trakcie przesyłania pliku"
+ ERROR_UNKNOWN: "Wystąpił nieznany błąd w trakcie przesyłania pliku na serwer"
EDITOR:
TEXT_SWITCHER_PLAINT_TEXT: "HTML <-> zwykły tekst"
TEXT_SWITCHER_RICH_FORMATTING: "Wzbogacony format tekstowy"
@@ -429,7 +431,7 @@ pl_PL:
LABEL_FILTERS_NAME: "Filtry"
LABEL_TEMPLATES_NAME: "Szablony"
LABEL_SECURITY_NAME: "Bezpieczeństwo"
- LABEL_SOCIAL_NAME: "Sieci społecznościowe"
+ LABEL_SOCIAL_NAME: "Media społecznościowe"
LABEL_THEMES_NAME: "Motywy"
LABEL_CHANGE_PASSWORD_NAME: "Hasło"
LABEL_OPEN_PGP_NAME: "OpenPGP"
@@ -439,39 +441,39 @@ pl_PL:
BUTTON_SAVE: "Zapisz"
BUTTON_ADD_FILTER: "Dodaj filtr"
BUTTON_DELETE: "Usuń"
- BUTTON_RAW_SCRIPT: "Utwórz własny skrypt użytkownika"
+ BUTTON_RAW_SCRIPT: "Użyj własnego skryptu użytkownika"
SUBNAME_NONE: "Brak"
SUBNAME_MOVE_TO: "Przenieś do \"%FOLDER%\""
SUBNAME_FORWARD_TO: "Przekaż do \"%EMAIL%\""
SUBNAME_REJECT: "Odrzuć"
SUBNAME_VACATION_MESSAGE: "Wiadomość urlopowa"
- SUBNAME_DISCARD: "Usuń"
+ SUBNAME_DISCARD: "Porzuć"
CAPABILITY_LABEL: "Możliwości"
LOADING_PROCESS: "Aktualizowanie listy filtrów"
DELETING_ASK: "Czy jesteś pewny(a)?"
CHACHES_NEED_TO_BE_SAVED_DESC: "Zmiany te muszą zostać zapisane na serwerze."
SETTINGS_IDENTITY:
LEGEND_IDENTITY: "Tożsamość"
- LABEL_DISPLAY_NAME: "Imię i nazwisko"
- LABEL_REPLY_TO: "Zwrot do"
+ LABEL_DISPLAY_NAME: "Nazwa"
+ LABEL_REPLY_TO: "Odpisz do"
LABEL_SIGNATURE: "Podpis"
- LABEL_ADD_SIGNATURE_TO_ALL: "Dadawaj podpis do wszystkich wiadomości"
+ LABEL_ADD_SIGNATURE_TO_ALL: "Dodawaj podpis do wszystkich wiadomości wychodzących"
SETTINGS_SECURITY:
LEGEND_SECURITY: "Bezpieczeństwo"
- LABEL_CONFIGURE_TWO_FACTOR: "Konfiguracja dwuskładnikowej autoryzacji"
- LABEL_AUTOLOGOUT: "Auto. wylogowanie:"
+ LABEL_CONFIGURE_TWO_FACTOR: "Konfiguracja autoryzacji 2-etapowej"
+ LABEL_AUTOLOGOUT: "Automatyczne wylogowanie"
AUTOLOGIN_NEVER_OPTION_NAME: "Nidgy"
- AUTOLOGIN_MINUTES_OPTION_NAME: "%MINUTES% minut"
+ AUTOLOGIN_MINUTES_OPTION_NAME: "%MINUTES% minut(a)"
AUTOLOGIN_HOURS_OPTION_NAME: "%HOURS% godzina(-y)"
SETTINGS_GENERAL:
LEGEND_GENERAL: "Ogólne"
- LABEL_LANGUAGE: "Język:"
- LABEL_IDENTITY: "Tożsamość:"
- LABEL_LAYOUT: "Układ:"
+ LABEL_LANGUAGE: "Język"
+ LABEL_IDENTITY: "Tożsamość"
+ LABEL_LAYOUT: "Układ"
LABEL_LAYOUT_NO_SPLIT: "bez podziału"
LABEL_LAYOUT_VERTICAL_SPLIT: "podział w pionie"
LABEL_LAYOUT_HORIZONTAL_SPLIT: "podział w poziomie"
- LABEL_EDITOR: "Format wiadomości:"
+ LABEL_EDITOR: "Format wiadomości"
LABEL_EDITOR_HTML: "HTML"
LABEL_EDITOR_PLAIN: "zwykły tekst"
LABEL_EDITOR_HTML_FORCED: "HTML (wymuszony)"
@@ -482,49 +484,49 @@ pl_PL:
LABEL_ANIMATION_NONE: "brak"
LABEL_VIEW_OPTIONS: "Opcje wyświetlania"
LABEL_USE_PREVIEW_PANE: "Wyświetl okno podglądu"
- LABEL_USE_CHECKBOXES_IN_LIST: "Wyświetl pola zaznaczenia w listach"
+ LABEL_USE_CHECKBOXES_IN_LIST: "Pokazuj pola zaznaczenia na listach"
LABEL_USE_THREADS: "Używaj wątków"
LABEL_REPLY_SAME_FOLDER: "Umieść odpowiedzi w folderach, z których pochodzą wiadomości"
- LABEL_SHOW_IMAGES: "Zawsze wyświetlaj obrazy w wiadomościach"
+ LABEL_SHOW_IMAGES: "Zawsze wyświetlaj zewnętrzne obrazy w treści wiadomości"
LABEL_SHOW_ANIMATION: "Użyj animacji"
- LABEL_MESSAGE_PER_PAGE: "Wiad. na stronie:"
+ LABEL_MESSAGE_PER_PAGE: "Wiadomości na stronę"
LABEL_NOTIFICATIONS: "Powiadomienia"
LABEL_SOUND_NOTIFICATION: "Powiadomienia dźwiękowe"
LABEL_CHROME_NOTIFICATION_DESC: "Wyświetlaj powiadomienia o nowych wiadomościach"
LABEL_CHROME_NOTIFICATION_DESC_DENIED: "(Zablokowane przez przeglądarkę)"
SETTINGS_CONTACTS:
LEGEND_CONTACTS: "Kontakty"
- LABEL_CONTACTS_AUTOSAVE: "Automatycznie dodaj nieznanych nadawców i odbiorców do książki adresowej"
+ LABEL_CONTACTS_AUTOSAVE: "Automatycznie dodawaj odbiorców do książki adresowej"
LEGEND_CONTACTS_SYNC: "Zdalna synchronizacja (CardDAV)"
LABEL_CONTACTS_SYNC_ENABLE: "Włącz zdalną synchronizację"
- LABEL_CONTACTS_SYNC_SERVER: "Serwer:"
- LABEL_CONTACTS_SYNC_AB_URL: "Adres URL:"
- LABEL_CONTACTS_SYNC_USER: "Użytkownik:"
- LABEL_CONTACTS_SYNC_PASSWORD: "Hasło:"
+ LABEL_CONTACTS_SYNC_SERVER: "Serwer"
+ LABEL_CONTACTS_SYNC_AB_URL: "URL książki adresowej"
+ LABEL_CONTACTS_SYNC_USER: "Użytkownik"
+ LABEL_CONTACTS_SYNC_PASSWORD: "Hasło"
SETTINGS_THEMES:
- LEGEND_THEMES: "Motyw"
- LEGEND_THEMES_CUSTOM: "Własny motyw"
+ LEGEND_THEMES: "Motywy"
+ LEGEND_THEMES_CUSTOM: "Konfiguracja własnego motywu"
LABEL_CUSTOM_TYPE: "Typ"
LABEL_CUSTOM_TYPE_LIGHT: "Jasny"
LABEL_CUSTOM_TYPE_DARK: "Ciemny"
LABEL_CUSTOM_BACKGROUND_IMAGE: "Tło"
- BUTTON_UPLOAD_BACKGROUND_IMAGE: "Prześlij własne tło (.JPG, .PNG)"
- ERROR_FILE_IS_TOO_BIG: "Plik jest za duży (1MB+)"
- ERROR_FILE_TYPE_ERROR: "Nieprawidłowy format pliku (obsługiwane są wyłącznie pliki .JPG i .PNG)"
- ERROR_UNKNOWN: "Wystąpił nieznany błąd w trakcie przesyłania"
+ BUTTON_UPLOAD_BACKGROUND_IMAGE: "Prześlij własne tło (JPG, PNG)"
+ ERROR_FILE_IS_TOO_BIG: "Plik jest za duży"
+ ERROR_FILE_TYPE_ERROR: "Nieprawidłowy format pliku (obsługiwane są wyłącznie pliki JPG i PNG)"
+ ERROR_UNKNOWN: "Wystąpił nieznany błąd w trakcie przesyłania pliku na serwer"
SETTINGS_SOCIAL:
LEGEND_GOOGLE: "Konto Google"
BUTTON_GOOGLE_CONNECT: "Połącz z Google"
- BUTTON_GOOGLE_DISCONNECT: "Odłącz"
- MAIN_GOOGLE_DESC: "Po zezwoleniu na logowanie przez: Google, możesz zalogować się na to konto używając przycisku: \"Google\" w panelu logowania."
+ BUTTON_GOOGLE_DISCONNECT: "Odłącz Google"
+ MAIN_GOOGLE_DESC: "Po zezwoleniu na logowanie przez Google, możesz zalogować się na to konto używając przycisku \"Google\" w panelu logowania."
LEGEND_FACEBOOK: "Facebook"
BUTTON_FACEBOOK_CONNECT: "Połącz z Facebook"
- BUTTON_FACEBOOK_DISCONNECT: "Odłącz"
- MAIN_FACEBOOK_DESC: "Po zezwoleniu na logowanie przez: Facebook, możesz zalogować się na to konto używając przycisku: \"Facebook\" w panelu logowania."
+ BUTTON_FACEBOOK_DISCONNECT: "Odłącz Facebook"
+ MAIN_FACEBOOK_DESC: "Po zezwoleniu na logowanie przez Facebook, możesz zalogować się na to konto używając przycisku \"Facebook\" w panelu logowania."
LEGEND_TWITTER: "Twitter"
BUTTON_TWITTER_CONNECT: "Połącz z Twitter"
- BUTTON_TWITTER_DISCONNECT: "Odłącz"
- MAIN_TWITTER_DESC: "Po zezwoleniu na logowanie przez: Twitter, możesz zalogować się na to konto używając przycisku: \"Twitter\" w panelu logowania."
+ BUTTON_TWITTER_DISCONNECT: "Odłącz Twitter"
+ MAIN_TWITTER_DESC: "Po zezwoleniu na logowanie przez Twitter, możesz zalogować się na to konto używając przycisku \"Twitter\" w panelu logowania."
SETTINGS_FOLDERS:
LEGEND_FOLDERS: "Lista folderów"
BUTTON_CREATE: "Utwórz folder"
@@ -556,21 +558,21 @@ pl_PL:
LEGEND_IDENTITY: "Tożsamość"
LEGEND_IDENTITIES: "Dodatkowe tożsamości"
LABEL_DEFAULT: "Domyślna"
- LABEL_DISPLAY_NAME: "Nazwa:"
- LABEL_REPLY_TO: "Odpowiedź do:"
- LABEL_SIGNATURE: "Podpis:"
- LABEL_ADD_SIGNATURE_TO_ALL: "Dodaj podpis do wszystkich wysyłanych wiadomości"
+ LABEL_DISPLAY_NAME: "Nazwa"
+ LABEL_REPLY_TO: "Odpisz do"
+ LABEL_SIGNATURE: "Podpis"
+ LABEL_ADD_SIGNATURE_TO_ALL: "Dodaj podpis do wszystkich wiadomości wychodzących"
BUTTON_ADD_IDENTITY: "Dodaj tożsamość"
BUTTON_DELETE: "Usuń"
LOADING_PROCESS: "Trwa aktualizowanie listy tożsamości"
DELETING_ASK: "Czy na pewno chcesz usunąć?"
SETTINGS_CHANGE_PASSWORD:
LEGEND_CHANGE_PASSWORD: "Zmiana hasła"
- LABEL_CURRENT_PASSWORD: "Aktualne hasło:"
- LABEL_NEW_PASSWORD: "Nowe hasło:"
- LABEL_REPEAT_PASSWORD: "Powtórz nowe hasło:"
+ LABEL_CURRENT_PASSWORD: "Aktualne hasło"
+ LABEL_NEW_PASSWORD: "Nowe hasło"
+ LABEL_REPEAT_PASSWORD: "Powtórz nowe hasło"
BUTTON_UPDATE_PASSWORD: "Zmień hasło na nowe"
- ERROR_PASSWORD_MISMATCH: "Wpisane hasła nie pasują do siebie, proszę spróbować ponownie"
+ ERROR_PASSWORD_MISMATCH: "Podane hasła nie pasują do siebie, spróbuj ponownie"
SETTINGS_OPEN_PGP:
LEGEND_OPEN_PGP: "OpenPGP"
BUTTON_ADD_OPEN_PGP_KEY: "Importuj klucz OpenPGP"
@@ -579,26 +581,27 @@ pl_PL:
TITLE_PUBLIC: "Publiczny"
DELETING_ASK: "Czy na pewno chcesz usunąć?"
GENERATE_ONLY_HTTPS: "Tylko HTTPS"
+ LABEL_ALLOW_DRAFT_AUTOSAVE: "Automatycznie zapisuj szkic"
SHORTCUTS_HELP:
- LEGEND_SHORTCUTS_HELP: "Skróty klawiaturowe"
- TAB_MAILBOX: "Skrzynka pocztowa"
+ LEGEND_SHORTCUTS_HELP: "Pomoc dotycząca skrótów klawiaturowych"
+ TAB_MAILBOX: "Skrzynka odbiorcza"
TAB_MESSAGE_LIST: "Lista wiadomości"
TAB_MESSAGE_VIEW: "Widok wiadomości"
TAB_COMPOSE: "Tworzenie wiadomości"
LABEL_OPEN_USER_DROPDOWN: "Otwórz podręczne menu użytkownika"
LABEL_REPLY: "Odpowiedz"
LABEL_REPLY_ALL: "Odpowiedz wszystkim"
- LABEL_FORWARD: "Przekaż"
- LABEL_FORWARD_MULTIPLY: "Przekaż (wielokrotnie)"
+ LABEL_FORWARD: "Przekaż dalej"
+ LABEL_FORWARD_MULTIPLY: "Przekaż dalej jako załącznik(i)"
LABEL_HELP: "Pomoc"
- LABEL_CHECK_ALL: "Sprawdź wszystkie wiadomości"
+ LABEL_CHECK_ALL: "Zaznacz wszystkie wiadomości"
LABEL_ARCHIVE: "Archiwum"
LABEL_DELETE: "Usuń"
LABEL_OPEN_THREAD: "Otwórz wybrany wątek"
LABEL_MOVE: "Przenieś"
- LABEL_READ: "Oznacz zaznaczone wiadomości, jako przeczytane"
- LABEL_UNREAD: "Oznacz zaznaczone wiadomości, jako nieprzeczytane"
- LABEL_IMPORTANT: "Oznacz zaznaczone wiadomości, jako ważne"
+ LABEL_READ: "Oznacz zaznaczone wiadomości jako przeczytane"
+ LABEL_UNREAD: "Oznacz zaznaczone wiadomości jako nieprzeczytane"
+ LABEL_IMPORTANT: "Oznacz zaznaczone wiadomości jako ważne"
LABEL_SEARCH: "Szukaj"
LABEL_CANCEL_SEARCH: "Anuluj szukanie"
LABEL_FULLSCREEN_ENTER: "Pełny ekran (aktywny podgląd wiadomości)"
@@ -621,46 +624,46 @@ pl_PL:
LABEL_CLOSE_COMPOSE: "Zamknij okno tworzenia wiadomości"
PGP_NOTIFICATIONS:
NO_PUBLIC_KEYS_FOUND: "Nie znaleziono klucza publicznego"
- NO_PUBLIC_KEYS_FOUND_FOR: "Nie znaleziono klucza publicznego dla adresu: \"%EMAIL%\""
+ NO_PUBLIC_KEYS_FOUND_FOR: "Nie znaleziono klucza publicznego dla adresu \"%EMAIL%\""
NO_PRIVATE_KEY_FOUND: "Nie znaleziono klucza prywatnego"
- NO_PRIVATE_KEY_FOUND_FOR: "Nie znaleziono klucza prywatnego dla adresu: \"%EMAIL%\""
+ NO_PRIVATE_KEY_FOUND_FOR: "Nie znaleziono klucza prywatnego dla adresu \"%EMAIL%\""
ADD_A_PUBLICK_KEY: "Dodaj klucz publiczny"
SELECT_A_PRIVATE_KEY: "Wybierz klucz prywatny"
- UNVERIFIRED_SIGNATURE: "Niezweryfikowana"
- DECRYPTION_ERROR: "Błąd deszyfrowania OpenPGP"
- GOOD_SIGNATURE: "Podpisana przez: %USER%"
+ UNVERIFIRED_SIGNATURE: "Podpis niezweryfikowany"
+ DECRYPTION_ERROR: "Błąd odszyfrowywania OpenPGP"
+ GOOD_SIGNATURE: "Poprawnie podpisana przez %USER%"
PGP_ERROR: "Błąd OpenPGP: %ERROR%"
- SPECIFY_FROM_EMAIL: "Proszę podać adres e-mail w polu: OD"
- SPECIFY_AT_LEAST_ONE_RECIPIENT: "Proszę podać przynajmniej jednego odbiorcę"
+ SPECIFY_FROM_EMAIL: "Podaj adres e-mail w polu OD"
+ SPECIFY_AT_LEAST_ONE_RECIPIENT: "Podaj przynajmniej jednego odbiorcę"
NOTIFICATIONS:
INVALID_TOKEN: "Nieprawidłowy token"
AUTH_ERROR: "Błąd autoryzacji"
ACCESS_ERROR: "Błąd dostępu"
CONNECTION_ERROR: "Błąd połączenia z serwerem"
- CAPTCHA_ERROR: "Nieprawidłowy kod CAPTCHA"
+ CAPTCHA_ERROR: "Nieprawidłowy kod CAPTCHA."
SOCIAL_FACEBOOK_LOGIN_ACCESS_DISABLE: >
- To społecznościowe ID (Facebooku), nie jest powiązane z żadnym kontem pocztowym.
- Zaloguj się używając danych swojego konta e-mail i skonfiguruj tę opcję w:
- Ustawienia > Sieci społecznościowe.
+ Ten identyfikator społecznościowy (Facebook) nie jest powiązany z żadnym kontem
+ pocztowym. Zaloguj się używając danych swojego konta e-mail i skonfiguruj
+ tę opcję w: Ustawienia > Sieci społecznościowe.
SOCIAL_TWITTER_LOGIN_ACCESS_DISABLE: >
- To społecznościowe ID (Twitter), nie jest powiązane z żadnym kontem pocztowym.
- Zaloguj się używając danych swojego konta e-mail i skonfiguruj tę opcję w:
- Ustawienia > Sieci społecznościowe.
+ Ten identyfikator społecznościowy (Twitter) nie jest powiązany z żadnym kontem
+ pocztowym. Zaloguj się używając danych swojego konta e-mail i skonfiguruj
+ tę opcję w: Ustawienia > Sieci społecznościowe.
SOCIAL_GOOGLE_LOGIN_ACCESS_DISABLE: >
- To społecznościowe ID (Konto Google), nie jest powiązane z żadnym kontem pocztowym.
- Zaloguj się używając danych swojego konta e-mail i skonfiguruj tę opcję w:
- Ustawienia > Sieci społecznościowe.
+ Ten identyfikator społecznościowy (Konto Google) nie jest powiązany z żadnym
+ kontem pocztowym. Zaloguj się używając danych swojego konta e-mail i skonfiguruj
+ tę opcję w: Ustawienia > Sieci społecznościowe.
DOMAIN_NOT_ALLOWED: "Domena niedozwolona"
ACCOUNT_NOT_ALLOWED: "Konto nie jest dozwolone"
- ACCOUNT_TWO_FACTOR_AUTH_REQUIRED: "Wymagana dwuskładnikowa autoryzacja"
- ACCOUNT_TWO_FACTOR_AUTH_ERROR: "Błąd dwuskładnikowej autoryzacji"
+ ACCOUNT_TWO_FACTOR_AUTH_REQUIRED: "Wymagana autoryzacja dwuetapowa"
+ ACCOUNT_TWO_FACTOR_AUTH_ERROR: "Błąd autoryzacji dwuetapowej"
COULD_NOT_SAVE_NEW_PASSWORD: "Nie można było zapisać nowego hasła"
CURRENT_PASSWORD_INCORRECT: "Obecne hasło jest niepoprawne"
NEW_PASSWORD_SHORT: "Hasło jest za krótkie"
NEW_PASSWORD_WEAK: "Hasło jest zbyt łatwe"
- NEW_PASSWORD_FORBIDDENT: "Hasło zawiera zakazane znaki"
+ NEW_PASSWORD_FORBIDDENT: "Hasło zawiera niedozwolone znaki"
CONTACTS_SYNC_ERROR: "Błąd synchronizacji kontaktów"
- CANT_GET_MESSAGE_LIST: "Nie jest możliwe pobranie listy wiadomości"
+ CANT_GET_MESSAGE_LIST: "Nie można pobrać listy wiadomości"
CANT_GET_MESSAGE: "Nie można pobrać wiadomości"
CANT_DELETE_MESSAGE: "Nie można usunąć wiadomości"
CANT_MOVE_MESSAGE: "Nie można przenieść wiadomości"
@@ -669,25 +672,25 @@ pl_PL:
INVALID_RECIPIENTS: "Nieprawidłowy adres odbiorcy"
CANT_SAVE_FILTERS: "Nie można zapisać filtrów"
CANT_GET_FILTERS: "Nie można pobrać filtrów"
- FILTERS_ARE_NOT_CORRECT: "Filtry sa nieprawidłowe"
+ FILTERS_ARE_NOT_CORRECT: "Filtry są nieprawidłowe"
CANT_CREATE_FOLDER: "Nie można utworzyć folderu"
CANT_RENAME_FOLDER: "Nie można zmienić nazwy folderu"
CANT_DELETE_FOLDER: "Nie można usunąć folderu"
- CANT_DELETE_NON_EMPTY_FOLDER: "Nie można usunąć folderu w którym znajdują się wiadomości"
- CANT_SUBSCRIBE_FOLDER: "Nie można przypisać folderu"
- CANT_UNSUBSCRIBE_FOLDER: "Nie można wypisać z folderu"
- CANT_SAVE_SETTINGS: "Nie można zmienić ustawień"
- CANT_SAVE_PLUGIN_SETTINGS: "Nie mozna zmienić ustawień wtyczki"
+ CANT_DELETE_NON_EMPTY_FOLDER: "Nie można usunąć folderu, w którym znajdują się wiadomości"
+ CANT_SUBSCRIBE_FOLDER: "Nie można zasubskrybować folderu"
+ CANT_UNSUBSCRIBE_FOLDER: "Nie można usunąć subskrypcji folderu"
+ CANT_SAVE_SETTINGS: "Nie można zapisać ustawień"
+ CANT_SAVE_PLUGIN_SETTINGS: "Nie można zapisać ustawień"
DOMAIN_ALREADY_EXISTS: "Domena już istnieje"
CANT_INSTALL_PACKAGE: "Nieudana instalacja pakietu"
CANT_DELETE_PACKAGE: "Nieudane usunięcie pakietu"
INVALID_PLUGIN_PACKAGE: "Nieprawidłowy pakiet rozszerzenia"
UNSUPPORTED_PLUGIN_PACKAGE: "Nieobsługiwany pakiet rozszerzenia"
LICENSING_SERVER_IS_UNAVAILABLE: "Serwer subskrypcji jest niedostępny"
- LICENSING_DOMAIN_EXPIRED: "Subskrypcja dla tej domeny wygasła"
- LICENSING_DOMAIN_BANNED: "Subskrypcja dla tej domeny została zablokowana"
- DEMO_SEND_MESSAGE_ERROR: "Ze względów bezpieczeństwa, to konto testowe nie ma możliwości przesyłania, wiadomości na zewnętrzne adresy e-mail."
- DEMO_ACCOUNT_ERROR: "Ze względów bezpieczeństwa, ta akcja jest niedozwolona na tym koncie!"
+ LICENSING_DOMAIN_EXPIRED: "Subskrypcja dla tej domeny wygasła."
+ LICENSING_DOMAIN_BANNED: "Subskrypcja dla tej domeny została zablokowana."
+ DEMO_SEND_MESSAGE_ERROR: "Ze względów bezpieczeństwa konto testowe nie ma możliwości przesyłania wiadomości na zewnętrzne adresy e-mail."
+ DEMO_ACCOUNT_ERROR: "Ze względów bezpieczeństwa ta akcja jest niedozwolona na tym koncie!"
ACCOUNT_ALREADY_EXISTS: "Konto o takiej nazwie już istnieje"
ACCOUNT_DOES_NOT_EXIST: "Konto nie istnieje"
MAIL_SERVER_ERROR: "Wystąpił błąd w trakcie połączenia z serwerem poczty"
@@ -695,18 +698,18 @@ pl_PL:
UNKNOWN_ERROR: "Nieznany błąd"
STATIC:
BACK_LINK: "Odśwież"
- DOMAIN_LIST_DESC: "Lista domen do których webmail ma dostęp"
+ DOMAIN_LIST_DESC: "Lista domen, do których webmail ma dostęp."
PHP_EXSTENSIONS_ERROR_DESC: "Wymagane rozszerzenia PHP są niedostępne!"
PHP_VERSION_ERROR_DESC: "Aktualnie zainstalowana wersja PHP: (%VERSION%), jest niższa niż minimalnie wymagana 5.3.0!"
- NO_SCRIPT_TITLE: "Ta aplikacja wymaga JavaScript"
+ NO_SCRIPT_TITLE: "Ta aplikacja wymaga JavaScript."
NO_SCRIPT_DESC: |
- Twoja przeglądarka nie obsługuje JavaScript
- Proszę o umożliwienie obsługi JavaScript w przeglądarce, oraz ponowne załadowanie tej strony.
+ Twoja przeglądarka nie obsługuje JavaScript.
+ Włącz obsługę JavaScript w przeglądarce i ponowne załaduj tę stronę.
NO_COOKIE_TITLE: "Ta aplikacja wymaga plików Cookies"
NO_COOKIE_DESC: |
- Obsługa Cookies jest wyłączona w twojej przeglądarce
- Proszę o umożliwienie obsługi plików Cookie w przeglądarce oraz ponowne uruchomienie tej strony.
- BAD_BROWSER_TITLE: "Twoja przeglądarka jest przestarzała!"
+ Obsługa Cookies jest wyłączona w Twojej przeglądarce.
+ Włącz obsługę plików Cookie w przeglądarce i spróbuj ponowne.
+ BAD_BROWSER_TITLE: "Twoja przeglądarka jest przestarzała."
BAD_BROWSER_DESC: |
W celu wykorzystania wszystkich funkcji tej aplikacji,
zaktualizuj aktualnie używaną lub pobierz i zainstaluj jedną z poniższych przeglądarek:
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/pt_BR.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/pt_BR.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/pt_BR.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/pt_BR.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/pt_PT.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/pt_PT.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/pt_PT.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/pt_PT.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/ro_RO.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/ro_RO.yml
similarity index 99%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/ro_RO.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/ro_RO.yml
index 7d216b6a9723dbc98b881fcf6a1aeda8450f0653..afb0ee8ff2c69b5eb87723455a9b2e4bc59d30a1 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/ro_RO.yml
+++ b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/ro_RO.yml
@@ -45,8 +45,8 @@ ro_RO:
ZOOM: "Zoom in/out"
CLOSE: "Închide (Esc)"
LOADING: "Se îcarcă..."
- GALLERY_PREV: "Precedentul (Стрелка ←)"
- GALLERY_NEXT: "Următorul (Стрелка →)"
+ GALLERY_PREV: "Precedentul (săgeată stânga)"
+ GALLERY_NEXT: "Următorul (săgeată dreapta)"
GALLERY_COUNTER: "%curr% din %total%"
IMAGE_ERROR: "Imaginea nu a putut fi încărcată"
AJAX_ERROR: "Conținutul nu a putut fi încărcat"
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/ru_RU.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/ru_RU.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/ru_RU.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/ru_RU.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/sk_SK.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/sk_SK.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/sk_SK.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/sk_SK.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/sl_SI.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/sl_SI.yml
similarity index 99%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/sl_SI.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/sl_SI.yml
index e92a7ff7d41701156b4da52676a837b9c5e9a0f4..c177681e3374a44795c09988d6f44c4cb21f1bc6 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/sl_SI.yml
+++ b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/sl_SI.yml
@@ -151,6 +151,7 @@ sl_SI:
PGP_ENCRYPTED_MESSAGE_DESC: "Sporočilo, šifrirano z OpenPGP (kliknite za dešifriranje)"
LINK_DOWNLOAD_AS_ZIP: "Prenesi kot .zip datoteko"
LINK_SAVE_TO_OWNCLOUD: "Shrani na ownCloud"
+ LINK_SAVE_TO_CLOUD: "Shrani v oblak"
LINK_SAVE_TO_DROPBOX: "Shrani na Dropbox"
READ_RECEIPT:
SUBJECT: "Povratno poročilo (prikazano) - %SUBJECT%"
@@ -580,6 +581,7 @@ sl_SI:
TITLE_PUBLIC: "Javni"
DELETING_ASK: "Ste prepričani?"
GENERATE_ONLY_HTTPS: "Samo HTTPS"
+ LABEL_ALLOW_DRAFT_AUTOSAVE: "Samodejno shrani osnutek"
SHORTCUTS_HELP:
LEGEND_SHORTCUTS_HELP: "Tipkovne bližnjice"
TAB_MAILBOX: "Nabiralnik"
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/sv_SE.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/sv_SE.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/sv_SE.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/sv_SE.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/tr_TR.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/tr_TR.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/tr_TR.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/tr_TR.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/uk_UA.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/uk_UA.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/uk_UA.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/uk_UA.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/zh_CN.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/zh_CN.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/zh_CN.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/zh_CN.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/localization/webmail/zh_TW.yml b/rainloop/app/rainloop/v/1.12.1/app/localization/webmail/zh_TW.yml
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/localization/webmail/zh_TW.yml
rename to rainloop/app/rainloop/v/1.12.1/app/localization/webmail/zh_TW.yml
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/RainLoop.asc b/rainloop/app/rainloop/v/1.12.1/app/resources/RainLoop.asc
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/RainLoop.asc
rename to rainloop/app/rainloop/v/1.12.1/app/resources/RainLoop.asc
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/empty-contact.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/empty-contact.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/empty-contact.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/empty-contact.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/amazon.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/amazon.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/amazon.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/amazon.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/apple.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/apple.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/apple.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/apple.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/asana.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/asana.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/asana.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/asana.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/battle.net.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/battle.net.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/battle.net.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/battle.net.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/blizzard.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/blizzard.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/blizzard.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/blizzard.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/cnet.online.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/cnet.online.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/cnet.online.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/cnet.online.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/connect.asana.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/connect.asana.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/connect.asana.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/connect.asana.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/e.paypal.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/e.paypal.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/e.paypal.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/e.paypal.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/ea.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/ea.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/ea.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/ea.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/ebay.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/ebay.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/ebay.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/ebay.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/em.ea.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/em.ea.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/em.ea.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/em.ea.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/email.blizzard.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/email.blizzard.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/email.blizzard.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/email.blizzard.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/email.microsoft.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/email.microsoft.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/email.microsoft.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/email.microsoft.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/email.skype.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/email.skype.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/email.skype.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/email.skype.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/facebook.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/facebook.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/facebook.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/facebook.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/facebookmail.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/facebookmail.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/facebookmail.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/facebookmail.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/github.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/github.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/github.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/github.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/google.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/google.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/google.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/google.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/id.apple.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/id.apple.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/id.apple.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/id.apple.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/intl.paypal.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/intl.paypal.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/intl.paypal.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/intl.paypal.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/microsoft.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/microsoft.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/microsoft.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/microsoft.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/microsoftonline.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/microsoftonline.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/microsoftonline.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/microsoftonline.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/myspace.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/myspace.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/myspace.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/myspace.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/news.myspace.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/news.myspace.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/news.myspace.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/news.myspace.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/news.onlive.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/news.onlive.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/news.onlive.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/news.onlive.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/onlive.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/onlive.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/onlive.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/onlive.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/paypal.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/paypal.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/paypal.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/paypal.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/plus.google.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/plus.google.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/plus.google.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/plus.google.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/postmaster.twitter.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/postmaster.twitter.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/postmaster.twitter.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/postmaster.twitter.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/reply.ebay.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/reply.ebay.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/reply.ebay.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/reply.ebay.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/reply1.ebay.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/reply1.ebay.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/reply1.ebay.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/reply1.ebay.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/reply2.ebay.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/reply2.ebay.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/reply2.ebay.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/reply2.ebay.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/reply3.ebay.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/reply3.ebay.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/reply3.ebay.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/reply3.ebay.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/skype.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/skype.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/skype.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/skype.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/steampowered.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/steampowered.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/steampowered.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/steampowered.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/ted.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/ted.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/ted.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/ted.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/twitter.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/twitter.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/twitter.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/twitter.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/resources/images/services/youtube.com.png b/rainloop/app/rainloop/v/1.12.1/app/resources/images/services/youtube.com.png
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/resources/images/services/youtube.com.png
rename to rainloop/app/rainloop/v/1.12.1/app/resources/images/services/youtube.com.png
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/BadBrowser.html b/rainloop/app/rainloop/v/1.12.1/app/templates/BadBrowser.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/BadBrowser.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/BadBrowser.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Error.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Error.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Error.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Error.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Index.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Index.html
similarity index 97%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Index.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Index.html
index e13fe4797abba0b53f3e0e6c4804b315cebe3033..3be1b78edafa90ba2a9532afd8b8029fe666005e 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/templates/Index.html
+++ b/rainloop/app/rainloop/v/1.12.1/app/templates/Index.html
@@ -1,30 +1,30 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{BaseContentSecurityPolicy}}
-
- {{BaseAppFaviconPngLinkTag}}
- {{BaseAppFaviconTouchLinkTag}}
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{BaseContentSecurityPolicy}}
+
+ {{BaseAppFaviconPngLinkTag}}
+ {{BaseAppFaviconTouchLinkTag}}
+
+
+
+
+
+
+
+
+
+
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Social.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Social.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Social.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Social.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Themes/template.less b/rainloop/app/rainloop/v/1.12.1/app/templates/Themes/template.less
similarity index 96%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Themes/template.less
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Themes/template.less
index b4ebb2ab4b48019e482063c51dcc9bb706395855..90b00d0857a5e7ac16f06c5dc891f7840f853ccf 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/templates/Themes/template.less
+++ b/rainloop/app/rainloop/v/1.12.1/app/templates/Themes/template.less
@@ -1,357 +1,357 @@
-
-// mixins +++
-.thm-linear-gradient-mixin(@start, @end) when (iscolor(@start)) and (iscolor(@end)) {
- background-color: mix(@start, @end, 60%) !important;
- background-image: -moz-linear-gradient(top, @start, @end) !important; // FF 3.6+
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@start), to(@end)) !important; // Safari 4+, Chrome 2+
- background-image: -webkit-linear-gradient(top, @start, @end) !important; // Safari 5.1+, Chrome 10+
- background-image: -o-linear-gradient(top, @start, @end !important); // Opera 11.10
- background-image: linear-gradient(to bottom, @start, @end) !important; // Standard, IE10
- background-repeat: repeat-x !important;
- filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@start),argb(@end))) !important; // IE9 and down
-}
-
-.thm-border-radius(@radius) when (ispixel(@radius)) {
- -webkit-border-radius: @radius !important;
- -moz-border-radius: @radius !important;
- border-radius: @radius !important;
-}
-
-.thm-box-shadow(@shadow) {
- -webkit-box-shadow: @shadow !important;
- -moz-box-shadow: @shadow !important;
- box-shadow: @shadow !important;
-}
-.thm-body-background-image(@value) when (isstring(@value)) {
- background-image: url("@{base}@{value}") !important;
-}
-.thm-body-background-image(@value) when not (isstring(@value)) {
- background-image: @value !important;
-}
-.thm-rgba-background-color(@simple, @rgba) when (@rgba = false) {
- background-color: @simple !important;
-}
-.thm-rgba-background-color(@simple, @rgba) when not (@rgba = false) {
- background-color: @simple !important;
- background-color: @rgba !important;
-}
-// --- mixins
-
-.thm-body {
- color: @main-color;
- background-color: @main-background-color;
- background-size: @main-background-size;
- .thm-body-background-image(@main-background-image);
-}
-
-.thm-loading {
- color: @loading-color !important;
- text-shadow: @loading-text-shadow !important;
-
- .e-spinner .e-bounce {
- background-color: @loading-color !important;
- }
-}
-
-.thm-login-desc .desc {
- color: @loading-color !important;
- text-shadow: @loading-text-shadow !important;
-}
-
-.thm-login {
- border: @login-border !important;
- .thm-rgba-background-color(@login-background-color, @login-rgba-background-color);
- .thm-linear-gradient-mixin(@login-gradient-start, @login-gradient-end);
- .thm-border-radius(@login-border-radius);
- .thm-box-shadow(@login-box-shadow);
-
- &.submitting-pane.submitting {
- &:before{
- background: @spinner-background;
- .thm-border-radius(@login-border-radius);
- }
- &:after{
- border-top-color: @spinner-color;
- }
- }
-}
-
-.thm-login-text {
- color: @login-color !important;
-
- .legend, .e-checkbox-icon, .g-ui-link, .social-button, .language-button {
- color: @login-color !important;
- }
-}
-
-.thm-powered, .thm-mobile-switcher {
- color: @powered-color;
- a {
- color: @powered-color;
- &:hover {
- color: lighten(@powered-color, 20%);
- }
- }
-}
-
-.thm-languages {
- color: @languages-color;
- .flag-name {
- color: @languages-color;
- border-color: @languages-color;
- }
-}
-
-.g-ui-menu {
- color: @dropdown-menu-color !important;
- background-color: @dropdown-menu-background-color !important;
-}
-
-.g-ui-menu .e-item > .e-link {
- color: @dropdown-menu-color !important;
- background-color: @dropdown-menu-background-color !important;
-
- > i {
- color: @dropdown-menu-color !important;
- }
-}
-
-.g-ui-menu .e-item.selected > .e-link {
- background-color: @dropdown-menu-selected-background-color !important;
-}
-
-.g-ui-menu .e-item > .e-link:hover, .g-ui-menu .e-item > .e-link:focus {
- color: @dropdown-menu-hover-color !important;
- background-color: @dropdown-menu-hover-background-color !important;
-
- > i {
- color: @dropdown-menu-hover-color !important;
- }
-}
-
-.g-ui-menu .e-item.disabled > .e-link, .g-ui-menu .e-item.disabled > .e-link:hover {
- color: @dropdown-menu-disabled-color !important;
- background-color: @dropdown-menu-background-color !important;
-
- > i {
- color: @dropdown-menu-disabled-color !important;
- }
-}
-
-.thm-message-list-top-toolbar, .thm-message-list-bottom-toolbar {
- .thm-rgba-background-color(@message-list-toolbar-background-color, @message-list-toolbar-rgba-background-color);
- .thm-linear-gradient-mixin(@message-list-toolbar-gradient-start, @message-list-toolbar-gradient-end);
-}
-
-.thm-folders .e-link {
-
- color: @folders-disabled-color !important;
-
- &.selectable {
- color: @folders-color !important;
- }
-
- &.selectable:hover {
- color: @folders-hover-color !important;
- .thm-rgba-background-color(@folders-hover-background-color, @folders-hover-rgba-background-color);
- }
-
- &.selectable.selected {
- color: @folders-selected-color !important;
- .thm-rgba-background-color(@folders-selected-background-color, @folders-selected-rgba-background-color);
- }
-
- &.focused {
- color: @folders-focused-color !important;
- .thm-rgba-background-color(@folders-focused-background-color, @folders-focused-rgba-background-color);
- }
-
- &.selectable.droppableHover {
- color: @folders-drop-color !important;
- .thm-rgba-background-color(@folders-drop-background-color, @folders-drop-rgba-background-color);
- }
-}
-
-.thm-settings-menu .e-item {
-
- .e-link {
- color: @settings-menu-disabled-color !important;
- }
-
- &.selectable .e-link {
- color: @settings-menu-color !important;
- }
-
- &.selectable:hover .e-link {
- .thm-rgba-background-color(@settings-menu-hover-background-color, @settings-menu-hover-rgba-background-color);
- color: @settings-menu-hover-color !important;
- }
-
- &.selectable.selected .e-link {
- .thm-rgba-background-color(@settings-menu-selected-background-color, @settings-menu-selected-rgba-background-color);
- color: @settings-menu-selected-color !important;
- }
-}
-
-.thm-message-view-background-color {
- .thm-rgba-background-color(@message-background-color, @message-rgba-background-color);
-}
-
-#rl-app{
- display: block;
-}
-
-html.no-css {
-
- margin: 0;
- padding: 0;
- font-family: Arial, Verdana, Geneva, sans-serif;
-
- body {
- margin: 0;
- padding: 0;
- }
-
- #rl-loading, #rl-loading-error {
- position: absolute;
- font-size: 30px;
- line-height: 130%;
- top: 50%;
- width: 100%;
- height: 65px;
- margin: 0;
- margin-top: -60px;
- background-color: transparent;
- text-align: center;
- color: #333;
- }
-
- .progressjs-container {
- display: none;
- }
-
- .thm-body {
- color: #333;
- background-color: #aaa;
- background-image: none;
- }
-
- .thm-loading {
- color: #333 !important;
- text-shadow: none !important;
-
- .e-spinner .e-bounce {
- display: none !important;
- }
- }
-
- .thm-login-desc .desc {
- color: #333 !important;
- text-shadow: none !important;
- }
-}
-
-// glass style
-html.glass {
-
- @glass-color: #fff !important;
- @glass-p-color: #aaa !important;
- @glass-error-color: #f76260 !important;
- @glass-m-color: rgba(255, 255, 255, .8) !important;
-
- .thm-login {
- background: none !important;
- background: rgba(0, 0, 0, .5) !important;
- box-shadow: none !important;
-
- border: none !important;
- border: 1px solid rgba(255, 255, 255, .2) !important;
-
- .controls {
- .input-append .add-on i {
- color: @glass-m-color;
- text-shadow: none !important;
- outline: none !important;
- box-shadow: none !important;
- }
-
- input {
- border: 1px solid none !important;
- background: none !important;
- outline: none !important;
- text-shadow: none !important;
- box-shadow: none !important;
-
- color: @glass-color;
- border-color: @glass-m-color;
-
- &::-webkit-input-placeholder {
- color: @glass-color;
- text-shadow: none !important;
- }
- &::-moz-placeholder {
- color: @glass-color;
- text-shadow: none !important;
- }
- &:-moz-placeholder {
- color: @glass-color;
- text-shadow: none !important;
- }
- &:-ms-input-placeholder {
- color: @glass-color;
- text-shadow: none !important;
- }
- &:input-placeholder {
- color: @glass-color;
- text-shadow: none !important;
- }
- &:placeholder {
- color: @glass-color;
- text-shadow: none !important;
- }
-
- &:focus, &:hover {
- border-color: @glass-color;
- }
- }
- .btn {
- border: 1px solid none !important;
- background: none !important;
- outline: none !important;
- text-shadow: none !important;
- box-shadow: none !important;
-
- color: @glass-color;
- border-color: @glass-m-color;
-
- text-transform: uppercase;
- font-size: 13px;
-
- &:hover, &:active{
- border-color: @glass-color;
- }
- }
-
- &.error {
- .input-append .add-on i {
- color: @glass-error-color;
- }
-
- input {
- color: @glass-error-color;
- border-color: @glass-error-color;
- }
- }
- }
- }
-
- .thm-login-text {
- color: @glass-m-color;
- text-shadow: none !important;
-
- .legend, .e-checkbox-icon, .g-ui-link, .social-button, .language-button {
- color: @glass-m-color;
- text-shadow: none !important;
- }
- }
-}
+
+// mixins +++
+.thm-linear-gradient-mixin(@start, @end) when (iscolor(@start)) and (iscolor(@end)) {
+ background-color: mix(@start, @end, 60%) !important;
+ background-image: -moz-linear-gradient(top, @start, @end) !important; // FF 3.6+
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@start), to(@end)) !important; // Safari 4+, Chrome 2+
+ background-image: -webkit-linear-gradient(top, @start, @end) !important; // Safari 5.1+, Chrome 10+
+ background-image: -o-linear-gradient(top, @start, @end !important); // Opera 11.10
+ background-image: linear-gradient(to bottom, @start, @end) !important; // Standard, IE10
+ background-repeat: repeat-x !important;
+ filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@start),argb(@end))) !important; // IE9 and down
+}
+
+.thm-border-radius(@radius) when (ispixel(@radius)) {
+ -webkit-border-radius: @radius !important;
+ -moz-border-radius: @radius !important;
+ border-radius: @radius !important;
+}
+
+.thm-box-shadow(@shadow) {
+ -webkit-box-shadow: @shadow !important;
+ -moz-box-shadow: @shadow !important;
+ box-shadow: @shadow !important;
+}
+.thm-body-background-image(@value) when (isstring(@value)) {
+ background-image: url("@{base}@{value}") !important;
+}
+.thm-body-background-image(@value) when not (isstring(@value)) {
+ background-image: @value !important;
+}
+.thm-rgba-background-color(@simple, @rgba) when (@rgba = false) {
+ background-color: @simple !important;
+}
+.thm-rgba-background-color(@simple, @rgba) when not (@rgba = false) {
+ background-color: @simple !important;
+ background-color: @rgba !important;
+}
+// --- mixins
+
+.thm-body {
+ color: @main-color;
+ background-color: @main-background-color;
+ background-size: @main-background-size;
+ .thm-body-background-image(@main-background-image);
+}
+
+.thm-loading {
+ color: @loading-color !important;
+ text-shadow: @loading-text-shadow !important;
+
+ .e-spinner .e-bounce {
+ background-color: @loading-color !important;
+ }
+}
+
+.thm-login-desc .desc {
+ color: @loading-color !important;
+ text-shadow: @loading-text-shadow !important;
+}
+
+.thm-login {
+ border: @login-border !important;
+ .thm-rgba-background-color(@login-background-color, @login-rgba-background-color);
+ .thm-linear-gradient-mixin(@login-gradient-start, @login-gradient-end);
+ .thm-border-radius(@login-border-radius);
+ .thm-box-shadow(@login-box-shadow);
+
+ &.submitting-pane.submitting {
+ &:before{
+ background: @spinner-background;
+ .thm-border-radius(@login-border-radius);
+ }
+ &:after{
+ border-top-color: @spinner-color;
+ }
+ }
+}
+
+.thm-login-text {
+ color: @login-color !important;
+
+ .legend, .e-checkbox-icon, .g-ui-link, .social-button, .language-button {
+ color: @login-color !important;
+ }
+}
+
+.thm-powered, .thm-mobile-switcher {
+ color: @powered-color;
+ a {
+ color: @powered-color;
+ &:hover {
+ color: lighten(@powered-color, 20%);
+ }
+ }
+}
+
+.thm-languages {
+ color: @languages-color;
+ .flag-name {
+ color: @languages-color;
+ border-color: @languages-color;
+ }
+}
+
+.g-ui-menu {
+ color: @dropdown-menu-color !important;
+ background-color: @dropdown-menu-background-color !important;
+}
+
+.g-ui-menu .e-item > .e-link {
+ color: @dropdown-menu-color !important;
+ background-color: @dropdown-menu-background-color !important;
+
+ > i {
+ color: @dropdown-menu-color !important;
+ }
+}
+
+.g-ui-menu .e-item.selected > .e-link {
+ background-color: @dropdown-menu-selected-background-color !important;
+}
+
+.g-ui-menu .e-item > .e-link:hover, .g-ui-menu .e-item > .e-link:focus {
+ color: @dropdown-menu-hover-color !important;
+ background-color: @dropdown-menu-hover-background-color !important;
+
+ > i {
+ color: @dropdown-menu-hover-color !important;
+ }
+}
+
+.g-ui-menu .e-item.disabled > .e-link, .g-ui-menu .e-item.disabled > .e-link:hover {
+ color: @dropdown-menu-disabled-color !important;
+ background-color: @dropdown-menu-background-color !important;
+
+ > i {
+ color: @dropdown-menu-disabled-color !important;
+ }
+}
+
+.thm-message-list-top-toolbar, .thm-message-list-bottom-toolbar {
+ .thm-rgba-background-color(@message-list-toolbar-background-color, @message-list-toolbar-rgba-background-color);
+ .thm-linear-gradient-mixin(@message-list-toolbar-gradient-start, @message-list-toolbar-gradient-end);
+}
+
+.thm-folders .e-link {
+
+ color: @folders-disabled-color !important;
+
+ &.selectable {
+ color: @folders-color !important;
+ }
+
+ &.selectable:hover {
+ color: @folders-hover-color !important;
+ .thm-rgba-background-color(@folders-hover-background-color, @folders-hover-rgba-background-color);
+ }
+
+ &.selectable.selected {
+ color: @folders-selected-color !important;
+ .thm-rgba-background-color(@folders-selected-background-color, @folders-selected-rgba-background-color);
+ }
+
+ &.focused {
+ color: @folders-focused-color !important;
+ .thm-rgba-background-color(@folders-focused-background-color, @folders-focused-rgba-background-color);
+ }
+
+ &.selectable.droppableHover {
+ color: @folders-drop-color !important;
+ .thm-rgba-background-color(@folders-drop-background-color, @folders-drop-rgba-background-color);
+ }
+}
+
+.thm-settings-menu .e-item {
+
+ .e-link {
+ color: @settings-menu-disabled-color !important;
+ }
+
+ &.selectable .e-link {
+ color: @settings-menu-color !important;
+ }
+
+ &.selectable:hover .e-link {
+ .thm-rgba-background-color(@settings-menu-hover-background-color, @settings-menu-hover-rgba-background-color);
+ color: @settings-menu-hover-color !important;
+ }
+
+ &.selectable.selected .e-link {
+ .thm-rgba-background-color(@settings-menu-selected-background-color, @settings-menu-selected-rgba-background-color);
+ color: @settings-menu-selected-color !important;
+ }
+}
+
+.thm-message-view-background-color {
+ .thm-rgba-background-color(@message-background-color, @message-rgba-background-color);
+}
+
+#rl-app{
+ display: block;
+}
+
+html.no-css {
+
+ margin: 0;
+ padding: 0;
+ font-family: Arial, Verdana, Geneva, sans-serif;
+
+ body {
+ margin: 0;
+ padding: 0;
+ }
+
+ #rl-loading, #rl-loading-error {
+ position: absolute;
+ font-size: 30px;
+ line-height: 130%;
+ top: 50%;
+ width: 100%;
+ height: 65px;
+ margin: 0;
+ margin-top: -60px;
+ background-color: transparent;
+ text-align: center;
+ color: #333;
+ }
+
+ .progressjs-container {
+ display: none;
+ }
+
+ .thm-body {
+ color: #333;
+ background-color: #aaa;
+ background-image: none;
+ }
+
+ .thm-loading {
+ color: #333 !important;
+ text-shadow: none !important;
+
+ .e-spinner .e-bounce {
+ display: none !important;
+ }
+ }
+
+ .thm-login-desc .desc {
+ color: #333 !important;
+ text-shadow: none !important;
+ }
+}
+
+// glass style
+html.glass {
+
+ @glass-color: #fff !important;
+ @glass-p-color: #aaa !important;
+ @glass-error-color: #f76260 !important;
+ @glass-m-color: rgba(255, 255, 255, .8) !important;
+
+ .thm-login {
+ background: none !important;
+ background: rgba(0, 0, 0, .5) !important;
+ box-shadow: none !important;
+
+ border: none !important;
+ border: 1px solid rgba(255, 255, 255, .2) !important;
+
+ .controls {
+ .input-append .add-on i {
+ color: @glass-m-color;
+ text-shadow: none !important;
+ outline: none !important;
+ box-shadow: none !important;
+ }
+
+ input {
+ border: 1px solid none !important;
+ background: none !important;
+ outline: none !important;
+ text-shadow: none !important;
+ box-shadow: none !important;
+
+ color: @glass-color;
+ border-color: @glass-m-color;
+
+ &::-webkit-input-placeholder {
+ color: @glass-color;
+ text-shadow: none !important;
+ }
+ &::-moz-placeholder {
+ color: @glass-color;
+ text-shadow: none !important;
+ }
+ &:-moz-placeholder {
+ color: @glass-color;
+ text-shadow: none !important;
+ }
+ &:-ms-input-placeholder {
+ color: @glass-color;
+ text-shadow: none !important;
+ }
+ &:input-placeholder {
+ color: @glass-color;
+ text-shadow: none !important;
+ }
+ &:placeholder {
+ color: @glass-color;
+ text-shadow: none !important;
+ }
+
+ &:focus, &:hover {
+ border-color: @glass-color;
+ }
+ }
+ .btn {
+ border: 1px solid none !important;
+ background: none !important;
+ outline: none !important;
+ text-shadow: none !important;
+ box-shadow: none !important;
+
+ color: @glass-color;
+ border-color: @glass-m-color;
+
+ text-transform: uppercase;
+ font-size: 13px;
+
+ &:hover, &:active{
+ border-color: @glass-color;
+ }
+ }
+
+ &.error {
+ .input-append .add-on i {
+ color: @glass-error-color;
+ }
+
+ input {
+ color: @glass-error-color;
+ border-color: @glass-error-color;
+ }
+ }
+ }
+ }
+
+ .thm-login-text {
+ color: @glass-m-color;
+ text-shadow: none !important;
+
+ .legend, .e-checkbox-icon, .g-ui-link, .social-button, .language-button {
+ color: @glass-m-color;
+ text-shadow: none !important;
+ }
+ }
+}
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Themes/values.less b/rainloop/app/rainloop/v/1.12.1/app/templates/Themes/values.less
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Themes/values.less
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Themes/values.less
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminLogin.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminLogin.html
similarity index 98%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminLogin.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminLogin.html
index db784c2a7278dd6d9082a4ab28ab9e8a219978e5..dc6c1176e617214a6b551dfc36afd36bd308d778 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminLogin.html
+++ b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminLogin.html
@@ -1,50 +1,50 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminMenu.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminMenu.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminMenu.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminMenu.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminPane.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminPane.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminPane.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminPane.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsAbout.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsAbout.html
similarity index 97%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsAbout.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsAbout.html
index 0ed3506ffe3b68d9d0aec9d16b820079a5e53b94..e3d57438cb0bbc2dcb6123ed7411b1633cad8475 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsAbout.html
+++ b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsAbout.html
@@ -1,87 +1,87 @@
-
-
+
\ No newline at end of file
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsBranding.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsBranding.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsBranding.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsBranding.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsContacts.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsContacts.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsContacts.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsContacts.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsDomainListItem.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsDomainListItem.html
similarity index 97%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsDomainListItem.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsDomainListItem.html
index b6f36ba9a0b2f563d78346ca38b9bcd576f3aa8a..6d32c4368b67e063fb933d54ca6818c79c32cc40 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsDomainListItem.html
+++ b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsDomainListItem.html
@@ -1,21 +1,21 @@
-
-
-
- (alias)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ (alias)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsDomains.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsDomains.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsDomains.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsDomains.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsGeneral.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsGeneral.html
similarity index 96%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsGeneral.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsGeneral.html
index 2cdbc347be42ad13cb86e71929e7228510698b4b..914af770c980a09a57de69a4cd600c86cf46a322 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsGeneral.html
+++ b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsGeneral.html
@@ -1,181 +1,181 @@
-
-
-
-
+
\ No newline at end of file
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsLicensing.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsLicensing.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsLicensing.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsLicensing.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsLogin.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsLogin.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsLogin.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsLogin.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsPackages.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPackages.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsPackages.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPackages.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsPackagesListItem.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPackagesListItem.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsPackagesListItem.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPackagesListItem.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsPackagesTable.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPackagesTable.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsPackagesTable.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPackagesTable.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsPluginListItem.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPluginListItem.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsPluginListItem.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPluginListItem.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsPluginProperty.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPluginProperty.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsPluginProperty.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPluginProperty.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsPlugins.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPlugins.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsPlugins.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsPlugins.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsSecurity.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsSecurity.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsSecurity.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsSecurity.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsSocial.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsSocial.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/AdminSettingsSocial.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/AdminSettingsSocial.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/PopupsActivate.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/PopupsActivate.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/PopupsActivate.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/PopupsActivate.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/PopupsDomain.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/PopupsDomain.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/PopupsDomain.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/PopupsDomain.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/PopupsDomainAlias.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/PopupsDomainAlias.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/PopupsDomainAlias.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/PopupsDomainAlias.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/PopupsPlugin.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/PopupsPlugin.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Admin/PopupsPlugin.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Admin/PopupsPlugin.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Common/Cmd.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/Cmd.html
similarity index 98%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Common/Cmd.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/Cmd.html
index 9cd70b5f39fea7a954a8fd7423af12851da6e233..f51b642bcf425c191101e2b257f49184d3a6f701 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Common/Cmd.html
+++ b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/Cmd.html
@@ -1,10 +1,10 @@
-
-
+
\ No newline at end of file
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Common/Pagenator.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/Pagenator.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Common/Pagenator.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/Pagenator.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Common/PopupsAsk.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/PopupsAsk.html
similarity index 96%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Common/PopupsAsk.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/PopupsAsk.html
index 93df1f523b47bfaf805afa9fcf0c9ad783f3dd94..4054b3b611e021fba1916ab719292c7cc9b59dda 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Common/PopupsAsk.html
+++ b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/PopupsAsk.html
@@ -1,26 +1,26 @@
-
+
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Common/PopupsKeyboardShortcutsHelp.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/PopupsKeyboardShortcutsHelp.html
similarity index 100%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Common/PopupsKeyboardShortcutsHelp.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/PopupsKeyboardShortcutsHelp.html
diff --git a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Common/PopupsLanguages.html b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/PopupsLanguages.html
similarity index 98%
rename from rainloop/app/rainloop/v/1.12.0/app/templates/Views/Common/PopupsLanguages.html
rename to rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/PopupsLanguages.html
index 03e3297bac99f0f52bcf1bdf6fd5a70fb7719096..0294673c0cba460abafc819acc5adea73a1751bb 100644
--- a/rainloop/app/rainloop/v/1.12.0/app/templates/Views/Common/PopupsLanguages.html
+++ b/rainloop/app/rainloop/v/1.12.1/app/templates/Views/Common/PopupsLanguages.html
@@ -1,22 +1,22 @@
-