mirror of
https://github.com/the-djmaze/snappymail.git
synced 2025-09-04 20:24:12 +08:00
+ Updated contacts sql shema (breaking changes) + Fixes - Removed SabreDAV Server - Removed Contacts Sharing (awhile, code refactoring)
This commit is contained in:
parent
54a4c2657a
commit
d29f20789f
78 changed files with 2024 additions and 2317 deletions
|
@ -190,7 +190,7 @@ AdminContacts.prototype.onBuild = function ()
|
|||
'ContactsSync': bValue ? '1' : '0'
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
self.contactsType.subscribe(function (sValue) {
|
||||
RL.remote().saveAdminConfig(f5, {
|
||||
'ContactsPdoType': sValue
|
||||
|
|
|
@ -14,7 +14,7 @@ Consts.Defaults.MessagesPerPage = 20;
|
|||
* @const
|
||||
* @type {number}
|
||||
*/
|
||||
Consts.Defaults.ContactsPerPage = 20;
|
||||
Consts.Defaults.ContactsPerPage = 50;
|
||||
|
||||
/**
|
||||
* @const
|
||||
|
@ -46,6 +46,12 @@ Consts.Defaults.SendMessageAjaxTimeout = 300000;
|
|||
*/
|
||||
Consts.Defaults.SaveMessageAjaxTimeout = 200000;
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {number}
|
||||
*/
|
||||
Consts.Defaults.ContactsSyncAjaxTimeout = 200000;
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {string}
|
||||
|
|
|
@ -263,14 +263,6 @@ Enums.Layout = {
|
|||
'BottomPreview': 2
|
||||
};
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
*/
|
||||
Enums.ContactScopeType = {
|
||||
'Default': 0,
|
||||
'ShareAll': 2
|
||||
};
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
*/
|
||||
|
@ -300,17 +292,9 @@ Enums.ContactPropertyType = {
|
|||
'NamePrefix': 20,
|
||||
'NameSuffix': 21,
|
||||
|
||||
'EmailPersonal': 30,
|
||||
'EmailBussines': 31,
|
||||
|
||||
'PhonePersonal': 50,
|
||||
'PhoneBussines': 51,
|
||||
|
||||
'MobilePersonal': 60,
|
||||
'MobileBussines': 61,
|
||||
|
||||
'FaxPesonal': 70,
|
||||
'FaxBussines': 71,
|
||||
'Email': 30,
|
||||
'Phone': 31,
|
||||
'Web': 32,
|
||||
|
||||
'Facebook': 90,
|
||||
'Skype': 91,
|
||||
|
@ -344,6 +328,8 @@ Enums.Notification = {
|
|||
'NewPasswordShort': 132,
|
||||
'NewPasswordWeak': 133,
|
||||
'NewPasswordForbidden': 134,
|
||||
|
||||
'ContactsSyncError': 140,
|
||||
|
||||
'CantGetMessageList': 201,
|
||||
'CantGetMessage': 202,
|
||||
|
|
|
@ -577,6 +577,8 @@ Utils.initNotificationLanguage = function ()
|
|||
NotificationI18N[Enums.Notification.NewPasswordWeak] = Utils.i18n('NOTIFICATIONS/NEW_PASSWORD_WEAK');
|
||||
NotificationI18N[Enums.Notification.NewPasswordForbidden] = Utils.i18n('NOTIFICATIONS/NEW_PASSWORD_FORBIDDENT');
|
||||
|
||||
NotificationI18N[Enums.Notification.ContactsSyncError] = Utils.i18n('NOTIFICATIONS/CONTACTS_SYNC_ERROR');
|
||||
|
||||
NotificationI18N[Enums.Notification.CantGetMessageList] = Utils.i18n('NOTIFICATIONS/CANT_GET_MESSAGE_LIST');
|
||||
NotificationI18N[Enums.Notification.CantGetMessage] = Utils.i18n('NOTIFICATIONS/CANT_GET_MESSAGE');
|
||||
NotificationI18N[Enums.Notification.CantDeleteMessage] = Utils.i18n('NOTIFICATIONS/CANT_DELETE_MESSAGE');
|
||||
|
@ -1362,6 +1364,15 @@ Utils.fakeMd5 = function(iLen)
|
|||
return sResult;
|
||||
};
|
||||
|
||||
/* jshint ignore:start */
|
||||
|
||||
/**
|
||||
* @param {string} s
|
||||
* @return {string}
|
||||
*/
|
||||
Utils.md5 = function(s){function L(k,d){return(k<<d)|(k>>>(32-d))}function K(G,k){var I,d,F,H,x;F=(G&2147483648);H=(k&2147483648);I=(G&1073741824);d=(k&1073741824);x=(G&1073741823)+(k&1073741823);if(I&d){return(x^2147483648^F^H)}if(I|d){if(x&1073741824){return(x^3221225472^F^H)}else{return(x^1073741824^F^H)}}else{return(x^F^H)}}function r(d,F,k){return(d&F)|((~d)&k)}function q(d,F,k){return(d&k)|(F&(~k))}function p(d,F,k){return(d^F^k)}function n(d,F,k){return(F^(d|(~k)))}function u(G,F,aa,Z,k,H,I){G=K(G,K(K(r(F,aa,Z),k),I));return K(L(G,H),F)}function f(G,F,aa,Z,k,H,I){G=K(G,K(K(q(F,aa,Z),k),I));return K(L(G,H),F)}function D(G,F,aa,Z,k,H,I){G=K(G,K(K(p(F,aa,Z),k),I));return K(L(G,H),F)}function t(G,F,aa,Z,k,H,I){G=K(G,K(K(n(F,aa,Z),k),I));return K(L(G,H),F)}function e(G){var Z;var F=G.length;var x=F+8;var k=(x-(x%64))/64;var I=(k+1)*16;var aa=Array(I-1);var d=0;var H=0;while(H<F){Z=(H-(H%4))/4;d=(H%4)*8;aa[Z]=(aa[Z]|(G.charCodeAt(H)<<d));H++}Z=(H-(H%4))/4;d=(H%4)*8;aa[Z]=aa[Z]|(128<<d);aa[I-2]=F<<3;aa[I-1]=F>>>29;return aa}function B(x){var k="",F="",G,d;for(d=0;d<=3;d++){G=(x>>>(d*8))&255;F="0"+G.toString(16);k=k+F.substr(F.length-2,2)}return k}function J(k){k=k.replace(/rn/g,"n");var d="";for(var F=0;F<k.length;F++){var x=k.charCodeAt(F);if(x<128){d+=String.fromCharCode(x)}else{if((x>127)&&(x<2048)){d+=String.fromCharCode((x>>6)|192);d+=String.fromCharCode((x&63)|128)}else{d+=String.fromCharCode((x>>12)|224);d+=String.fromCharCode(((x>>6)&63)|128);d+=String.fromCharCode((x&63)|128)}}}return d}var C=Array();var P,h,E,v,g,Y,X,W,V;var S=7,Q=12,N=17,M=22;var A=5,z=9,y=14,w=20;var o=4,m=11,l=16,j=23;var U=6,T=10,R=15,O=21;s=J(s);C=e(s);Y=1732584193;X=4023233417;W=2562383102;V=271733878;for(P=0;P<C.length;P+=16){h=Y;E=X;v=W;g=V;Y=u(Y,X,W,V,C[P+0],S,3614090360);V=u(V,Y,X,W,C[P+1],Q,3905402710);W=u(W,V,Y,X,C[P+2],N,606105819);X=u(X,W,V,Y,C[P+3],M,3250441966);Y=u(Y,X,W,V,C[P+4],S,4118548399);V=u(V,Y,X,W,C[P+5],Q,1200080426);W=u(W,V,Y,X,C[P+6],N,2821735955);X=u(X,W,V,Y,C[P+7],M,4249261313);Y=u(Y,X,W,V,C[P+8],S,1770035416);V=u(V,Y,X,W,C[P+9],Q,2336552879);W=u(W,V,Y,X,C[P+10],N,4294925233);X=u(X,W,V,Y,C[P+11],M,2304563134);Y=u(Y,X,W,V,C[P+12],S,1804603682);V=u(V,Y,X,W,C[P+13],Q,4254626195);W=u(W,V,Y,X,C[P+14],N,2792965006);X=u(X,W,V,Y,C[P+15],M,1236535329);Y=f(Y,X,W,V,C[P+1],A,4129170786);V=f(V,Y,X,W,C[P+6],z,3225465664);W=f(W,V,Y,X,C[P+11],y,643717713);X=f(X,W,V,Y,C[P+0],w,3921069994);Y=f(Y,X,W,V,C[P+5],A,3593408605);V=f(V,Y,X,W,C[P+10],z,38016083);W=f(W,V,Y,X,C[P+15],y,3634488961);X=f(X,W,V,Y,C[P+4],w,3889429448);Y=f(Y,X,W,V,C[P+9],A,568446438);V=f(V,Y,X,W,C[P+14],z,3275163606);W=f(W,V,Y,X,C[P+3],y,4107603335);X=f(X,W,V,Y,C[P+8],w,1163531501);Y=f(Y,X,W,V,C[P+13],A,2850285829);V=f(V,Y,X,W,C[P+2],z,4243563512);W=f(W,V,Y,X,C[P+7],y,1735328473);X=f(X,W,V,Y,C[P+12],w,2368359562);Y=D(Y,X,W,V,C[P+5],o,4294588738);V=D(V,Y,X,W,C[P+8],m,2272392833);W=D(W,V,Y,X,C[P+11],l,1839030562);X=D(X,W,V,Y,C[P+14],j,4259657740);Y=D(Y,X,W,V,C[P+1],o,2763975236);V=D(V,Y,X,W,C[P+4],m,1272893353);W=D(W,V,Y,X,C[P+7],l,4139469664);X=D(X,W,V,Y,C[P+10],j,3200236656);Y=D(Y,X,W,V,C[P+13],o,681279174);V=D(V,Y,X,W,C[P+0],m,3936430074);W=D(W,V,Y,X,C[P+3],l,3572445317);X=D(X,W,V,Y,C[P+6],j,76029189);Y=D(Y,X,W,V,C[P+9],o,3654602809);V=D(V,Y,X,W,C[P+12],m,3873151461);W=D(W,V,Y,X,C[P+15],l,530742520);X=D(X,W,V,Y,C[P+2],j,3299628645);Y=t(Y,X,W,V,C[P+0],U,4096336452);V=t(V,Y,X,W,C[P+7],T,1126891415);W=t(W,V,Y,X,C[P+14],R,2878612391);X=t(X,W,V,Y,C[P+5],O,4237533241);Y=t(Y,X,W,V,C[P+12],U,1700485571);V=t(V,Y,X,W,C[P+3],T,2399980690);W=t(W,V,Y,X,C[P+10],R,4293915773);X=t(X,W,V,Y,C[P+1],O,2240044497);Y=t(Y,X,W,V,C[P+8],U,1873313359);V=t(V,Y,X,W,C[P+15],T,4264355552);W=t(W,V,Y,X,C[P+6],R,2734768916);X=t(X,W,V,Y,C[P+13],O,1309151649);Y=t(Y,X,W,V,C[P+4],U,4149444226);V=t(V,Y,X,W,C[P+11],T,3174756917);W=t(W,V,Y,X,C[P+2],R,718787259);X=t(X,W,V,Y,C[P+9],O,3951481745);Y=K(Y,h);X=K(X,E);W=K(W,v);V=K(V,g)}var i=B(Y)+B(X)+B(W)+B(V);return i.toLowerCase()};
|
||||
/* jshint ignore:end */
|
||||
|
||||
Utils.convertPlainTextToHtml = function (sPlain)
|
||||
{
|
||||
return sPlain.toString()
|
||||
|
@ -1376,11 +1387,12 @@ Utils.draggeblePlace = function ()
|
|||
|
||||
Utils.defautOptionsAfterRender = function (oOption, oItem)
|
||||
{
|
||||
if (oItem && !Utils.isUnd(oItem.disabled))
|
||||
if (oItem && !Utils.isUnd(oItem.disabled) && oOption)
|
||||
{
|
||||
ko.applyBindingsToNode(oOption, {
|
||||
'disabled': oItem.disabled
|
||||
}, oItem);
|
||||
$(oOption)
|
||||
.toggleClass('disabled', oItem.disabled)
|
||||
.prop('disabled', oItem.disabled)
|
||||
;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -6,17 +6,14 @@
|
|||
function ContactModel()
|
||||
{
|
||||
this.idContact = 0;
|
||||
this.idContactStr = '';
|
||||
this.display = '';
|
||||
this.properties = [];
|
||||
this.readOnly = false;
|
||||
this.scopeType = Enums.ContactScopeType.Default;
|
||||
|
||||
this.focused = ko.observable(false);
|
||||
this.selected = ko.observable(false);
|
||||
this.checked = ko.observable(false);
|
||||
this.deleted = ko.observable(false);
|
||||
this.shared = ko.observable(false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -34,15 +31,15 @@ ContactModel.prototype.getNameAndEmailHelper = function ()
|
|||
_.each(this.properties, function (aProperty) {
|
||||
if (aProperty)
|
||||
{
|
||||
if ('' === sName && Enums.ContactPropertyType.FullName === aProperty[0])
|
||||
if (Enums.ContactPropertyType.FirstName === aProperty[0])
|
||||
{
|
||||
sName = aProperty[1];
|
||||
sName = Utils.trim(aProperty[1] + ' ' + sName);
|
||||
}
|
||||
else if ('' === sEmail && -1 < Utils.inArray(aProperty[0], [
|
||||
Enums.ContactPropertyType.EmailPersonal,
|
||||
Enums.ContactPropertyType.EmailBussines,
|
||||
Enums.ContactPropertyType.EmailOther
|
||||
]))
|
||||
else if (Enums.ContactPropertyType.LastName === aProperty[0])
|
||||
{
|
||||
sName = Utils.trim(sName + ' ' + aProperty[1]);
|
||||
}
|
||||
else if ('' === sEmail && Enums.ContactPropertyType.Email === aProperty[0])
|
||||
{
|
||||
sEmail = aProperty[1];
|
||||
}
|
||||
|
@ -59,22 +56,19 @@ ContactModel.prototype.parse = function (oItem)
|
|||
if (oItem && 'Object/Contact' === oItem['@Object'])
|
||||
{
|
||||
this.idContact = Utils.pInt(oItem['IdContact']);
|
||||
this.idContactStr = Utils.pString(oItem['IdContactStr']);
|
||||
this.display = Utils.pString(oItem['Display']);
|
||||
this.readOnly = !!oItem['ReadOnly'];
|
||||
this.scopeType = Utils.pInt(oItem['ScopeType']);
|
||||
|
||||
if (Utils.isNonEmptyArray(oItem['Properties']))
|
||||
{
|
||||
_.each(oItem['Properties'], function (oProperty) {
|
||||
if (oProperty && oProperty['Type'] && Utils.isNormal(oProperty['Value']))
|
||||
if (oProperty && oProperty['Type'] && Utils.isNormal(oProperty['Value']) && Utils.isNormal(oProperty['TypeStr']))
|
||||
{
|
||||
this.properties.push([Utils.pInt(oProperty['Type']), Utils.pString(oProperty['Value'])]);
|
||||
this.properties.push([Utils.pInt(oProperty['Type']), Utils.pString(oProperty['Value']), Utils.pString(oProperty['TypeStr'])]);
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
|
||||
this.shared(Enums.ContactScopeType.ShareAll === this.scopeType);
|
||||
bResult = true;
|
||||
}
|
||||
|
||||
|
@ -115,10 +109,6 @@ ContactModel.prototype.lineAsCcc = function ()
|
|||
{
|
||||
aResult.push('checked');
|
||||
}
|
||||
if (this.shared())
|
||||
{
|
||||
aResult.push('shared');
|
||||
}
|
||||
if (this.focused())
|
||||
{
|
||||
aResult.push('focused');
|
||||
|
|
|
@ -2,15 +2,17 @@
|
|||
|
||||
/**
|
||||
* @param {number=} iType = Enums.ContactPropertyType.Unknown
|
||||
* @param {string=} sTypeStr = ''
|
||||
* @param {string=} sValue = ''
|
||||
* @param {boolean=} bFocused = false
|
||||
* @param {string=} sPlaceholder = ''
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function ContactPropertyModel(iType, sValue, bFocused, sPlaceholder)
|
||||
function ContactPropertyModel(iType, sTypeStr, sValue, bFocused, sPlaceholder)
|
||||
{
|
||||
this.type = ko.observable(Utils.isUnd(iType) ? Enums.ContactPropertyType.Unknown : iType);
|
||||
this.typeStr = ko.observable(Utils.isUnd(sTypeStr) ? '' : sTypeStr);
|
||||
this.focused = ko.observable(Utils.isUnd(bFocused) ? false : !!bFocused);
|
||||
this.value = ko.observable(Utils.pString(sValue));
|
||||
|
||||
|
|
|
@ -8,22 +8,34 @@ function SettingsContacts()
|
|||
var oData = RL.data();
|
||||
|
||||
this.contactsAutosave = oData.contactsAutosave;
|
||||
this.showPassword = ko.observable(false);
|
||||
|
||||
this.allowContactsSync = !!RL.settingsGet('ContactsSyncIsAllowed');
|
||||
this.contactsSyncServer = RL.settingsGet('ContactsSyncServer');
|
||||
this.contactsSyncUser = RL.settingsGet('ContactsSyncUser');
|
||||
this.contactsSyncPass = RL.settingsGet('ContactsSyncPassword');
|
||||
this.contactsSyncPabUrl = RL.settingsGet('ContactsSyncPabUrl');
|
||||
this.allowContactsSync = oData.allowContactsSync;
|
||||
this.enableContactsSync = oData.enableContactsSync;
|
||||
this.contactsSyncUrl = oData.contactsSyncUrl;
|
||||
this.contactsSyncUser = oData.contactsSyncUser;
|
||||
this.contactsSyncPass = oData.contactsSyncPass;
|
||||
|
||||
this.saveTrigger = ko.computed(function () {
|
||||
return [
|
||||
this.enableContactsSync() ? '1' : '0',
|
||||
this.contactsSyncUrl(),
|
||||
this.contactsSyncUser(),
|
||||
this.contactsSyncPass()
|
||||
].join('|');
|
||||
}, this).extend({'throttle': 500});
|
||||
|
||||
this.saveTrigger.subscribe(function () {
|
||||
RL.remote().saveContactsSyncData(null,
|
||||
this.enableContactsSync(),
|
||||
this.contactsSyncUrl(),
|
||||
this.contactsSyncUser(),
|
||||
this.contactsSyncPass()
|
||||
);
|
||||
}, this);
|
||||
}
|
||||
|
||||
Utils.addSettingsViewModel(SettingsContacts, 'SettingsContacts', 'SETTINGS_LABELS/LABEL_CONTACTS_NAME', 'contacts');
|
||||
|
||||
SettingsContacts.prototype.toggleShowPassword = function ()
|
||||
{
|
||||
this.showPassword(!this.showPassword());
|
||||
};
|
||||
|
||||
SettingsContacts.prototype.onBuild = function ()
|
||||
{
|
||||
RL.data().contactsAutosave.subscribe(function (bValue) {
|
||||
|
@ -33,7 +45,7 @@ SettingsContacts.prototype.onBuild = function ()
|
|||
});
|
||||
};
|
||||
|
||||
SettingsContacts.prototype.onShow = function ()
|
||||
{
|
||||
this.showPassword(false);
|
||||
};
|
||||
//SettingsContacts.prototype.onShow = function ()
|
||||
//{
|
||||
//
|
||||
//};
|
||||
|
|
|
@ -8,6 +8,7 @@ function AbstractCacheStorage()
|
|||
this.oEmailsPicsHashes = {};
|
||||
this.oServices = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
*/
|
||||
|
@ -28,26 +29,36 @@ AbstractCacheStorage.prototype.clear = function ()
|
|||
* @param {string} sEmail
|
||||
* @return {string}
|
||||
*/
|
||||
AbstractCacheStorage.prototype.getUserPic = function (sEmail)
|
||||
AbstractCacheStorage.prototype.getUserPic = function (sEmail, fCallback)
|
||||
{
|
||||
sEmail = Utils.trim(sEmail);
|
||||
|
||||
var
|
||||
sUrl = '',
|
||||
sService = '',
|
||||
sEmailLower = sEmail.toLowerCase(),
|
||||
sPicHash = Utils.isUnd(this.oEmailsPicsHashes[sEmail]) ? '' : this.oEmailsPicsHashes[sEmail]
|
||||
sPicHash = Utils.isUnd(this.oEmailsPicsHashes[sEmailLower]) ? '' : this.oEmailsPicsHashes[sEmailLower]
|
||||
;
|
||||
|
||||
if ('' === sPicHash)
|
||||
|
||||
if ('' !== sPicHash)
|
||||
{
|
||||
sUrl = RL.link().getUserPicUrlFromHash(sPicHash);
|
||||
}
|
||||
else
|
||||
{
|
||||
sService = sEmailLower.substr(sEmail.indexOf('@') + 1);
|
||||
sUrl = '' !== sService && this.oServices[sService] ? this.oServices[sService] : '';
|
||||
}
|
||||
else
|
||||
{
|
||||
sUrl = RL.link().getUserPicUrlFromHash(sPicHash);
|
||||
}
|
||||
|
||||
|
||||
return sUrl;
|
||||
// if ('' === sUrl) // Gravatar // TODO
|
||||
// {
|
||||
// fCallback('//secure.gravatar.com/avatar/' + Utils.md5(sEmailLower) + '.jpg?s=80&d=mm', sEmail);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
fCallback(sUrl, sEmail);
|
||||
// }
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -112,6 +112,31 @@ WebMailAjaxRemoteStorage.prototype.clearTwoFactorInfo = function (fCallback)
|
|||
this.defaultRequest(fCallback, 'ClearTwoFactorInfo');
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {?Function} fCallback
|
||||
*/
|
||||
WebMailAjaxRemoteStorage.prototype.contactsSync = function (fCallback)
|
||||
{
|
||||
this.defaultRequest(fCallback, 'ContactsSync', null, Consts.Defaults.ContactsSyncAjaxTimeout);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {?Function} fCallback
|
||||
* @param {boolean} bEnable
|
||||
* @param {string} sUrl
|
||||
* @param {string} sUser
|
||||
* @param {string} sPassword
|
||||
*/
|
||||
WebMailAjaxRemoteStorage.prototype.saveContactsSyncData = function (fCallback, bEnable, sUrl, sUser, sPassword)
|
||||
{
|
||||
this.defaultRequest(fCallback, 'SaveContactsSyncData', {
|
||||
'Enable': bEnable ? '1' : '0',
|
||||
'Url': sUrl,
|
||||
'User': sUser,
|
||||
'Password': sPassword
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {?Function} fCallback
|
||||
* @param {string} sEmail
|
||||
|
@ -659,13 +684,11 @@ WebMailAjaxRemoteStorage.prototype.contacts = function (fCallback, iOffset, iLim
|
|||
/**
|
||||
* @param {?Function} fCallback
|
||||
*/
|
||||
WebMailAjaxRemoteStorage.prototype.contactSave = function (fCallback, sRequestUid, sUid, sUidStr, iScopeType, aProperties)
|
||||
WebMailAjaxRemoteStorage.prototype.contactSave = function (fCallback, sRequestUid, sUid, aProperties)
|
||||
{
|
||||
this.defaultRequest(fCallback, 'ContactSave', {
|
||||
'RequestUid': sRequestUid,
|
||||
'Uid': Utils.trim(sUid),
|
||||
'UidStr': Utils.trim(sUidStr),
|
||||
'ScopeType': iScopeType,
|
||||
'Properties': aProperties
|
||||
});
|
||||
};
|
||||
|
|
|
@ -82,6 +82,18 @@ function WebMailDataStorage()
|
|||
this.identities = ko.observableArray([]);
|
||||
this.identitiesLoading = ko.observable(false).extend({'throttle': 100});
|
||||
|
||||
this.allowContactsSync = ko.observable(false);
|
||||
this.enableContactsSync = ko.observable(false);
|
||||
this.contactsSyncUrl = ko.observable('');
|
||||
this.contactsSyncUser = ko.observable('');
|
||||
this.contactsSyncPass = ko.observable('');
|
||||
|
||||
this.allowContactsSync = ko.observable(!!RL.settingsGet('ContactsSyncIsAllowed'));
|
||||
this.enableContactsSync = ko.observable(!!RL.settingsGet('EnableContactsSync'));
|
||||
this.contactsSyncUrl = ko.observable(RL.settingsGet('ContactsSyncUrl'));
|
||||
this.contactsSyncUser = ko.observable(RL.settingsGet('ContactsSyncUser'));
|
||||
this.contactsSyncPass = ko.observable(RL.settingsGet('ContactsSyncPassword'));
|
||||
|
||||
// folders
|
||||
this.namespace = '';
|
||||
this.folderList = ko.observableArray([]);
|
||||
|
|
|
@ -9,9 +9,9 @@ function MailBoxMessageViewViewModel()
|
|||
KnoinAbstractViewModel.call(this, 'Right', 'MailMessageView');
|
||||
|
||||
var
|
||||
sPic = '',
|
||||
oData = RL.data(),
|
||||
self = this,
|
||||
sLastEmail = '',
|
||||
oData = RL.data(),
|
||||
createCommandHelper = function (sType) {
|
||||
return Utils.createCommand(self, function () {
|
||||
this.replyOrforward(sType);
|
||||
|
@ -155,17 +155,19 @@ function MailBoxMessageViewViewModel()
|
|||
this.viewViewLink(oMessage.viewLink());
|
||||
this.viewDownloadLink(oMessage.downloadLink());
|
||||
|
||||
sPic = RL.cache().getUserPic(oMessage.fromAsSingleEmail());
|
||||
if (sPic !== this.viewUserPic())
|
||||
{
|
||||
this.viewUserPicVisible(false);
|
||||
this.viewUserPic(Consts.DataImages.UserDotPic);
|
||||
if ('' !== sPic)
|
||||
sLastEmail = oMessage.fromAsSingleEmail();
|
||||
RL.cache().getUserPic(sLastEmail, function (sPic, $sEmail) {
|
||||
if (sPic !== self.viewUserPic() && sLastEmail === $sEmail)
|
||||
{
|
||||
this.viewUserPicVisible(true);
|
||||
this.viewUserPic(sPic);
|
||||
self.viewUserPicVisible(false);
|
||||
self.viewUserPic(Consts.DataImages.UserDotPic);
|
||||
if ('' !== sPic)
|
||||
{
|
||||
self.viewUserPicVisible(true);
|
||||
self.viewUserPic(sPic);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}, this);
|
||||
|
|
|
@ -16,7 +16,7 @@ function PopupsAdvancedSearchViewModel()
|
|||
this.text = ko.observable('');
|
||||
this.selectedDateValue = ko.observable(-1);
|
||||
|
||||
this.hasAttachments = ko.observable(false);
|
||||
this.hasAttachment = ko.observable(false);
|
||||
this.starred = ko.observable(false);
|
||||
this.unseen = ko.observable(false);
|
||||
|
||||
|
@ -54,6 +54,7 @@ PopupsAdvancedSearchViewModel.prototype.buildSearchString = function ()
|
|||
sTo = Utils.trim(this.to()),
|
||||
sSubject = Utils.trim(this.subject()),
|
||||
sText = Utils.trim(this.text()),
|
||||
aIs = [],
|
||||
aHas = []
|
||||
;
|
||||
|
||||
|
@ -72,19 +73,19 @@ PopupsAdvancedSearchViewModel.prototype.buildSearchString = function ()
|
|||
aResult.push('subject:' + this.buildSearchStringValue(sSubject));
|
||||
}
|
||||
|
||||
if (this.hasAttachments())
|
||||
if (this.hasAttachment())
|
||||
{
|
||||
aHas.push('attachments');
|
||||
aHas.push('attachment');
|
||||
}
|
||||
|
||||
if (this.unseen())
|
||||
{
|
||||
aHas.push('unseen');
|
||||
aIs.push('unseen');
|
||||
}
|
||||
|
||||
if (this.starred())
|
||||
{
|
||||
aHas.push('flag');
|
||||
aIs.push('flagged');
|
||||
}
|
||||
|
||||
if (0 < aHas.length)
|
||||
|
@ -92,6 +93,11 @@ PopupsAdvancedSearchViewModel.prototype.buildSearchString = function ()
|
|||
aResult.push('has:' + aHas.join(','));
|
||||
}
|
||||
|
||||
if (0 < aIs.length)
|
||||
{
|
||||
aResult.push('is:' + aIs.join(','));
|
||||
}
|
||||
|
||||
if (-1 < this.selectedDateValue())
|
||||
{
|
||||
aResult.push('date:' + moment().subtract('days', this.selectedDateValue()).format('YYYY.MM.DD') + '/');
|
||||
|
@ -113,7 +119,7 @@ PopupsAdvancedSearchViewModel.prototype.clearPopup = function ()
|
|||
this.text('');
|
||||
|
||||
this.selectedDateValue(-1);
|
||||
this.hasAttachments(false);
|
||||
this.hasAttachment(false);
|
||||
this.starred(false);
|
||||
this.unseen(false);
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ function PopupsComposeOpenPgpViewModel()
|
|||
var aKeys = oData.findPublicKeysByEmail(sEmail);
|
||||
if (0 === aKeys.length && bResult)
|
||||
{
|
||||
this.notification(Utils.i18n('PGP_NOTIFICATIONS/NO_PUBLIC_KEYS_FOUND_FOR', {
|
||||
self.notification(Utils.i18n('PGP_NOTIFICATIONS/NO_PUBLIC_KEYS_FOUND_FOR', {
|
||||
'EMAIL': sEmail
|
||||
}));
|
||||
|
||||
|
|
|
@ -10,17 +10,6 @@ function PopupsContactsViewModel()
|
|||
|
||||
var
|
||||
self = this,
|
||||
oT = Enums.ContactPropertyType,
|
||||
aNameTypes = [oT.FirstName, oT.LastName],
|
||||
aEmailTypes = [oT.EmailPersonal, oT.EmailBussines, oT.EmailOther],
|
||||
aPhonesTypes = [
|
||||
oT.PhonePersonal, oT.PhoneBussines, oT.PhoneOther,
|
||||
oT.MobilePersonal, oT.MobileBussines, oT.MobileOther,
|
||||
oT.FaxPesonal, oT.FaxBussines, oT.FaxOther
|
||||
],
|
||||
aOtherTypes = [
|
||||
oT.Facebook, oT.Skype, oT.GitHub
|
||||
],
|
||||
fFastClearEmptyListHelper = function (aList) {
|
||||
if (aList && 0 < aList.length) {
|
||||
self.viewProperties.removeAll(aList);
|
||||
|
@ -28,18 +17,19 @@ function PopupsContactsViewModel()
|
|||
}
|
||||
;
|
||||
|
||||
this.enableContactsSync = RL.data().enableContactsSync;
|
||||
|
||||
this.search = ko.observable('');
|
||||
this.contactsCount = ko.observable(0);
|
||||
this.contacts = ko.observableArray([]);
|
||||
this.contacts.loading = ko.observable(false).extend({'throttle': 200});
|
||||
this.contacts.importing = ko.observable(false).extend({'throttle': 200});
|
||||
this.contacts.syncing = ko.observable(false).extend({'throttle': 200});
|
||||
|
||||
this.currentContact = ko.observable(null);
|
||||
|
||||
this.importUploaderButton = ko.observable(null);
|
||||
|
||||
this.contactsSharingIsAllowed = !!RL.settingsGet('ContactsSharingIsAllowed');
|
||||
|
||||
this.contactsPage = ko.observable(1);
|
||||
this.contactsPageCount = ko.computed(function () {
|
||||
var iPage = Math.ceil(this.contactsCount() / Consts.Defaults.ContactsPerPage);
|
||||
|
@ -52,33 +42,19 @@ function PopupsContactsViewModel()
|
|||
this.viewClearSearch = ko.observable(false);
|
||||
|
||||
this.viewID = ko.observable('');
|
||||
this.viewIDStr = ko.observable('');
|
||||
this.viewReadOnly = ko.observable(false);
|
||||
this.viewScopeType = ko.observable(Enums.ContactScopeType.Default);
|
||||
this.viewProperties = ko.observableArray([]);
|
||||
|
||||
this.viewSaveTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
|
||||
|
||||
this.viewPropertiesNames = this.viewProperties.filter(function(oProperty) {
|
||||
return -1 < Utils.inArray(oProperty.type(), aNameTypes);
|
||||
return -1 < Utils.inArray(oProperty.type(), [Enums.ContactPropertyType.FirstName, Enums.ContactPropertyType.LastName]);
|
||||
});
|
||||
|
||||
this.viewPropertiesEmails = this.viewProperties.filter(function(oProperty) {
|
||||
return -1 < Utils.inArray(oProperty.type(), aEmailTypes);
|
||||
return Enums.ContactPropertyType.Email === oProperty.type();
|
||||
});
|
||||
|
||||
this.shareIcon = ko.computed(function() {
|
||||
return Enums.ContactScopeType.ShareAll === this.viewScopeType() ? 'icon-earth' : 'icon-share';
|
||||
}, this);
|
||||
|
||||
this.shareToNone = ko.computed(function() {
|
||||
return Enums.ContactScopeType.ShareAll !== this.viewScopeType();
|
||||
}, this);
|
||||
|
||||
this.shareToAll = ko.computed(function() {
|
||||
return Enums.ContactScopeType.ShareAll === this.viewScopeType();
|
||||
}, this);
|
||||
|
||||
this.viewHasNonEmptyRequaredProperties = ko.computed(function() {
|
||||
|
||||
var
|
||||
|
@ -93,11 +69,7 @@ function PopupsContactsViewModel()
|
|||
}, this);
|
||||
|
||||
this.viewPropertiesPhones = this.viewProperties.filter(function(oProperty) {
|
||||
return -1 < Utils.inArray(oProperty.type(), aPhonesTypes);
|
||||
});
|
||||
|
||||
this.viewPropertiesOther = this.viewProperties.filter(function(oProperty) {
|
||||
return -1 < Utils.inArray(oProperty.type(), aOtherTypes);
|
||||
return Enums.ContactPropertyType.Phone === oProperty.type();
|
||||
});
|
||||
|
||||
this.viewPropertiesEmailsNonEmpty = this.viewPropertiesNames.filter(function(oProperty) {
|
||||
|
@ -167,6 +139,10 @@ function PopupsContactsViewModel()
|
|||
|
||||
this.selector.on('onItemSelect', _.bind(function (oContact) {
|
||||
this.populateViewContact(oContact ? oContact : null);
|
||||
if (!oContact)
|
||||
{
|
||||
this.emptySelection(true);
|
||||
}
|
||||
}, this));
|
||||
|
||||
this.selector.on('onItemGetUid', function (oContact) {
|
||||
|
@ -236,7 +212,7 @@ function PopupsContactsViewModel()
|
|||
_.each(this.viewProperties(), function (oItem) {
|
||||
if (oItem.type() && '' !== Utils.trim(oItem.value()))
|
||||
{
|
||||
aProperties.push([oItem.type(), oItem.value()]);
|
||||
aProperties.push([oItem.type(), oItem.value(), oItem.typeStr()]);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -253,11 +229,6 @@ function PopupsContactsViewModel()
|
|||
self.viewID(Utils.pInt(oData.Result.ResultID));
|
||||
}
|
||||
|
||||
if ('' === self.viewIDStr())
|
||||
{
|
||||
self.viewIDStr(Utils.pString(oData.Result.ResultIDStr));
|
||||
}
|
||||
|
||||
self.reloadContactList();
|
||||
bRes = true;
|
||||
}
|
||||
|
@ -275,7 +246,7 @@ function PopupsContactsViewModel()
|
|||
}, 1000);
|
||||
}
|
||||
|
||||
}, sRequestUid, this.viewID(), this.viewIDStr(), this.viewScopeType(), aProperties);
|
||||
}, sRequestUid, this.viewID(), aProperties);
|
||||
|
||||
}, function () {
|
||||
var
|
||||
|
@ -285,13 +256,43 @@ function PopupsContactsViewModel()
|
|||
return !this.viewSaving() && bV && !bReadOnly;
|
||||
});
|
||||
|
||||
this.syncCommand = Utils.createCommand(this, function () {
|
||||
|
||||
if (this.contacts.syncing())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
|
||||
this.contacts.syncing(true);
|
||||
|
||||
|
||||
RL.remote().contactsSync(function (sResult, oData) {
|
||||
|
||||
self.contacts.syncing(false);
|
||||
|
||||
if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result)
|
||||
{
|
||||
window.alert(Utils.getNotification(
|
||||
oData && oData.ErrorCode ? oData.ErrorCode : Enums.Notification.ContactsSyncError));
|
||||
}
|
||||
|
||||
self.reloadContactList(true);
|
||||
|
||||
});
|
||||
|
||||
}, function () {
|
||||
return !this.contacts.syncing() && !this.contacts.importing();
|
||||
});
|
||||
|
||||
this.bDropPageAfterDelete = false;
|
||||
|
||||
this.watchDirty = ko.observable(false);
|
||||
this.watchHash = ko.observable(false);
|
||||
|
||||
this.viewHash = ko.computed(function () {
|
||||
return '' + self.viewScopeType() + ' - ' + _.map(self.viewProperties(), function (oItem) {
|
||||
return '' + _.map(self.viewProperties(), function (oItem) {
|
||||
return oItem.value();
|
||||
}).join('');
|
||||
});
|
||||
|
@ -312,31 +313,21 @@ function PopupsContactsViewModel()
|
|||
|
||||
Utils.extendAsViewModel('PopupsContactsViewModel', PopupsContactsViewModel);
|
||||
|
||||
PopupsContactsViewModel.prototype.setShareToNone = function ()
|
||||
PopupsContactsViewModel.prototype.addNewProperty = function (sType, sTypeStr)
|
||||
{
|
||||
this.viewScopeType(Enums.ContactScopeType.Default);
|
||||
};
|
||||
|
||||
PopupsContactsViewModel.prototype.setShareToAll = function ()
|
||||
{
|
||||
this.viewScopeType(Enums.ContactScopeType.ShareAll);
|
||||
};
|
||||
|
||||
PopupsContactsViewModel.prototype.addNewProperty = function (sType)
|
||||
{
|
||||
var oItem = new ContactPropertyModel(sType, '');
|
||||
var oItem = new ContactPropertyModel(sType, sTypeStr || '', '');
|
||||
oItem.focused(true);
|
||||
this.viewProperties.push(oItem);
|
||||
};
|
||||
|
||||
PopupsContactsViewModel.prototype.addNewEmail = function ()
|
||||
{
|
||||
this.addNewProperty(Enums.ContactPropertyType.EmailPersonal);
|
||||
this.addNewProperty(Enums.ContactPropertyType.Email, 'Home');
|
||||
};
|
||||
|
||||
PopupsContactsViewModel.prototype.addNewPhone = function ()
|
||||
{
|
||||
this.addNewProperty(Enums.ContactPropertyType.MobilePersonal);
|
||||
this.addNewProperty(Enums.ContactPropertyType.Phone, 'Mobile');
|
||||
};
|
||||
|
||||
PopupsContactsViewModel.prototype.initUploader = function ()
|
||||
|
@ -463,7 +454,6 @@ PopupsContactsViewModel.prototype.populateViewContact = function (oContact)
|
|||
{
|
||||
var
|
||||
sId = '',
|
||||
sIdStr = '',
|
||||
sLastName = '',
|
||||
sFirstName = '',
|
||||
aList = []
|
||||
|
@ -473,13 +463,10 @@ PopupsContactsViewModel.prototype.populateViewContact = function (oContact)
|
|||
|
||||
this.emptySelection(false);
|
||||
this.viewReadOnly(false);
|
||||
this.viewScopeType(Enums.ContactScopeType.Default);
|
||||
|
||||
if (oContact)
|
||||
{
|
||||
sId = oContact.idContact;
|
||||
sIdStr = oContact.idContactStr;
|
||||
|
||||
if (Utils.isNonEmptyArray(oContact.properties))
|
||||
{
|
||||
_.each(oContact.properties, function (aProperty) {
|
||||
|
@ -493,23 +480,21 @@ PopupsContactsViewModel.prototype.populateViewContact = function (oContact)
|
|||
{
|
||||
sFirstName = aProperty[1];
|
||||
}
|
||||
else if (-1 === Utils.inArray(aProperty[0], [Enums.ContactPropertyType.FullName]))
|
||||
else
|
||||
{
|
||||
aList.push(new ContactPropertyModel(aProperty[0], aProperty[1]));
|
||||
aList.push(new ContactPropertyModel(aProperty[0], aProperty[2] || '', aProperty[1]));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.viewReadOnly(!!oContact.readOnly);
|
||||
this.viewScopeType(oContact.scopeType);
|
||||
}
|
||||
|
||||
aList.unshift(new ContactPropertyModel(Enums.ContactPropertyType.LastName, sLastName, !oContact, 'CONTACTS/PLACEHOLDER_ENTER_LAST_NAME'));
|
||||
aList.unshift(new ContactPropertyModel(Enums.ContactPropertyType.FirstName, sFirstName, false, 'CONTACTS/PLACEHOLDER_ENTER_FIRST_NAME'));
|
||||
aList.unshift(new ContactPropertyModel(Enums.ContactPropertyType.LastName, '', sLastName, !oContact, 'CONTACTS/PLACEHOLDER_ENTER_LAST_NAME'));
|
||||
aList.unshift(new ContactPropertyModel(Enums.ContactPropertyType.FirstName, '', sFirstName, false, 'CONTACTS/PLACEHOLDER_ENTER_FIRST_NAME'));
|
||||
|
||||
this.viewID(sId);
|
||||
this.viewIDStr(sIdStr);
|
||||
this.viewProperties([]);
|
||||
this.viewProperties(aList);
|
||||
|
||||
|
@ -548,7 +533,7 @@ PopupsContactsViewModel.prototype.reloadContactList = function (bDropPagePositio
|
|||
{
|
||||
aList = _.map(oData.Result.List, function (oItem) {
|
||||
var oContact = new ContactModel();
|
||||
return oContact.parse(oItem, self.contactsSharingIsAllowed) ? oContact : null;
|
||||
return oContact.parse(oItem) ? oContact : null;
|
||||
});
|
||||
|
||||
aList = _.compact(aList);
|
||||
|
@ -564,11 +549,6 @@ PopupsContactsViewModel.prototype.reloadContactList = function (bDropPagePositio
|
|||
self.viewClearSearch('' !== self.search());
|
||||
self.contacts.loading(false);
|
||||
|
||||
// if ('' !== self.viewID() && !self.currentContact() && self.contacts.setSelectedByUid)
|
||||
// {
|
||||
// self.contacts.setSelectedByUid('' + self.viewID());
|
||||
// }
|
||||
|
||||
}, iOffset, Consts.Defaults.ContactsPerPage, this.search());
|
||||
};
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"name": "RainLoop",
|
||||
"title": "RainLoop Webmail",
|
||||
"version": "1.6.5",
|
||||
"release": "903",
|
||||
"release": "908",
|
||||
"description": "Simple, modern & fast web-based email client",
|
||||
"homepage": "http://rainloop.net",
|
||||
"main": "Gruntfile.js",
|
||||
|
|
|
@ -18,7 +18,7 @@ if (!\defined('RAINLOOP_APP_ROOT_PATH'))
|
|||
if (!RAINLOOP_MB_SUPPORTED && !defined('RL_MB_FIXED'))
|
||||
{
|
||||
\define('RL_MB_FIXED', true);
|
||||
include_once RAINLOOP_APP_LIBRARIES_PATH.'RainLoop/SabreDAV/MbStringFix.php';
|
||||
include_once RAINLOOP_APP_LIBRARIES_PATH.'RainLoop/Common/MbStringFix.php';
|
||||
}
|
||||
|
||||
return include RAINLOOP_APP_LIBRARIES_PATH.'Sabre/'.\str_replace('\\', '/', \substr($sClassName, 6)).'.php';
|
||||
|
|
|
@ -77,11 +77,6 @@ class Actions
|
|||
*/
|
||||
private $oAddressBookProvider;
|
||||
|
||||
/**
|
||||
* @var \RainLoop\Providers\PersonalAddressBook
|
||||
*/
|
||||
private $oPersonalAddressBookProvider;
|
||||
|
||||
/**
|
||||
* @var \RainLoop\Providers\Suggestions
|
||||
*/
|
||||
|
@ -127,7 +122,6 @@ class Actions
|
|||
$this->oSettingsProvider = null;
|
||||
$this->oDomainProvider = null;
|
||||
$this->oAddressBookProvider = null;
|
||||
$this->oPersonalAddressBookProvider = null;
|
||||
$this->oSuggestionsProvider = null;
|
||||
$this->oChangePasswordProvider = null;
|
||||
$this->oTwoFactorAuthProvider = null;
|
||||
|
@ -242,26 +236,6 @@ class Actions
|
|||
$oResult = new \RainLoop\Providers\Domain\DefaultDomain(APP_PRIVATE_DATA.'domains',
|
||||
$this->Cacher());
|
||||
break;
|
||||
case 'personal-address-book':
|
||||
// \RainLoop\Providers\PersonalAddressBook\PersonalAddressBookInterface
|
||||
|
||||
$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)
|
||||
{
|
||||
$oResult = new \RainLoop\Providers\PersonalAddressBook\PdoPersonalAddressBook(
|
||||
'sqlite:'.APP_PRIVATE_DATA.'PersonalAddressBook.sqlite', '', '', 'sqlite');
|
||||
}
|
||||
else
|
||||
{
|
||||
$oResult = new \RainLoop\Providers\PersonalAddressBook\PdoPersonalAddressBook($sDsn, $sUser, $sPassword, $sDsnType);
|
||||
}
|
||||
|
||||
$oResult->SetLogger($this->Logger());
|
||||
break;
|
||||
case 'address-book':
|
||||
// \RainLoop\Providers\AddressBook\AddressBookInterface
|
||||
|
||||
|
@ -625,32 +599,6 @@ class Actions
|
|||
return $this->oAddressBookProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account $oAccount = null
|
||||
* @param bool $bForceEnable = false
|
||||
*
|
||||
* @return \RainLoop\Providers\PersonalAddressBook
|
||||
*/
|
||||
public function PersonalAddressBookProvider($oAccount = null, $bForceEnable = false)
|
||||
{
|
||||
if (null === $this->oPersonalAddressBookProvider)
|
||||
{
|
||||
$this->oPersonalAddressBookProvider = new \RainLoop\Providers\PersonalAddressBook(
|
||||
$this->Config()->Get('contacts', 'enable', false) || $bForceEnable ? $this->fabrica('personal-address-book', $oAccount) : null);
|
||||
|
||||
$this->oPersonalAddressBookProvider->SetLogger($this->Logger());
|
||||
|
||||
$this->oPersonalAddressBookProvider->ConsiderShare(
|
||||
!!$this->Config()->Get('contacts', 'allow_sharing', false));
|
||||
}
|
||||
else if ($oAccount && $this->oPersonalAddressBookProvider->IsSupported())
|
||||
{
|
||||
$this->oPersonalAddressBookProvider->SetAccount($oAccount);
|
||||
}
|
||||
|
||||
return $this->oPersonalAddressBookProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \OAuth2\Client|null
|
||||
*/
|
||||
|
@ -1033,10 +981,10 @@ class Actions
|
|||
'CustomLogoutLink' => $oConfig->Get('labs', 'custom_logout_link', ''),
|
||||
'AllowAdditionalAccounts' => (bool) $oConfig->Get('webmail', 'allow_additional_accounts', true),
|
||||
'AllowIdentities' => (bool) $oConfig->Get('webmail', 'allow_identities', true),
|
||||
'DetermineUserLanguage' => (bool) $oConfig->Get('labs', 'determine_user_language', false),
|
||||
'AllowPrefetch' => (bool) $oConfig->Get('labs', 'allow_prefetch', true),
|
||||
'AllowCustomLogin' => (bool) $oConfig->Get('login', 'allow_custom_login', false),
|
||||
'LoginDefaultDomain' => $oConfig->Get('login', 'default_domain', ''),
|
||||
'DetermineUserLanguage' => (bool) $oConfig->Get('labs', 'determine_user_language', false),
|
||||
'AllowThemes' => (bool) $oConfig->Get('webmail', 'allow_themes', true),
|
||||
'AllowCustomTheme' => (bool) $oConfig->Get('webmail', 'allow_custom_theme', true),
|
||||
'ChangePasswordIsAllowed' => false,
|
||||
|
@ -1060,7 +1008,7 @@ class Actions
|
|||
$oAccount = $this->getAccountFromToken(false);
|
||||
if ($oAccount instanceof \RainLoop\Account)
|
||||
{
|
||||
$oPab = $this->PersonalAddressBookProvider($oAccount);
|
||||
$oAddressBookProvider = $this->AddressBookProvider($oAccount);
|
||||
|
||||
$aResult['Auth'] = true;
|
||||
$aResult['Email'] = $oAccount->Email();
|
||||
|
@ -1069,59 +1017,27 @@ class Actions
|
|||
$aResult['AccountHash'] = $oAccount->Hash();
|
||||
$aResult['AccountSignMe'] = $oAccount->SignMe();
|
||||
$aResult['ChangePasswordIsAllowed'] = $this->ChangePasswordProvider()->PasswordChangePossibility($oAccount);
|
||||
$aResult['ContactsIsAllowed'] = $oPab->IsActive();
|
||||
$aResult['ContactsSharingIsAllowed'] = $oPab->IsSharingAllowed();
|
||||
|
||||
$aResult['ContactsIsAllowed'] = $oAddressBookProvider->IsActive();
|
||||
$aResult['ContactsSharingIsAllowed'] = $oAddressBookProvider->IsSharingAllowed();
|
||||
$aResult['ContactsSyncIsAllowed'] = (bool) $oConfig->Get('contacts', 'allow_sync', false);
|
||||
$aResult['ContactsSyncServer'] = '';
|
||||
|
||||
$aResult['EnableContactsSync'] = false;
|
||||
$aResult['ContactsSyncUrl'] = '';
|
||||
$aResult['ContactsSyncUser'] = '';
|
||||
$aResult['ContactsSyncPassword'] = '';
|
||||
$aResult['ContactsSyncPabUrl'] = '';
|
||||
|
||||
if ($aResult['ContactsSyncIsAllowed'])
|
||||
if ($aResult['ContactsIsAllowed'] && $aResult['ContactsSyncIsAllowed'])
|
||||
{
|
||||
$sDavDomain = (string) $oConfig->Get('labs', 'sync_dav_domain', '');
|
||||
if (empty($sDavDomain))
|
||||
$mData = $this->getContactsSyncData($oAccount);
|
||||
if (\is_array($mData))
|
||||
{
|
||||
$aResult['ContactsSyncServer'] = $this->Http()->GetHost(false, true, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sDavDomain = \rtrim($sDavDomain, '/\\ ');
|
||||
$sDavDomainWithoutScheme = \preg_replace('/https?:\/\//i', '', \trim($sDavDomain));
|
||||
|
||||
$aResult['ContactsSyncServer'] = $sDavDomainWithoutScheme;
|
||||
}
|
||||
|
||||
$aResult['ContactsSyncUser'] = $oAccount->ParentEmailHelper();
|
||||
|
||||
try
|
||||
{
|
||||
$aResult['ContactsSyncPassword'] = $oPab->GetUserHashByEmail($aResult['ContactsSyncUser'], true);
|
||||
}
|
||||
catch (\Exception $oException)
|
||||
{
|
||||
$this->Logger()->WriteException($oException);
|
||||
}
|
||||
|
||||
if (empty($sDavDomain))
|
||||
{
|
||||
$sUrl = \rtrim(\trim($this->Http()->GetScheme().'://'.$this->Http()->GetHost(true, false).$this->Http()->GetPath()), '/\\');
|
||||
$sUrl = \preg_replace('/index\.php(.*)$/i', '', $sUrl);
|
||||
|
||||
$aResult['ContactsSyncPabUrl'] = $sUrl.'/index.php/dav/';
|
||||
}
|
||||
else
|
||||
{
|
||||
$aResult['ContactsSyncPabUrl'] = \preg_match('/^https?:\/\//i', $sDavDomain) ? $sDavDomain : 'http://'.$sDavDomain;
|
||||
}
|
||||
|
||||
if (!empty($aResult['ContactsSyncPabUrl']))
|
||||
{
|
||||
$aResult['ContactsSyncPabUrl'] .= '/addressbooks/'.$oAccount->ParentEmailHelper().'/default/';
|
||||
$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);
|
||||
|
@ -2273,7 +2189,7 @@ class Actions
|
|||
return $self->ValidateContactPdoType($sType);
|
||||
});
|
||||
|
||||
$sTestMessage = $this->PersonalAddressBookProvider(null, true)->Test();
|
||||
$sTestMessage = $this->AddressBookProvider(null, true)->Test();
|
||||
return $this->DefaultResponse(__FUNCTION__, array(
|
||||
'Result' => '' === $sTestMessage,
|
||||
'Message' => \MailSo\Base\Utils::Utf8Clear($sTestMessage, '?')
|
||||
|
@ -4571,7 +4487,7 @@ class Actions
|
|||
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantSendMessage);
|
||||
}
|
||||
|
||||
if ($oMessage && $this->PersonalAddressBookProvider($oAccount)->IsActive())
|
||||
if ($oMessage && $this->AddressBookProvider($oAccount)->IsActive())
|
||||
{
|
||||
$aArrayToFrec = array();
|
||||
$oToCollection = $oMessage->GetTo();
|
||||
|
@ -4588,7 +4504,7 @@ class Actions
|
|||
{
|
||||
$oSettings = $this->SettingsProvider()->Load($oAccount);
|
||||
|
||||
$this->PersonalAddressBookProvider($oAccount)->IncFrec(
|
||||
$this->AddressBookProvider($oAccount)->IncFrec(
|
||||
$oAccount->ParentEmailHelper(), \array_values($aArrayToFrec), !!$oSettings->GetConf('ContactsAutosave', true));
|
||||
}
|
||||
}
|
||||
|
@ -4684,6 +4600,95 @@ class Actions
|
|||
return $this->DefaultResponse(__FUNCTION__, $aQuota);
|
||||
}
|
||||
|
||||
private function getContactsSyncData($oAccount)
|
||||
{
|
||||
$mResult = null;
|
||||
|
||||
$sData = $this->StorageProvider()->Get($oAccount->ParentEmailHelper(),
|
||||
\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->ParentEmailHelper(),
|
||||
\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($sEmail, $bRemoveSecret = false)
|
||||
{
|
||||
$mData = null;
|
||||
|
@ -4950,10 +4955,10 @@ class Actions
|
|||
$iLimit = 0 > $iLimit ? 20 : $iLimit;
|
||||
|
||||
$iResultCount = 0;
|
||||
if ($this->PersonalAddressBookProvider($oAccount)->IsActive())
|
||||
if ($this->AddressBookProvider($oAccount)->IsActive())
|
||||
{
|
||||
$iResultCount = 0;
|
||||
$mResult = $this->PersonalAddressBookProvider($oAccount)->GetContacts($oAccount->ParentEmailHelper(),
|
||||
$mResult = $this->AddressBookProvider($oAccount)->GetContacts($oAccount->ParentEmailHelper(),
|
||||
$iOffset, $iLimit, $sSearch, $iResultCount);
|
||||
}
|
||||
|
||||
|
@ -4980,9 +4985,9 @@ class Actions
|
|||
});
|
||||
|
||||
$bResult = false;
|
||||
if (0 < \count($aFilteredUids) && $this->PersonalAddressBookProvider($oAccount)->IsActive())
|
||||
if (0 < \count($aFilteredUids) && $this->AddressBookProvider($oAccount)->IsActive())
|
||||
{
|
||||
$bResult = $this->PersonalAddressBookProvider($oAccount)->DeleteContacts($oAccount->ParentEmailHelper(), $aFilteredUids);
|
||||
$bResult = $this->AddressBookProvider($oAccount)->DeleteContacts($oAccount->ParentEmailHelper(), $aFilteredUids);
|
||||
}
|
||||
|
||||
return $this->DefaultResponse(__FUNCTION__, $bResult);
|
||||
|
@ -4997,68 +5002,55 @@ class Actions
|
|||
|
||||
$bResult = false;
|
||||
|
||||
$oPab = $this->PersonalAddressBookProvider($oAccount);
|
||||
$oAddressBookProvider = $this->AddressBookProvider($oAccount);
|
||||
$sRequestUid = \trim($this->GetActionParam('RequestUid', ''));
|
||||
if ($oPab && $oPab->IsActive() && 0 < \strlen($sRequestUid))
|
||||
if ($oAddressBookProvider && $oAddressBookProvider->IsActive() && 0 < \strlen($sRequestUid))
|
||||
{
|
||||
$sUid = \trim($this->GetActionParam('Uid', ''));
|
||||
$sUidStr = \trim($this->GetActionParam('UidStr', ''));
|
||||
$iScopeType = (int) $this->GetActionParam('ScopeType', null);
|
||||
if (!in_array($iScopeType, array(
|
||||
\RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::DEFAULT_,
|
||||
\RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::SHARE_ALL)))
|
||||
{
|
||||
$iScopeType = \RainLoop\Providers\PersonalAddressBook\Enumerations\ScopeType::DEFAULT_;
|
||||
}
|
||||
|
||||
$oContact = null;
|
||||
if (0 < \strlen($sUid))
|
||||
{
|
||||
$oContact = $oPab->GetContactByID($oAccount->ParentEmailHelper(), $sUid);
|
||||
$oContact = $oAddressBookProvider->GetContactByID($oAccount->ParentEmailHelper(), $sUid);
|
||||
}
|
||||
|
||||
if (!$oContact)
|
||||
{
|
||||
$oContact = new \RainLoop\Providers\PersonalAddressBook\Classes\Contact();
|
||||
$oContact = new \RainLoop\Providers\AddressBook\Classes\Contact();
|
||||
if (0 < \strlen($sUid))
|
||||
{
|
||||
$oContact->IdContact = $sUid;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 < \strlen($sUidStr))
|
||||
{
|
||||
$oContact->IdContactStr = $sUidStr;
|
||||
}
|
||||
|
||||
$oContact->ScopeType = $iScopeType;
|
||||
$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]))
|
||||
if ($aItem && isset($aItem[0], $aItem[1]) && \is_numeric($aItem[0]))
|
||||
{
|
||||
$oProp = new \RainLoop\Providers\PersonalAddressBook\Classes\Property();
|
||||
$oProp = new \RainLoop\Providers\AddressBook\Classes\Property();
|
||||
$oProp->Type = (int) $aItem[0];
|
||||
$oProp->Value = $aItem[1];
|
||||
$oProp->ScopeType = $iScopeType;
|
||||
$oProp->TypeStr = empty($aItem[2]) ? '': $aItem[2];
|
||||
|
||||
$oContact->Properties[] = $oProp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$bResult = $oPab->ContactSave($oAccount->ParentEmailHelper(), $oContact);
|
||||
if (!empty($oContact->Etag))
|
||||
{
|
||||
$oContact->Etag = \md5($oContact->ToVCard());
|
||||
}
|
||||
|
||||
$bResult = $oAddressBookProvider->ContactSave($oAccount->ParentEmailHelper(), $oContact);
|
||||
}
|
||||
|
||||
return $this->DefaultResponse(__FUNCTION__, array(
|
||||
'RequestUid' => $sRequestUid,
|
||||
'ResultID' => $bResult ? $oContact->IdContact : '',
|
||||
'ResultIDStr' => $bResult ? $oContact->IdContactStr : '',
|
||||
'Result' => $bResult
|
||||
));
|
||||
}
|
||||
|
@ -5087,11 +5079,11 @@ class Actions
|
|||
|
||||
if ($iLimit > \count($aResult) && 0 < \strlen($sQuery))
|
||||
{
|
||||
// Personal Address Book
|
||||
$oPab = $this->PersonalAddressBookProvider($oAccount);
|
||||
if ($oPab && $oPab->IsActive())
|
||||
// Address Book
|
||||
$oAddressBookProvider = $this->AddressBookProvider($oAccount);
|
||||
if ($oAddressBookProvider && $oAddressBookProvider->IsActive())
|
||||
{
|
||||
$aSuggestions = $oPab->GetSuggestions($oAccount->ParentEmailHelper(), $sQuery, $iLimit);
|
||||
$aSuggestions = $oAddressBookProvider->GetSuggestions($oAccount->ParentEmailHelper(), $sQuery, $iLimit);
|
||||
if (0 === \count($aResult))
|
||||
{
|
||||
$aResult = $aSuggestions;
|
||||
|
@ -5669,8 +5661,8 @@ class Actions
|
|||
|
||||
if ($oAccount && \is_resource($rFile))
|
||||
{
|
||||
$oPab = $this->PersonalAddressBookProvider($oAccount);
|
||||
if ($oPab && $oPab->IsActive())
|
||||
$oAddressBookProvider = $this->AddressBookProvider($oAccount);
|
||||
if ($oAddressBookProvider && $oAddressBookProvider->IsActive())
|
||||
{
|
||||
$sDelimiter = ((int) \strpos($sFileStart, ',') > (int) \strpos($sFileStart, ';')) ? ',' : ';';
|
||||
|
||||
|
@ -5706,7 +5698,7 @@ class Actions
|
|||
if (\is_array($aData) && 0 < \count($aData))
|
||||
{
|
||||
$this->Logger()->Write('Import contacts from csv');
|
||||
$iCount = $oPab->ImportCsvArray($oAccount->ParentEmailHelper(), $aData);
|
||||
$iCount = $oAddressBookProvider->ImportCsvArray($oAccount->ParentEmailHelper(), $aData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5726,8 +5718,8 @@ class Actions
|
|||
$iCount = 0;
|
||||
if ($oAccount && \is_resource($rFile))
|
||||
{
|
||||
$oPab = $this->PersonalAddressBookProvider($oAccount);
|
||||
if ($oPab && $oPab->IsActive())
|
||||
$oAddressBookProvider = $this->AddressBookProvider($oAccount);
|
||||
if ($oAddressBookProvider && $oAddressBookProvider->IsActive())
|
||||
{
|
||||
$sFile = \stream_get_contents($rFile);
|
||||
if (\is_resource($rFile))
|
||||
|
@ -5738,7 +5730,7 @@ class Actions
|
|||
if (is_string($sFile) && 5 < \strlen($sFile))
|
||||
{
|
||||
$this->Logger()->Write('Import contacts from vcf');
|
||||
$iCount = $oPab->ImportVcfFile($oAccount->ParentEmailHelper(), $sFile);
|
||||
$iCount = $oAddressBookProvider->ImportVcfFile($oAccount->ParentEmailHelper(), $sFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5762,8 +5754,8 @@ class Actions
|
|||
|
||||
if ($oAccount)
|
||||
{
|
||||
$oPab = $this->PersonalAddressBookProvider($oAccount);
|
||||
if ($oPab)
|
||||
$oAddressBookProvider = $this->AddressBookProvider($oAccount);
|
||||
if ($oAddressBookProvider && $oAddressBookProvider->IsActive())
|
||||
{
|
||||
$iError = UPLOAD_ERR_OK;
|
||||
$_FILES = isset($_FILES) ? $_FILES : null;
|
||||
|
@ -6949,28 +6941,25 @@ class Actions
|
|||
'Email' => \MailSo\Base\Utils::Utf8Clear($mResponse->GetEmail())
|
||||
));
|
||||
}
|
||||
else if ('RainLoop\Providers\PersonalAddressBook\Classes\Contact' === $sClassName)
|
||||
else if ('RainLoop\Providers\AddressBook\Classes\Contact' === $sClassName)
|
||||
{
|
||||
$mResult = \array_merge($this->objectData($mResponse, $sParent, $aParameters), array(
|
||||
/* @var $mResponse \RainLoop\Providers\PersonalAddressBook\Classes\Contact */
|
||||
/* @var $mResponse \RainLoop\Providers\AddressBook\Classes\Contact */
|
||||
'IdContact' => $mResponse->IdContact,
|
||||
'IdContactStr' => $mResponse->IdContactStr,
|
||||
'Display' => \MailSo\Base\Utils::Utf8Clear($mResponse->Display),
|
||||
'ReadOnly' => $mResponse->ReadOnly,
|
||||
'ScopeType' => $mResponse->ScopeType,
|
||||
'IdPropertyFromSearch' => $mResponse->IdPropertyFromSearch,
|
||||
'Properties' => $this->responseObject($mResponse->Properties, $sParent, $aParameters)
|
||||
));
|
||||
}
|
||||
else if ('RainLoop\Providers\PersonalAddressBook\Classes\Property' === $sClassName)
|
||||
else if ('RainLoop\Providers\AddressBook\Classes\Property' === $sClassName)
|
||||
{
|
||||
$mResult = \array_merge($this->objectData($mResponse, $sParent, $aParameters), array(
|
||||
/* @var $mResponse \RainLoop\Providers\PersonalAddressBook\Classes\Property */
|
||||
/* @var $mResponse \RainLoop\Providers\AddressBook\Classes\Property */
|
||||
'IdProperty' => $mResponse->IdProperty,
|
||||
'Type' => $mResponse->Type,
|
||||
'TypeCustom' => $mResponse->TypeCustom,
|
||||
'Value' => \MailSo\Base\Utils::Utf8Clear($mResponse->Value),
|
||||
'ValueCustom' => \MailSo\Base\Utils::Utf8Clear($mResponse->ValueCustom)
|
||||
'TypeStr' => $mResponse->TypeStr,
|
||||
'Value' => \MailSo\Base\Utils::Utf8Clear($mResponse->Value)
|
||||
));
|
||||
}
|
||||
else if ('MailSo\Mail\Attachment' === $sClassName)
|
||||
|
|
|
@ -14,6 +14,11 @@ abstract class PdoAbstract
|
|||
*/
|
||||
protected $bExplain = false;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $iResetTimer = 0;
|
||||
|
||||
/**
|
||||
* @var \MailSo\Log\Logger
|
||||
*/
|
||||
|
@ -114,13 +119,21 @@ abstract class PdoAbstract
|
|||
}
|
||||
|
||||
/**
|
||||
* @param string $sName = null
|
||||
* @param string $sTabelName = null
|
||||
* @param string $sColumnName = null
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function lastInsertId($sName = null)
|
||||
protected function lastInsertId($sTabelName = null, $sColumnName = null)
|
||||
{
|
||||
return $this->getPDO()->lastInsertId($sName);
|
||||
$mName = null;
|
||||
if ('pgsql' === $this->sDbType &&
|
||||
null !== $sTabelName && $sColumnName !== null)
|
||||
{
|
||||
$mName = \strtolower($sTabelName.'_'.$sColumnName.'_seq');
|
||||
}
|
||||
|
||||
return null === $mName ? $this->getPDO()->lastInsertId() : $this->getPDO()->lastInsertId($mName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,6 +24,8 @@ class Notifications
|
|||
const NewPasswordWeak = 133;
|
||||
const NewPasswordForbidden = 134;
|
||||
|
||||
const ContactsSyncError = 140;
|
||||
|
||||
const CantGetMessageList = 201;
|
||||
const CantGetMessage = 202;
|
||||
const CantDeleteMessage = 203;
|
||||
|
@ -93,6 +95,8 @@ class Notifications
|
|||
self::NewPasswordShort => 'NewPasswordShort',
|
||||
self::NewPasswordWeak => 'NewPasswordWeak',
|
||||
self::NewPasswordForbidden => 'NewPasswordForbidden',
|
||||
|
||||
self::ContactsSyncError => 'ContactsSyncError',
|
||||
|
||||
self::CantGetMessageList => 'CantGetMessageList',
|
||||
self::CantGetMessage => 'CantGetMessage',
|
||||
|
|
|
@ -53,6 +53,28 @@ class AddressBook extends \RainLoop\Providers\AbstractProvider
|
|||
$this->oDriver->IsSupported();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function IsSharingAllowed()
|
||||
{
|
||||
return $this->oDriver instanceof \RainLoop\Providers\PersonalAddressBook\AddressBookInterface &&
|
||||
$this->oDriver->IsSharingAllowed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sEmail
|
||||
* @param string $sUrl
|
||||
* @param string $sUser
|
||||
* @param string $sPassword
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function Sync($sEmail, $sUrl, $sUser, $sPassword)
|
||||
{
|
||||
return $this->IsActive() ? $this->oDriver->Sync($sEmail, $sUrl, $sUser, $sPassword) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sEmail
|
||||
* @param \RainLoop\Providers\AddressBook\Classes\Contact $oContact
|
||||
|
@ -140,37 +162,64 @@ class AddressBook extends \RainLoop\Providers\AbstractProvider
|
|||
{
|
||||
$aMap = array(
|
||||
'Title' => PropertyType::FULLNAME,
|
||||
'First Name' => PropertyType::FIRST_NAME,
|
||||
'Middle Name' => PropertyType::MIDDLE_NAME,
|
||||
'Last Name' => PropertyType::LAST_NAME,
|
||||
'Name' => PropertyType::FULLNAME,
|
||||
'FullName' => PropertyType::FULLNAME,
|
||||
'DisplayName' => PropertyType::FULLNAME,
|
||||
'First' => PropertyType::FIRST_NAME,
|
||||
'FirstName' => PropertyType::FIRST_NAME,
|
||||
'Middle' => PropertyType::MIDDLE_NAME,
|
||||
'MiddleName' => PropertyType::MIDDLE_NAME,
|
||||
'Last' => PropertyType::LAST_NAME,
|
||||
'LastName' => PropertyType::LAST_NAME,
|
||||
'Suffix' => PropertyType::NAME_SUFFIX,
|
||||
'Business Fax' => PropertyType::FAX_BUSSINES,
|
||||
'Business Phone' => PropertyType::PHONE_BUSSINES,
|
||||
'Business Phone 2' => PropertyType::PHONE_BUSSINES,
|
||||
'Company Main Phone' => PropertyType::PHONE_BUSSINES,
|
||||
'Home Fax' => PropertyType::FAX_PERSONAL,
|
||||
'Home Phone' => PropertyType::PHONE_PERSONAL,
|
||||
'Home Phone 2' => PropertyType::PHONE_PERSONAL,
|
||||
'Mobile Phone' => PropertyType::MOBILE_PERSONAL,
|
||||
'Other Fax' => PropertyType::FAX_OTHER,
|
||||
'Other Phone' => PropertyType::PHONE_OTHER,
|
||||
// 'Primary Phone' => PropertyType::PHONE_PERSONAL,
|
||||
'E-mail Address' => PropertyType::EMAIl_PERSONAL,
|
||||
'E-mail 2 Address' => PropertyType::EMAIl_OTHER,
|
||||
'E-mail 3 Address' => PropertyType::EMAIl_OTHER,
|
||||
'E-mail Display Name' => PropertyType::FULLNAME,
|
||||
'E-mail 2 Display Name' => PropertyType::FULLNAME,
|
||||
'E-mail 3 Display Name' => PropertyType::FULLNAME,
|
||||
'NickName' => PropertyType::NICK_NAME,
|
||||
'BusinessFax' => array(PropertyType::PHONE, 'Work,Fax'),
|
||||
'BusinessFax2' => array(PropertyType::PHONE, 'Work,Fax'),
|
||||
'BusinessPhone' => array(PropertyType::PHONE, 'Work'),
|
||||
'BusinessPhone2' => array(PropertyType::PHONE, 'Work'),
|
||||
'BusinessPhone3' => array(PropertyType::PHONE, 'Work'),
|
||||
'CompanyPhone' => array(PropertyType::PHONE, 'Work'),
|
||||
'CompanyMainPhone' => array(PropertyType::PHONE, 'Work'),
|
||||
'HomeFax' => array(PropertyType::PHONE, 'Home,Fax'),
|
||||
'HomeFax2' => array(PropertyType::PHONE, 'Home,Fax'),
|
||||
'HomePhone' => array(PropertyType::PHONE, 'Home'),
|
||||
'HomePhone2' => array(PropertyType::PHONE, 'Home'),
|
||||
'HomePhone3' => array(PropertyType::PHONE, 'Home'),
|
||||
'Mobile' => array(PropertyType::PHONE, 'Mobile'),
|
||||
'MobilePhone' => array(PropertyType::PHONE, 'Mobile'),
|
||||
'BusinessMobile' => array(PropertyType::PHONE, 'Work,Mobile'),
|
||||
'BusinessMobilePhone' => array(PropertyType::PHONE, 'Work,Mobile'),
|
||||
'OtherFax' => array(PropertyType::PHONE, 'Other,Fax'),
|
||||
'OtherPhone' => array(PropertyType::PHONE, 'Other'),
|
||||
'PrimaryPhone' => array(PropertyType::PHONE, 'Pref,Home'),
|
||||
'Email' => array(PropertyType::EMAIl, 'Home'),
|
||||
'Email2' => array(PropertyType::EMAIl, 'Home'),
|
||||
'Email3' => array(PropertyType::EMAIl, 'Home'),
|
||||
'EmailAddress' => array(PropertyType::EMAIl, 'Home'),
|
||||
'Email2Address' => array(PropertyType::EMAIl, 'Home'),
|
||||
'Email3Address' => array(PropertyType::EMAIl, 'Home'),
|
||||
'OtherEmail' => array(PropertyType::EMAIl, 'Other'),
|
||||
'BusinessEmail' => array(PropertyType::EMAIl, 'Work'),
|
||||
'BusinessEmail2' => array(PropertyType::EMAIl, 'Work'),
|
||||
'BusinessEmail3' => array(PropertyType::EMAIl, 'Work'),
|
||||
'PersonalEmail' => array(PropertyType::EMAIl, 'Home'),
|
||||
'PersonalEmail2' => array(PropertyType::EMAIl, 'Home'),
|
||||
'PersonalEmail3' => array(PropertyType::EMAIl, 'Home'),
|
||||
'Notes' => PropertyType::NOTE,
|
||||
'Web Page' => PropertyType::WEB_PAGE_PERSONAL,
|
||||
'WebPage' => PropertyType::WEB_PAGE_PERSONAL,
|
||||
'Web' => PropertyType::WEB_PAGE,
|
||||
'BusinessWeb' => array(PropertyType::WEB_PAGE, 'Work'),
|
||||
'WebPage' => PropertyType::WEB_PAGE,
|
||||
'BusinessWebPage' => array(PropertyType::WEB_PAGE, 'Work'),
|
||||
'WebSite' => PropertyType::WEB_PAGE,
|
||||
'BusinessWebSite' => array(PropertyType::WEB_PAGE, 'Work'),
|
||||
'PersonalWebSite' => PropertyType::WEB_PAGE
|
||||
);
|
||||
|
||||
$aMap = \array_change_key_case($aMap, CASE_LOWER);
|
||||
}
|
||||
|
||||
$sCsvNameLower = \MailSo\Base\Utils::IsAscii($sCsvName) ? \strtolower($sCsvName) : '';
|
||||
return isset($aMap[$sCsvNameLower]) ? $aMap[$sCsvNameLower] : PropertyType::UNKNOWN;
|
||||
$sCsvNameLower = \MailSo\Base\Utils::IsAscii($sCsvName) ? \preg_replace('/[\s\-]+/', '', \strtolower($sCsvName)) : '';
|
||||
return !empty($sCsvNameLower) && isset($aMap[$sCsvNameLower]) ? $aMap[$sCsvNameLower] : PropertyType::UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -182,11 +231,15 @@ class AddressBook extends \RainLoop\Providers\AbstractProvider
|
|||
public function ImportCsvArray($sEmail, $aCsvData)
|
||||
{
|
||||
$iCount = 0;
|
||||
$iResetTimer = 0;
|
||||
|
||||
if ($this->IsActive() && \is_array($aCsvData) && 0 < \count($aCsvData))
|
||||
{
|
||||
$oContact = new \RainLoop\Providers\AddressBook\Classes\Contact();
|
||||
foreach ($aCsvData as $aItem)
|
||||
{
|
||||
\MailSo\Base\Utils::ResetTimeLimit($iResetTimer);
|
||||
|
||||
foreach ($aItem as $sItemName => $sItemValue)
|
||||
{
|
||||
$sItemName = \trim($sItemName);
|
||||
|
@ -194,12 +247,15 @@ class AddressBook extends \RainLoop\Providers\AbstractProvider
|
|||
|
||||
if (!empty($sItemName) && !empty($sItemValue))
|
||||
{
|
||||
$iType = $this->csvNameToTypeConvertor($sItemName);
|
||||
$mData = $this->csvNameToTypeConvertor($sItemName);
|
||||
$iType = \is_array($mData) ? $mData[0] : $mData;
|
||||
|
||||
if (PropertyType::UNKNOWN !== $iType)
|
||||
{
|
||||
$oProp = new \RainLoop\Providers\AddressBook\Classes\Property();
|
||||
$oProp->Type = $iType;
|
||||
$oProp->Value = $sItemValue;
|
||||
$oProp->TypeStr = \is_array($mData) && !empty($mData[1]) ? $mData[1] : '';
|
||||
|
||||
$oContact->Properties[] = $oProp;
|
||||
}
|
||||
|
@ -232,6 +288,8 @@ class AddressBook extends \RainLoop\Providers\AbstractProvider
|
|||
public function ImportVcfFile($sEmail, $sVcfData)
|
||||
{
|
||||
$iCount = 0;
|
||||
$iResetTimer = 0;
|
||||
|
||||
if ($this->IsActive() && \is_string($sVcfData))
|
||||
{
|
||||
$sVcfData = \trim($sVcfData);
|
||||
|
@ -260,12 +318,15 @@ class AddressBook extends \RainLoop\Providers\AbstractProvider
|
|||
{
|
||||
if ($oVCard instanceof \Sabre\VObject\Component\VCard)
|
||||
{
|
||||
\MailSo\Base\Utils::ResetTimeLimit($iResetTimer);
|
||||
|
||||
if (empty($oVCard->UID))
|
||||
{
|
||||
$oVCard->UID = \Sabre\DAV\UUIDUtil::getUUID();
|
||||
}
|
||||
|
||||
$oContact->ParseVCard($oVCard, $oVCard->serialize());
|
||||
$oContact->PopulateByVCard($oVCard->serialize());
|
||||
|
||||
if (0 < \count($oContact->Properties))
|
||||
{
|
||||
if ($this->ContactSave($sEmail, $oContact))
|
||||
|
|
|
@ -47,7 +47,7 @@ class Contact
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $Hash;
|
||||
public $Etag;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
@ -64,7 +64,7 @@ class Contact
|
|||
$this->Properties = array();
|
||||
$this->ReadOnly = false;
|
||||
$this->IdPropertyFromSearch = 0;
|
||||
$this->Hash = '';
|
||||
$this->Etag = '';
|
||||
}
|
||||
|
||||
public function UpdateDependentValues()
|
||||
|
@ -101,9 +101,8 @@ class Contact
|
|||
{
|
||||
$sFirstName = $oProperty->Value;
|
||||
}
|
||||
else if (\in_array($oProperty->Type, array(PropertyType::FULLNAME,
|
||||
PropertyType::PHONE_PERSONAL, PropertyType::PHONE_BUSSINES, PropertyType::PHONE_OTHER,
|
||||
PropertyType::MOBILE_PERSONAL, PropertyType::MOBILE_BUSSINES, PropertyType::MOBILE_OTHER
|
||||
else if (\in_array($oProperty->Type, array(
|
||||
PropertyType::FULLNAME, PropertyType::PHONE
|
||||
)))
|
||||
{
|
||||
$sOther = $oProperty->Value;
|
||||
|
@ -134,20 +133,16 @@ class Contact
|
|||
}
|
||||
|
||||
$this->Display = \trim($sDisplay);
|
||||
|
||||
$bNewFull = false;
|
||||
if (!$oFullNameProperty)
|
||||
|
||||
if ($oFullNameProperty)
|
||||
{
|
||||
$oFullNameProperty = new \RainLoop\Providers\AddressBook\Classes\Property(PropertyType::FULLNAME, $this->Display);
|
||||
$bNewFull = true;
|
||||
$oFullNameProperty->Value = $this->Display;
|
||||
$oFullNameProperty->UpdateDependentValues();
|
||||
}
|
||||
|
||||
$oFullNameProperty->Value = $this->Display;
|
||||
$oFullNameProperty->UpdateDependentValues();
|
||||
|
||||
if ($bNewFull)
|
||||
if (!$oFullNameProperty)
|
||||
{
|
||||
$this->Properties[] = $oFullNameProperty;
|
||||
$this->Properties[] = new \RainLoop\Providers\AddressBook\Classes\Property(PropertyType::FULLNAME, $this->Display);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,85 +172,189 @@ class Contact
|
|||
}
|
||||
|
||||
/**
|
||||
* @param \Sabre\VObject\Document $oVCard
|
||||
* @return string
|
||||
*/
|
||||
public function ParseVCard($oVCard)
|
||||
public function CardDavNameUri()
|
||||
{
|
||||
$bNew = empty($this->IdContact);
|
||||
return $this->IdContactStr.'.vcf';
|
||||
}
|
||||
|
||||
if (!$bNew)
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function ToVCard($sPreVCard = '')
|
||||
{
|
||||
$this->UpdateDependentValues();
|
||||
|
||||
$oVCard = null;
|
||||
if (0 < \strlen($sPreVCard))
|
||||
{
|
||||
$this->Properties = array();
|
||||
try
|
||||
{
|
||||
$oVCard = \Sabre\VObject\Reader::read($sPreVCard);
|
||||
}
|
||||
catch (\Exception $oExc) {};
|
||||
}
|
||||
|
||||
if (!$oVCard)
|
||||
{
|
||||
$oVCard = new \Sabre\VObject\Component\VCard();
|
||||
}
|
||||
|
||||
$oVCard->VERSION = '3.0';
|
||||
$oVCard->PRODID = '-//RainLoop//'.APP_VERSION.'//EN';
|
||||
|
||||
unset($oVCard->FN, $oVCard->EMAIL, $oVCard->TEL, $oVCard->URL);
|
||||
|
||||
$sFirstName = $sLastName = $sMiddleName = $sSuffix = $sPrefix = '';
|
||||
foreach ($this->Properties as /* @var $oProperty \RainLoop\Providers\AddressBook\Classes\Property */ &$oProperty)
|
||||
{
|
||||
if ($oProperty)
|
||||
{
|
||||
$sAddKey = '';
|
||||
switch ($oProperty->Type)
|
||||
{
|
||||
case PropertyType::FULLNAME:
|
||||
$oVCard->FN = $oProperty->Value;
|
||||
break;
|
||||
case PropertyType::NICK_NAME:
|
||||
$oVCard->NICKNAME = $oProperty->Value;
|
||||
break;
|
||||
case PropertyType::FIRST_NAME:
|
||||
$sFirstName = $oProperty->Value;
|
||||
break;
|
||||
case PropertyType::LAST_NAME:
|
||||
$sLastName = $oProperty->Value;
|
||||
break;
|
||||
case PropertyType::MIDDLE_NAME:
|
||||
$sMiddleName = $oProperty->Value;
|
||||
break;
|
||||
case PropertyType::NAME_SUFFIX:
|
||||
$sSuffix = $oProperty->Value;
|
||||
break;
|
||||
case PropertyType::NAME_PREFIX:
|
||||
$sPrefix = $oProperty->Value;
|
||||
break;
|
||||
case PropertyType::EMAIl:
|
||||
if (empty($sAddKey))
|
||||
{
|
||||
$sAddKey = 'EMAIL';
|
||||
}
|
||||
case PropertyType::WEB_PAGE:
|
||||
if (empty($sAddKey))
|
||||
{
|
||||
$sAddKey = 'URL';
|
||||
}
|
||||
case PropertyType::PHONE:
|
||||
if (empty($sAddKey))
|
||||
{
|
||||
$sAddKey = 'TEL';
|
||||
}
|
||||
|
||||
$aTypes = $oProperty->TypesAsArray();
|
||||
$oVCard->add($sAddKey, $oProperty->Value, \is_array($aTypes) && 0 < \count($aTypes) ? array('TYPE' => $aTypes) : null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$oVCard->UID = $this->IdContactStr;
|
||||
$oVCard->N = array($sLastName, $sFirstName, $sMiddleName, $sPrefix, $sSuffix);
|
||||
$oVCard->REV = \gmdate('Ymd', $this->Changed).'T'.\gmdate('His', $this->Changed).'Z';
|
||||
|
||||
return (string) $oVCard->serialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $oProp
|
||||
* @param bool $bOldVersion
|
||||
* @return string
|
||||
*/
|
||||
private function getPropertyValueHelper($oProp, $bOldVersion)
|
||||
{
|
||||
$sValue = \trim($oProp);
|
||||
if ($bOldVersion && !isset($oProp->parameters['CHARSET']))
|
||||
{
|
||||
if (0 < \strlen($sValue))
|
||||
{
|
||||
$sEncValue = @\utf8_encode($sValue);
|
||||
if (0 === \strlen($sEncValue))
|
||||
{
|
||||
$sEncValue = $sValue;
|
||||
}
|
||||
|
||||
$sValue = $sEncValue;
|
||||
}
|
||||
}
|
||||
|
||||
return \MailSo\Base\Utils::Utf8Clear($sValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $oProp
|
||||
* @param bool $bOldVersion
|
||||
* @return string
|
||||
*/
|
||||
private function addArrayPropertyHelper(&$aProperties, $oArrayProp, $iType)
|
||||
{
|
||||
foreach ($oArrayProp as $oProp)
|
||||
{
|
||||
$oTypes = $oProp ? $oProp['TYPE'] : null;
|
||||
$aTypes = $oTypes ? $oTypes->getParts() : array();
|
||||
$sValue = $oProp ? \trim($oProp->getValue()) : '';
|
||||
|
||||
if (0 < \strlen($sValue))
|
||||
{
|
||||
if (!$oTypes || $oTypes->has('PREF'))
|
||||
{
|
||||
\array_unshift($aProperties, new Property($iType, $sValue, \implode(',', $aTypes)));
|
||||
}
|
||||
else
|
||||
{
|
||||
\array_push($aProperties, new Property($iType, $sValue, \implode(',', $aTypes)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function PopulateByVCard($sVCard, $sEtag = '')
|
||||
{
|
||||
$this->Properties = array();
|
||||
|
||||
if (!empty($sEtag))
|
||||
{
|
||||
$this->Etag = $sEtag;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$oVCard = \Sabre\VObject\Reader::read($sVCard);
|
||||
}
|
||||
catch (\Exception $oExc) {};
|
||||
|
||||
$aProperties = array();
|
||||
if ($oVCard)
|
||||
{
|
||||
$bOldVersion = empty($oVCard->VERSION) ? false :
|
||||
$bOldVersion = empty($oVCard->VERSION) ? false :
|
||||
\in_array((string) $oVCard->VERSION, array('2.1', '2.0', '1.0'));
|
||||
|
||||
$this->IdContactStr = !empty($oVCard->UID) ? (string) $oVCard->UID : \Sabre\DAV\UUIDUtil::getUUID();
|
||||
$this->IdContactStr = $oVCard->UID ? (string) $oVCard->UID : \Sabre\DAV\UUIDUtil::getUUID();
|
||||
|
||||
if (isset($oVCard->FN) && '' !== \trim($oVCard->FN))
|
||||
{
|
||||
$sValue = \trim($oVCard->FN);
|
||||
if ($bOldVersion && !isset($oVCard->FN->parameters['CHARSET']))
|
||||
{
|
||||
if (0 < \strlen($sValue))
|
||||
{
|
||||
$sEncValue = @\utf8_encode($sValue);
|
||||
if (0 === \strlen($sEncValue))
|
||||
{
|
||||
$sEncValue = $sValue;
|
||||
}
|
||||
|
||||
$sValue = $sEncValue;
|
||||
}
|
||||
}
|
||||
|
||||
$sValue = \MailSo\Base\Utils::Utf8Clear($sValue);
|
||||
$sValue = $this->getPropertyValueHelper($oVCard->FN, $bOldVersion);
|
||||
$aProperties[] = new Property(PropertyType::FULLNAME, $sValue);
|
||||
}
|
||||
|
||||
if (isset($oVCard->NICKNAME) && '' !== \trim($oVCard->NICKNAME))
|
||||
{
|
||||
$sValue = \trim($oVCard->NICKNAME);
|
||||
if ($bOldVersion && !isset($oVCard->NICKNAME->parameters['CHARSET']))
|
||||
{
|
||||
if (0 < \strlen($sValue))
|
||||
{
|
||||
$sEncValue = @\utf8_encode($sValue);
|
||||
if (0 === \strlen($sEncValue))
|
||||
{
|
||||
$sEncValue = $sValue;
|
||||
}
|
||||
|
||||
$sValue = $sEncValue;
|
||||
}
|
||||
}
|
||||
|
||||
$sValue = \MailSo\Base\Utils::Utf8Clear($sValue);
|
||||
$sValue = $sValue = $this->getPropertyValueHelper($oVCard->NICKNAME, $bOldVersion);
|
||||
$aProperties[] = new Property(PropertyType::NICK_NAME, $sValue);
|
||||
}
|
||||
|
||||
// if (isset($oVCard->NOTE) && '' !== \trim($oVCard->NOTE))
|
||||
// {
|
||||
// $sValue = \trim($oVCard->NOTE);
|
||||
// if ($bOldVersion)
|
||||
// {
|
||||
// if (0 < \strlen($sValue))
|
||||
// {
|
||||
// $sEncValue = @\utf8_encode($sValue);
|
||||
// if (0 === \strlen($sEncValue))
|
||||
// {
|
||||
// $sEncValue = $sValue;
|
||||
// }
|
||||
//
|
||||
// $sValue = $sEncValue;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// $sValue = \MailSo\Base\Utils::Utf8Clear($sValue);
|
||||
// $sValue = $this->getPropertyValueHelper($oVCard->NOTE, $bOldVersion);
|
||||
// $aProperties[] = new Property(PropertyType::NOTE, $sValue);
|
||||
// }
|
||||
|
||||
|
@ -302,244 +401,22 @@ class Contact
|
|||
|
||||
if (isset($oVCard->EMAIL))
|
||||
{
|
||||
$bPref = false;
|
||||
foreach($oVCard->EMAIL as $oEmail)
|
||||
{
|
||||
$oTypes = $oEmail ? $oEmail['TYPE'] : null;
|
||||
$sEmail = $oEmail ? \trim($oEmail->getValue()) : '';
|
||||
|
||||
if (0 < \strlen($sEmail))
|
||||
{
|
||||
if ($oTypes)
|
||||
{
|
||||
$oProp = new Property($oTypes->has('WORK') ? PropertyType::EMAIl_BUSSINES : PropertyType::EMAIl_PERSONAL, $sEmail);
|
||||
if (!$bPref && $oTypes->has('pref'))
|
||||
{
|
||||
$bPref = true;
|
||||
\array_unshift($aProperties, $oProp);
|
||||
}
|
||||
else
|
||||
{
|
||||
\array_push($aProperties, $oProp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
\array_unshift($aProperties,
|
||||
new Property(PropertyType::EMAIl_PERSONAL, $sEmail));
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->addArrayPropertyHelper(&$aProperties, $oVCard->EMAIL, PropertyType::EMAIl);
|
||||
}
|
||||
|
||||
if (isset($oVCard->URL))
|
||||
{
|
||||
$this->addArrayPropertyHelper(&$aProperties, $oVCard->URL, PropertyType::WEB_PAGE);
|
||||
}
|
||||
|
||||
// if (isset($oVCard->URL))
|
||||
// {
|
||||
// foreach($oVCard->URL as $oUrl)
|
||||
// {
|
||||
// $oTypes = $oUrl ? $oUrl['TYPE'] : null;
|
||||
// $sUrl = $oUrl ? \trim((string) $oUrl) : '';
|
||||
//
|
||||
// if (0 < \strlen($sUrl))
|
||||
// {
|
||||
// \array_push($aProperties,
|
||||
// new Property($oTypes && $oTypes->has('WORK') ?
|
||||
// PropertyType::WEB_PAGE_BUSSINES : PropertyType::WEB_PAGE_PERSONAL, $sUrl));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
if (isset($oVCard->TEL))
|
||||
{
|
||||
$bPref = false;
|
||||
foreach($oVCard->TEL as $oTel)
|
||||
{
|
||||
$oTypes = $oTel ? $oTel['TYPE'] : null;
|
||||
$sTel = $oTypes ? \trim((string) $oTel) : '';
|
||||
|
||||
if (0 < \strlen($sTel))
|
||||
{
|
||||
if ($oTypes)
|
||||
{
|
||||
$oProp = null;
|
||||
$bWork = $oTypes->has('WORK');
|
||||
|
||||
switch (true)
|
||||
{
|
||||
case $oTypes->has('VOICE'):
|
||||
$oProp = new Property($bWork ? PropertyType::PHONE_BUSSINES : PropertyType::PHONE_PERSONAL, $sTel);
|
||||
break;
|
||||
case $oTypes->has('CELL'):
|
||||
$oProp = new Property($bWork ? PropertyType::MOBILE_BUSSINES : PropertyType::MOBILE_PERSONAL, $sTel);
|
||||
break;
|
||||
case $oTypes->has('FAX'):
|
||||
$oProp = new Property($bWork ? PropertyType::FAX_BUSSINES : PropertyType::FAX_PERSONAL, $sTel);
|
||||
break;
|
||||
case $oTypes->has('WORK'):
|
||||
$oProp = new Property(PropertyType::MOBILE_BUSSINES, $sTel);
|
||||
break;
|
||||
default:
|
||||
$oProp = new Property(PropertyType::MOBILE_PERSONAL, $sTel);
|
||||
break;
|
||||
}
|
||||
|
||||
if ($oProp)
|
||||
{
|
||||
if (!$bPref && $oTypes->has('pref'))
|
||||
{
|
||||
$bPref = true;
|
||||
\array_unshift($aProperties, $oProp);
|
||||
}
|
||||
else
|
||||
{
|
||||
\array_push($aProperties, $oProp);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
\array_unshift($aProperties,
|
||||
new Property(PropertyType::MOBILE_PERSONAL, $sTel));
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->addArrayPropertyHelper(&$aProperties, $oVCard->TEL, PropertyType::PHONE);
|
||||
}
|
||||
|
||||
|
||||
$this->Properties = $aProperties;
|
||||
}
|
||||
|
||||
$this->UpdateDependentValues(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function ToVCardObject($sPreVCard = '')
|
||||
{
|
||||
$oVCard = null;
|
||||
if (0 < \strlen($sPreVCard))
|
||||
{
|
||||
try
|
||||
{
|
||||
$oVCard = \Sabre\VObject\Reader::read($sPreVCard);
|
||||
}
|
||||
catch (\Exception $oExc) {};
|
||||
}
|
||||
|
||||
if (!$oVCard)
|
||||
{
|
||||
$oVCard = new \Sabre\VObject\Component\VCard();
|
||||
}
|
||||
|
||||
$oVCard->VERSION = '3.0';
|
||||
$oVCard->PRODID = '-//RainLoop//'.APP_VERSION.'//EN';
|
||||
|
||||
unset($oVCard->FN, $oVCard->EMAIL, $oVCard->TEL);
|
||||
|
||||
$bPrefEmail = $bPrefPhone = false;
|
||||
$sFirstName = $sLastName = $sMiddleName = $sSuffix = $sPrefix = '';
|
||||
foreach ($this->Properties as /* @var $oProperty \RainLoop\Providers\AddressBook\Classes\Property */ &$oProperty)
|
||||
{
|
||||
if ($oProperty)
|
||||
{
|
||||
switch ($oProperty->Type)
|
||||
{
|
||||
case PropertyType::FULLNAME:
|
||||
$oVCard->FN = $oProperty->Value;
|
||||
break;
|
||||
case PropertyType::NICK_NAME:
|
||||
$oVCard->NICKNAME = $oProperty->Value;
|
||||
break;
|
||||
case PropertyType::FIRST_NAME:
|
||||
$sFirstName = $oProperty->Value;
|
||||
break;
|
||||
case PropertyType::LAST_NAME:
|
||||
$sLastName = $oProperty->Value;
|
||||
break;
|
||||
case PropertyType::MIDDLE_NAME:
|
||||
$sMiddleName = $oProperty->Value;
|
||||
break;
|
||||
case PropertyType::NAME_SUFFIX:
|
||||
$sSuffix = $oProperty->Value;
|
||||
break;
|
||||
case PropertyType::NAME_PREFIX:
|
||||
$sPrefix = $oProperty->Value;
|
||||
break;
|
||||
case PropertyType::EMAIl_PERSONAL:
|
||||
case PropertyType::EMAIl_BUSSINES:
|
||||
case PropertyType::EMAIl_OTHER:
|
||||
$aParams = array('TYPE' => array('INTERNET'));
|
||||
$aParams['TYPE'][] = PropertyType::EMAIl_BUSSINES === $oProperty->Type ? 'WORK' : 'HOME';
|
||||
|
||||
if (!$bPrefEmail)
|
||||
{
|
||||
$bPrefEmail = true;
|
||||
$aParams['TYPE'][] = 'pref';
|
||||
}
|
||||
$oVCard->add('EMAIL', $oProperty->Value, $aParams);
|
||||
break;
|
||||
case PropertyType::WEB_PAGE_PERSONAL:
|
||||
case PropertyType::WEB_PAGE_BUSSINES:
|
||||
case PropertyType::WEB_PAGE_OTHER:
|
||||
$aParams = array('TYPE' => array());
|
||||
$aParams['TYPE'][] = PropertyType::WEB_PAGE_BUSSINES === $oProperty->Type ? 'WORK' : 'HOME';
|
||||
$oVCard->add('URL', $oProperty->Value, $aParams);
|
||||
break;
|
||||
case PropertyType::PHONE_PERSONAL:
|
||||
case PropertyType::PHONE_BUSSINES:
|
||||
case PropertyType::PHONE_OTHER:
|
||||
case PropertyType::MOBILE_PERSONAL:
|
||||
case PropertyType::MOBILE_BUSSINES:
|
||||
case PropertyType::MOBILE_OTHER:
|
||||
case PropertyType::FAX_PERSONAL:
|
||||
case PropertyType::FAX_BUSSINES:
|
||||
case PropertyType::FAX_OTHER:
|
||||
$aParams = array('TYPE' => array());
|
||||
$sType = '';
|
||||
if (\in_array($oProperty->Type, array(PropertyType::PHONE_PERSONAL, PropertyType::PHONE_BUSSINES, PropertyType::PHONE_OTHER)))
|
||||
{
|
||||
$sType = 'VOICE';
|
||||
}
|
||||
else if (\in_array($oProperty->Type, array(PropertyType::MOBILE_PERSONAL, PropertyType::MOBILE_BUSSINES, PropertyType::MOBILE_OTHER)))
|
||||
{
|
||||
$sType = 'CELL';
|
||||
}
|
||||
else if (\in_array($oProperty->Type, array(PropertyType::FAX_PERSONAL, PropertyType::FAX_BUSSINES, PropertyType::FAX_OTHER)))
|
||||
{
|
||||
$sType = 'FAX';
|
||||
}
|
||||
|
||||
if (!empty($sType))
|
||||
{
|
||||
$aParams['TYPE'][] = $sType;
|
||||
}
|
||||
|
||||
$aParams['TYPE'][] = \in_array($oProperty->Type, array(
|
||||
PropertyType::PHONE_BUSSINES, PropertyType::MOBILE_BUSSINES, PropertyType::FAX_BUSSINES)) ? 'WORK' : 'HOME';
|
||||
|
||||
if (!$bPrefPhone)
|
||||
{
|
||||
$bPrefPhone = true;
|
||||
$aParams['TYPE'][] = 'pref';
|
||||
}
|
||||
|
||||
$oVCard->add('TEL', $oProperty->Value, $aParams);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$oVCard->UID = $this->IdContactStr;
|
||||
$oVCard->N = array($sLastName, $sFirstName, $sMiddleName, $sPrefix, $sSuffix);
|
||||
$oVCard->REV = \gmdate('Ymd', $this->Changed).'T'.\gmdate('His', $this->Changed).'Z';
|
||||
|
||||
return $oVCard;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function VCardUri()
|
||||
{
|
||||
return $this->IdContactStr.'.vcf';
|
||||
$this->UpdateDependentValues();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ class Property
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $TypeCustom;
|
||||
public $TypeStr;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
|
@ -37,12 +37,13 @@ class Property
|
|||
public $Frec;
|
||||
|
||||
public function __construct(
|
||||
$iType = \RainLoop\Providers\AddressBook\Enumerations\PropertyType::UNKNOWN, $sValue = '')
|
||||
$iType = \RainLoop\Providers\AddressBook\Enumerations\PropertyType::UNKNOWN, $sValue = '', $sTypeStr = '')
|
||||
{
|
||||
$this->Clear();
|
||||
|
||||
$this->Type = $iType;
|
||||
$this->Value = $sValue;
|
||||
$this->TypeStr = $sTypeStr;
|
||||
}
|
||||
|
||||
public function Clear()
|
||||
|
@ -50,7 +51,7 @@ class Property
|
|||
$this->IdProperty = 0;
|
||||
|
||||
$this->Type = PropertyType::UNKNOWN;
|
||||
$this->TypeCustom = '';
|
||||
$this->TypeStr = '';
|
||||
|
||||
$this->Value = '';
|
||||
$this->ValueCustom = '';
|
||||
|
@ -63,9 +64,7 @@ class Property
|
|||
*/
|
||||
public function IsEmail()
|
||||
{
|
||||
return \in_array($this->Type, array(
|
||||
PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER
|
||||
));
|
||||
return PropertyType::EMAIl === $this->Type;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,18 +72,29 @@ class Property
|
|||
*/
|
||||
public function IsPhone()
|
||||
{
|
||||
return \in_array($this->Type, array(
|
||||
PropertyType::PHONE_PERSONAL, PropertyType::PHONE_BUSSINES, PropertyType::PHONE_OTHER,
|
||||
PropertyType::MOBILE_PERSONAL, PropertyType::MOBILE_BUSSINES, PropertyType::MOBILE_OTHER,
|
||||
PropertyType::FAX_PERSONAL, PropertyType::FAX_BUSSINES, PropertyType::FAX_OTHER
|
||||
));
|
||||
return PropertyType::PHONE === $this->Type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function TypesAsArray()
|
||||
{
|
||||
$aResult = array();
|
||||
if (!empty($this->TypeStr))
|
||||
{
|
||||
$sTypeStr = \preg_replace('/[\s]+/', '', $this->TypeStr);
|
||||
$aResult = \explode(',', $sTypeStr);
|
||||
}
|
||||
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
public function UpdateDependentValues()
|
||||
{
|
||||
$this->Value = \trim($this->Value);
|
||||
$this->ValueCustom = \trim($this->ValueCustom);
|
||||
$this->TypeCustom = \trim($this->TypeCustom);
|
||||
$this->TypeStr = \trim($this->TypeStr);
|
||||
|
||||
if (0 < \strlen($this->Value))
|
||||
{
|
||||
|
|
|
@ -16,21 +16,11 @@ class PropertyType
|
|||
const NAME_PREFIX = 20;
|
||||
const NAME_SUFFIX = 21;
|
||||
|
||||
const EMAIl_PERSONAL = 30;
|
||||
const EMAIl_BUSSINES = 31;
|
||||
const EMAIl_OTHER = 32;
|
||||
|
||||
const PHONE_PERSONAL = 50;
|
||||
const PHONE_BUSSINES = 51;
|
||||
const PHONE_OTHER = 52;
|
||||
|
||||
const MOBILE_PERSONAL = 60;
|
||||
const MOBILE_BUSSINES = 61;
|
||||
const MOBILE_OTHER = 62;
|
||||
|
||||
const FAX_PERSONAL = 70;
|
||||
const FAX_BUSSINES = 71;
|
||||
const FAX_OTHER = 72;
|
||||
const EMAIl = 30;
|
||||
const PHONE = 31;
|
||||
// const MOBILE = 32;
|
||||
// const FAX = 33;
|
||||
const WEB_PAGE = 32;
|
||||
|
||||
const FACEBOOK = 90;
|
||||
const SKYPE = 91;
|
||||
|
@ -38,9 +28,5 @@ class PropertyType
|
|||
|
||||
const NOTE = 110;
|
||||
|
||||
const WEB_PAGE_PERSONAL = 220;
|
||||
const WEB_PAGE_BUSSINES = 221;
|
||||
const WEB_PAGE_OTHER = 222;
|
||||
|
||||
const CUSTOM = 250;
|
||||
}
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace RainLoop\Providers\AddressBook\Enumerations;
|
||||
|
||||
class ScopeType
|
||||
{
|
||||
const DEFAULT_ = 0;
|
||||
const SHARE_ALL = 2;
|
||||
}
|
|
@ -47,15 +47,335 @@ class PdoAddressBook
|
|||
return \is_array($aDrivers) ? \in_array($this->sDsnType, $aDrivers) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function IsSharingAllowed()
|
||||
{
|
||||
return $this->IsSupported() && false; // TODO
|
||||
}
|
||||
|
||||
private function flushDeletedContacts($iUserID)
|
||||
{
|
||||
return !!$this->prepareAndExecute('DELETE FROM rainloop_ab_contacts WHERE id_user = :id_user AND deleted = 1', array(
|
||||
':id_user' => array($iUserID, \PDO::PARAM_INT)
|
||||
));
|
||||
}
|
||||
|
||||
private function updateContactEtagAndTime($iUserID, $mID, $sEtag, $iChanged)
|
||||
{
|
||||
return !!$this->prepareAndExecute('UPDATE rainloop_ab_contacts SET changed = :changed, etag = :etag '.
|
||||
'WHERE id_user = :id_user AND id_contact = :id_contact', array(
|
||||
':id_user' => array($iUserID, \PDO::PARAM_INT),
|
||||
':id_contact' => array($mID, \PDO::PARAM_INT),
|
||||
':changed' => array($iChanged, \PDO::PARAM_INT),
|
||||
':etag' => array($sEtag, \PDO::PARAM_STR)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private function prepearDatabaseSyncData($iUserID)
|
||||
{
|
||||
$aResult = array();
|
||||
$oStmt = $this->prepareAndExecute('SELECT id_contact, id_contact_str, changed, deleted, etag FROM rainloop_ab_contacts WHERE id_user = :id_user', array(
|
||||
':id_user' => array($iUserID, \PDO::PARAM_INT)
|
||||
));
|
||||
|
||||
if ($oStmt)
|
||||
{
|
||||
$aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||
if (\is_array($aFetch) && 0 < \count($aFetch))
|
||||
{
|
||||
foreach ($aFetch as $aItem)
|
||||
{
|
||||
if ($aItem && isset($aItem['id_contact'], $aItem['id_contact_str'], $aItem['changed'], $aItem['deleted'], $aItem['etag']) &&
|
||||
!empty($aItem['id_contact_str']))
|
||||
{
|
||||
$aResult[$aItem['id_contact_str']] = array(
|
||||
'id_contact' => $aItem['id_contact'],
|
||||
'etag' => $aItem['etag'],
|
||||
'changed' => (int) $aItem['changed'],
|
||||
'deleted' => '1' === (string) $aItem['deleted']
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
private function prepearRemoteSyncData($oClient, $sPath)
|
||||
{
|
||||
$mResult = false;
|
||||
$aResponse = null;
|
||||
try
|
||||
{
|
||||
$this->oLogger->Write('PROPFIND '.$sPath, \MailSo\Log\Enumerations\Type::INFO, 'DAV');
|
||||
$aResponse = $oClient->propFind($sPath, array(
|
||||
'{DAV:}getlastmodified',
|
||||
'{DAV:}getetag'
|
||||
), 1);
|
||||
|
||||
}
|
||||
catch (\Exception $oException)
|
||||
{
|
||||
$this->oLogger->WriteException($oException);
|
||||
}
|
||||
|
||||
if (\is_array($aResponse))
|
||||
{
|
||||
$mResult = array();
|
||||
foreach ($aResponse as $sKey => $aItem)
|
||||
{
|
||||
$sKey = \rtrim(\trim($sKey), '\\/');
|
||||
if (!empty($sKey) && is_array($aItem))
|
||||
{
|
||||
$aItem = \array_change_key_case($aItem, \CASE_LOWER);
|
||||
if (isset($aItem['{dav:}getetag'], $aItem['{dav:}getlastmodified']))
|
||||
{
|
||||
$aMatch = array();
|
||||
if (\preg_match('/\/([^\/?]+)$/', $sKey, $aMatch) && !empty($aMatch[1]))
|
||||
{
|
||||
$sVcfFileName = $aMatch[1];
|
||||
$sKeyID = \preg_replace('/\.vcf$/i', '', $sVcfFileName);
|
||||
|
||||
$mResult[$sKeyID] = array(
|
||||
'vcf' => $sVcfFileName,
|
||||
'etag' => \trim(\trim($aItem['{dav:}getetag']), '"\''),
|
||||
'lastmodified' => $aItem['{dav:}getlastmodified'],
|
||||
'changed' => \MailSo\Base\DateTimeHelper::ParseRFC2822DateString($aItem['{dav:}getlastmodified']),
|
||||
'deleted' => false
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $mResult;
|
||||
}
|
||||
|
||||
private function davClientRequest($oClient, $sCmd, $sUrl, $mData = null)
|
||||
{
|
||||
\MailSo\Base\Utils::ResetTimeLimit($this->iResetTimer);
|
||||
|
||||
$this->oLogger->Write($sCmd.' '.$sUrl.('PUT' === $sCmd && null !== $mData ? ' ('.\strlen($mData).')' : ''),
|
||||
\MailSo\Log\Enumerations\Type::INFO, 'DAV');
|
||||
|
||||
if ('PUT' === $sCmd)
|
||||
{
|
||||
$this->oLogger->Write($mData, \MailSo\Log\Enumerations\Type::INFO, 'DAV');
|
||||
}
|
||||
|
||||
$oResponse = false;
|
||||
try
|
||||
{
|
||||
$oResponse = 'PUT' === $sCmd && null !== $mData ?
|
||||
$oClient->request($sCmd, $sUrl, $mData) : $oClient->request($sCmd, $sUrl);
|
||||
|
||||
if ('GET' === $sCmd || false)
|
||||
{
|
||||
$this->oLogger->WriteDump($oResponse, \MailSo\Log\Enumerations\Type::INFO, 'DAV');
|
||||
}
|
||||
}
|
||||
catch (\Exception $oException)
|
||||
{
|
||||
$this->oLogger->WriteException($oException);
|
||||
}
|
||||
|
||||
return $oResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sEmail
|
||||
* @param \RainLoop\Providers\AddressBook\Classes\Contact $oContact
|
||||
* @param string $sUrl
|
||||
* @param string $sUser
|
||||
* @param string $sPassword
|
||||
* @param string $sProxy = ''
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function ContactSave($sEmail, &$oContact)
|
||||
public function Sync($sEmail, $sUrl, $sUser, $sPassword, $sProxy = '')
|
||||
{
|
||||
$this->Sync();
|
||||
$this->SyncDatabase();
|
||||
|
||||
$iUserID = $this->getUserId($sEmail);
|
||||
if (0 >= $iUserID)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$aUrl = \parse_url($sUrl);
|
||||
if (!\is_array($aUrl))
|
||||
{
|
||||
$aUrl = array();
|
||||
}
|
||||
|
||||
$aUrl['scheme'] = isset($aUrl['scheme']) ? $aUrl['scheme'] : 'http';
|
||||
$aUrl['host'] = isset($aUrl['host']) ? $aUrl['host'] : 'localhost';
|
||||
$aUrl['port'] = isset($aUrl['port']) ? $aUrl['port'] : 80;
|
||||
$aUrl['path'] = isset($aUrl['path']) ? \rtrim($aUrl['path'], '\\/').'/' : '/';
|
||||
|
||||
$aSettings = array(
|
||||
'baseUri' => $aUrl['scheme'].'://'.$aUrl['host'].('80' === (string) $aUrl['port'] ? '' : ':'.$aUrl['port']),
|
||||
'userName' => $sUser,
|
||||
'password' => $sPassword
|
||||
);
|
||||
|
||||
if (!empty($sProxy))
|
||||
{
|
||||
$aSettings['proxy'] = $sProxy;
|
||||
}
|
||||
|
||||
$sPath = $aUrl['path'];
|
||||
|
||||
$oClient = new \Sabre\DAV\Client($aSettings);
|
||||
$oClient->setVerifyPeer(false);
|
||||
|
||||
$aRemoteSyncData = $this->prepearRemoteSyncData($oClient, $sPath);
|
||||
if (false === $aRemoteSyncData)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$aDatabaseSyncData = $this->prepearDatabaseSyncData($iUserID);
|
||||
|
||||
// $this->oLogger->WriteDump($aDatabaseSyncData);
|
||||
// $this->oLogger->WriteDump($aRemoteSyncData);
|
||||
|
||||
//+++del (from carddav)
|
||||
foreach ($aDatabaseSyncData as $sKey => $aData)
|
||||
{
|
||||
if ($aData['deleted'] &&
|
||||
isset($aRemoteSyncData[$sKey], $aRemoteSyncData[$sKey]['vcf']))
|
||||
{
|
||||
$this->davClientRequest($oClient, 'DELETE', $sPath.$aRemoteSyncData[$sKey]['vcf']);
|
||||
}
|
||||
}
|
||||
//---del
|
||||
|
||||
//+++del (from db)
|
||||
$aIdsForDeletedion = array();
|
||||
foreach ($aDatabaseSyncData as $sKey => $aData)
|
||||
{
|
||||
if (!$aData['deleted'] && !empty($aData['etag']) && !isset($aRemoteSyncData[$sKey]))
|
||||
{
|
||||
$aIdsForDeletedion[] = $aData['id_contact'];
|
||||
}
|
||||
}
|
||||
|
||||
if (0 < \count($aIdsForDeletedion))
|
||||
{
|
||||
$this->DeleteContacts($sEmail, $aIdsForDeletedion, false);
|
||||
}
|
||||
//---del
|
||||
|
||||
$this->flushDeletedContacts($iUserID);
|
||||
|
||||
//+++new or newer (from db)
|
||||
foreach ($aDatabaseSyncData as $sKey => $aData)
|
||||
{
|
||||
if (!$aData['deleted'] &&
|
||||
(empty($aData['etag']) && !isset($aRemoteSyncData[$sKey])) // new
|
||||
||
|
||||
(!empty($aData['etag']) && isset($aRemoteSyncData[$sKey]) && // newer
|
||||
$aRemoteSyncData[$sKey]['etag'] !== $aData['etag'] &&
|
||||
$aRemoteSyncData[$sKey]['changed'] < $aData['changed']
|
||||
)
|
||||
)
|
||||
{
|
||||
$mID = $aData['id_contact'];
|
||||
$oContact = $this->GetContactByID($sEmail, $mID, false);
|
||||
if ($oContact)
|
||||
{
|
||||
$sExsistensBody = '';
|
||||
$mExsistenRemoteID = isset($aRemoteSyncData[$sKey]['vcf']) && !empty($aData['etag']) ? $aRemoteSyncData[$sKey]['vcf'] : '';
|
||||
if (0 < \strlen($mExsistenRemoteID))
|
||||
{
|
||||
$oResponse = $this->davClientRequest($oClient, 'GET', $sPath.$mExsistenRemoteID);
|
||||
if ($oResponse && isset($oResponse['headers'], $oResponse['body']))
|
||||
{
|
||||
$sExsistensBody = \trim($oResponse['body']);
|
||||
}
|
||||
}
|
||||
|
||||
$oResponse = $this->davClientRequest($oClient, 'PUT',
|
||||
$sPath.$oContact->CardDavNameUri(), $oContact->ToVCard($sExsistensBody));
|
||||
|
||||
if ($oResponse && isset($oResponse['headers'], $oResponse['headers']['etag']))
|
||||
{
|
||||
$sEtag = \trim(\trim($oResponse['headers']['etag']), '"\'');
|
||||
$sDate = !empty($oResponse['headers']['date']) ? \trim($oResponse['headers']['date']) : '';
|
||||
if (!empty($sEtag))
|
||||
{
|
||||
$iChanged = empty($sDate) ? \time() : \MailSo\Base\DateTimeHelper::ParseRFC2822DateString($sDate);
|
||||
$this->updateContactEtagAndTime($iUserID, $mID, $sEtag, $iChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unset($oContact);
|
||||
}
|
||||
}
|
||||
//---new
|
||||
|
||||
//+++new or newer (from carddav)
|
||||
foreach ($aRemoteSyncData as $sKey => $aData)
|
||||
{
|
||||
if (!isset($aDatabaseSyncData[$sKey]) // new
|
||||
||
|
||||
($aDatabaseSyncData[$sKey]['etag'] !== $aData['etag'] && // newer
|
||||
$aDatabaseSyncData[$sKey]['changed'] < $aData['changed'])
|
||||
)
|
||||
{
|
||||
$mExsistenContactID = isset($aDatabaseSyncData[$sKey]['id_contact']) ?
|
||||
$aDatabaseSyncData[$sKey]['id_contact'] : '';
|
||||
|
||||
$oResponse = $this->davClientRequest($oClient, 'GET', $sPath.$aData['vcf']);
|
||||
if ($oResponse && isset($oResponse['headers'], $oResponse['body']))
|
||||
{
|
||||
$sBody = \trim($oResponse['body']);
|
||||
if (!empty($sBody))
|
||||
{
|
||||
$oContact = null;
|
||||
if ($mExsistenContactID)
|
||||
{
|
||||
$oContact = $this->GetContactByID($sEmail, $mExsistenContactID);
|
||||
}
|
||||
|
||||
if (!$oContact)
|
||||
{
|
||||
$oContact = new \RainLoop\Providers\AddressBook\Classes\Contact();
|
||||
}
|
||||
|
||||
$oContact->PopulateByVCard($sBody,
|
||||
!empty($oResponse['headers']['etag']) ? \trim(\trim($oResponse['headers']['etag']), '"\'') : '');
|
||||
|
||||
$this->ContactSave($sEmail, $oContact);
|
||||
unset($oContact);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sEmail
|
||||
* @param \RainLoop\Providers\AddressBook\Classes\Contact $oContact
|
||||
* @param bool $bSyncDb = true
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function ContactSave($sEmail, &$oContact, $bSyncDb = true)
|
||||
{
|
||||
if ($bSyncDb)
|
||||
{
|
||||
$this->SyncDatabase();
|
||||
}
|
||||
|
||||
$iUserID = $this->getUserId($sEmail);
|
||||
|
||||
$iIdContact = 0 < \strlen($oContact->IdContact) && \is_numeric($oContact->IdContact) ? (int) $oContact->IdContact : 0;
|
||||
|
@ -77,7 +397,7 @@ class PdoAddressBook
|
|||
{
|
||||
$aFreq = $this->getContactFreq($iUserID, $iIdContact);
|
||||
|
||||
$sSql = 'UPDATE rainloop_ab_contacts SET id_contact_str = :id_contact_str, display = :display, changed = :changed, hash = :hash '.
|
||||
$sSql = 'UPDATE rainloop_ab_contacts SET id_contact_str = :id_contact_str, display = :display, changed = :changed, etag = :etag '.
|
||||
'WHERE id_user = :id_user AND id_contact = :id_contact';
|
||||
|
||||
$this->prepareAndExecute($sSql,
|
||||
|
@ -87,7 +407,7 @@ class PdoAddressBook
|
|||
':id_contact_str' => array($oContact->IdContactStr, \PDO::PARAM_STR),
|
||||
':display' => array($oContact->Display, \PDO::PARAM_STR),
|
||||
':changed' => array($oContact->Changed, \PDO::PARAM_INT),
|
||||
':hash' => array($oContact->Hash, \PDO::PARAM_STR)
|
||||
':etag' => array($oContact->Etag, \PDO::PARAM_STR)
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -103,8 +423,8 @@ class PdoAddressBook
|
|||
else
|
||||
{
|
||||
$sSql = 'INSERT INTO rainloop_ab_contacts '.
|
||||
'( id_user, id_contact_str, display, changed, hash) VALUES '.
|
||||
'(:id_user, :id_contact_str, :display, :changed, :hash)';
|
||||
'( id_user, id_contact_str, display, changed, etag) VALUES '.
|
||||
'(:id_user, :id_contact_str, :display, :changed, :etag)';
|
||||
|
||||
$this->prepareAndExecute($sSql,
|
||||
array(
|
||||
|
@ -112,11 +432,11 @@ class PdoAddressBook
|
|||
':id_contact_str' => array($oContact->IdContactStr, \PDO::PARAM_STR),
|
||||
':display' => array($oContact->Display, \PDO::PARAM_STR),
|
||||
':changed' => array($oContact->Changed, \PDO::PARAM_INT),
|
||||
':hash' => array($oContact->Hash, \PDO::PARAM_STR)
|
||||
':etag' => array($oContact->Etag, \PDO::PARAM_STR)
|
||||
)
|
||||
);
|
||||
|
||||
$sLast = $this->lastInsertId('id_contact');
|
||||
$sLast = $this->lastInsertId('rainloop_ab_contacts', 'id_contact');
|
||||
if (\is_numeric($sLast) && 0 < (int) $sLast)
|
||||
{
|
||||
$iIdContact = (int) $sLast;
|
||||
|
@ -139,7 +459,7 @@ class PdoAddressBook
|
|||
':id_contact' => array($iIdContact, \PDO::PARAM_INT),
|
||||
':id_user' => array($iUserID, \PDO::PARAM_INT),
|
||||
':prop_type' => array($oProp->Type, \PDO::PARAM_INT),
|
||||
':prop_type_custom' => array($oProp->TypeCustom, \PDO::PARAM_STR),
|
||||
':prop_type_str' => array($oProp->TypeStr, \PDO::PARAM_STR),
|
||||
':prop_value' => array($oProp->Value, \PDO::PARAM_STR),
|
||||
':prop_value_custom' => array($oProp->ValueCustom, \PDO::PARAM_STR),
|
||||
':prop_frec' => array($iFreq, \PDO::PARAM_INT),
|
||||
|
@ -147,8 +467,8 @@ class PdoAddressBook
|
|||
}
|
||||
|
||||
$sSql = 'INSERT INTO rainloop_ab_properties '.
|
||||
'( id_contact, id_user, prop_type, prop_type_custom, prop_value, prop_value_custom, prop_frec) VALUES '.
|
||||
'(:id_contact, :id_user, :prop_type, :prop_type_custom, :prop_value, :prop_value_custom, :prop_frec)';
|
||||
'( id_contact, id_user, prop_type, prop_type_str, prop_value, prop_value_custom, prop_frec) VALUES '.
|
||||
'(:id_contact, :id_user, :prop_type, :prop_type_str, :prop_value, :prop_value_custom, :prop_frec)';
|
||||
|
||||
$this->prepareAndExecute($sSql, $aParams, true);
|
||||
}
|
||||
|
@ -174,12 +494,17 @@ class PdoAddressBook
|
|||
/**
|
||||
* @param string $sEmail
|
||||
* @param array $aContactIds
|
||||
* @param bool $bSyncDb = true
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function DeleteContacts($sEmail, $aContactIds)
|
||||
public function DeleteContacts($sEmail, $aContactIds, $bSyncDb = true)
|
||||
{
|
||||
$this->Sync();
|
||||
if ($bSyncDb)
|
||||
{
|
||||
$this->SyncDatabase();
|
||||
}
|
||||
|
||||
$iUserID = $this->getUserId($sEmail);
|
||||
|
||||
$aContactIds = \array_filter($aContactIds, function (&$mItem) {
|
||||
|
@ -196,7 +521,44 @@ class PdoAddressBook
|
|||
$aParams = array(':id_user' => array($iUserID, \PDO::PARAM_INT));
|
||||
|
||||
$this->prepareAndExecute('DELETE FROM rainloop_ab_properties WHERE id_user = :id_user AND id_contact IN ('.$sIDs.')', $aParams);
|
||||
$this->prepareAndExecute('DELETE FROM rainloop_ab_contacts WHERE id_user = :id_user AND id_contact IN ('.$sIDs.')', $aParams);
|
||||
|
||||
$aParams = array(
|
||||
':id_user' => array($iUserID, \PDO::PARAM_INT),
|
||||
':changed' => array(\time(), \PDO::PARAM_INT)
|
||||
);
|
||||
|
||||
$this->prepareAndExecute('UPDATE rainloop_ab_contacts SET deleted = 1, changed = :changed '.
|
||||
'WHERE id_user = :id_user AND id_contact IN ('.$sIDs.')', $aParams);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sEmail
|
||||
* @param array $aTagsIds
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function DeleteTags($sEmail, $aTagsIds)
|
||||
{
|
||||
$this->SyncDatabase();
|
||||
$iUserID = $this->getUserId($sEmail);
|
||||
|
||||
$aTagsIds = \array_filter($aTagsIds, function (&$mItem) {
|
||||
$mItem = (int) \trim($mItem);
|
||||
return 0 < $mItem;
|
||||
});
|
||||
|
||||
if (0 === \count($aTagsIds))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$sIDs = \implode(',', $aTagsIds);
|
||||
$aParams = array(':id_user' => array($iUserID, \PDO::PARAM_INT));
|
||||
|
||||
$this->prepareAndExecute('DELETE FROM rainloop_pab_tags_contacts WHERE id_tag IN ('.$sIDs.')');
|
||||
$this->prepareAndExecute('DELETE FROM rainloop_pab_tags WHERE id_user = :id_user AND id_tag IN ('.$sIDs.')', $aParams);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -212,7 +574,7 @@ class PdoAddressBook
|
|||
*/
|
||||
public function GetContacts($sEmail, $iOffset = 0, $iLimit = 20, $sSearch = '', &$iResultCount = 0)
|
||||
{
|
||||
$this->Sync();
|
||||
$this->SyncDatabase();
|
||||
|
||||
$iOffset = 0 <= $iOffset ? $iOffset : 0;
|
||||
$iLimit = 0 < $iLimit ? (int) $iLimit : 20;
|
||||
|
@ -235,11 +597,7 @@ class PdoAddressBook
|
|||
|
||||
$sSql = 'SELECT id_user, id_prop, id_contact FROM rainloop_ab_properties '.
|
||||
'WHERE (id_user = :id_user) AND (prop_value LIKE :search ESCAPE \'=\''.
|
||||
(0 < \strlen($sCustomSearch) ? ' OR (prop_type IN ('.\implode(',', array(
|
||||
PropertyType::PHONE_PERSONAL, PropertyType::PHONE_BUSSINES, PropertyType::PHONE_OTHER,
|
||||
PropertyType::MOBILE_PERSONAL, PropertyType::MOBILE_BUSSINES, PropertyType::MOBILE_OTHER,
|
||||
PropertyType::FAX_PERSONAL, PropertyType::FAX_BUSSINES, PropertyType::FAX_OTHER
|
||||
)).') AND prop_value_custom <> \'\' AND prop_value_custom LIKE :search_custom_phone)' : '').
|
||||
(0 < \strlen($sCustomSearch) ? ' OR prop_type = '.PropertyType::PHONE.' AND prop_value_custom <> \'\' AND prop_value_custom LIKE :search_custom_phone)' : '').
|
||||
') GROUP BY id_contact, id_prop';
|
||||
|
||||
$aParams = array(
|
||||
|
@ -297,7 +655,7 @@ class PdoAddressBook
|
|||
|
||||
if (0 < $iCount)
|
||||
{
|
||||
$sSql = 'SELECT * FROM rainloop_ab_contacts WHERE id_user = :id_user';
|
||||
$sSql = 'SELECT * FROM rainloop_ab_contacts WHERE deleted = 0 AND id_user = :id_user';
|
||||
|
||||
$aParams = array(
|
||||
':id_user' => array($iUserID, \PDO::PARAM_INT)
|
||||
|
@ -367,7 +725,7 @@ class PdoAddressBook
|
|||
$oProperty = new \RainLoop\Providers\AddressBook\Classes\Property();
|
||||
$oProperty->IdProperty = (int) $aItem['id_prop'];
|
||||
$oProperty->Type = (int) $aItem['prop_type'];
|
||||
$oProperty->TypeCustom = isset($aItem['prop_type_custom']) ? (string) $aItem['prop_type_custom'] : '';
|
||||
$oProperty->TypeStr = isset($aItem['prop_type_str']) ? (string) $aItem['prop_type_str'] : '';
|
||||
$oProperty->Value = (string) $aItem['prop_value'];
|
||||
$oProperty->ValueCustom = isset($aItem['prop_value_custom']) ? (string) $aItem['prop_value_custom'] : '';
|
||||
$oProperty->Frec = isset($aItem['prop_frec']) ? (int) $aItem['prop_frec'] : 0;
|
||||
|
@ -403,13 +761,11 @@ class PdoAddressBook
|
|||
*/
|
||||
public function GetContactByID($sEmail, $mID, $bIsStrID = false)
|
||||
{
|
||||
$this->Sync();
|
||||
|
||||
$mID = \trim($mID);
|
||||
|
||||
$iUserID = $this->getUserId($sEmail);
|
||||
|
||||
$sSql = 'SELECT * FROM rainloop_ab_contacts WHERE id_user = :id_user';
|
||||
$sSql = 'SELECT * FROM rainloop_ab_contacts WHERE deleted = 0 AND id_user = :id_user';
|
||||
|
||||
$aParams = array(
|
||||
':id_user' => array($iUserID, \PDO::PARAM_INT)
|
||||
|
@ -450,7 +806,7 @@ class PdoAddressBook
|
|||
$oContact->Display = isset($aItem['display']) ? (string) $aItem['display'] : '';
|
||||
$oContact->Changed = isset($aItem['changed']) ? (int) $aItem['changed'] : 0;
|
||||
$oContact->ReadOnly = $iUserID !== (isset($aItem['id_user']) ? (int) $aItem['id_user'] : 0);
|
||||
$oContact->Hash = empty($aItem['hash']) ? '' : (string) $aItem['hash'];
|
||||
$oContact->Etag = empty($aItem['etag']) ? '' : (string) $aItem['etag'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -478,7 +834,7 @@ class PdoAddressBook
|
|||
$oProperty = new \RainLoop\Providers\AddressBook\Classes\Property();
|
||||
$oProperty->IdProperty = (int) $aItem['id_prop'];
|
||||
$oProperty->Type = (int) $aItem['prop_type'];
|
||||
$oProperty->TypeCustom = isset($aItem['prop_type_custom']) ? (string) $aItem['prop_type_custom'] : '';
|
||||
$oProperty->TypeStr = isset($aItem['prop_type_str']) ? (string) $aItem['prop_type_str'] : '';
|
||||
$oProperty->Value = (string) $aItem['prop_value'];
|
||||
$oProperty->ValueCustom = isset($aItem['prop_value_custom']) ? (string) $aItem['prop_value_custom'] : '';
|
||||
$oProperty->Frec = isset($aItem['prop_frec']) ? (int) $aItem['prop_frec'] : 0;
|
||||
|
@ -516,12 +872,12 @@ class PdoAddressBook
|
|||
throw new \InvalidArgumentException('Empty Search argument');
|
||||
}
|
||||
|
||||
$this->Sync();
|
||||
$this->SyncDatabase();
|
||||
|
||||
$iUserID = $this->getUserId($sEmail);
|
||||
|
||||
$sTypes = implode(',', array(
|
||||
PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER, PropertyType::FIRST_NAME, PropertyType::LAST_NAME
|
||||
PropertyType::EMAIl, PropertyType::FIRST_NAME, PropertyType::LAST_NAME
|
||||
));
|
||||
|
||||
$sSql = 'SELECT id_contact, id_prop, prop_type, prop_value FROM rainloop_ab_properties '.
|
||||
|
@ -575,7 +931,7 @@ class PdoAddressBook
|
|||
$oStmt->closeCursor();
|
||||
|
||||
$sTypes = \implode(',', array(
|
||||
PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER, PropertyType::FIRST_NAME, PropertyType::LAST_NAME
|
||||
PropertyType::EMAIl, PropertyType::FIRST_NAME, PropertyType::LAST_NAME
|
||||
));
|
||||
|
||||
$sSql = 'SELECT id_prop, id_contact, prop_type, prop_value FROM rainloop_ab_properties '.
|
||||
|
@ -607,8 +963,8 @@ class PdoAddressBook
|
|||
|
||||
$aNames[$iIdContact][PropertyType::LAST_NAME === $iType ? 0 : 1] = $aItem['prop_value'];
|
||||
}
|
||||
else if ((isset($aIdProps[$iIdProp]) || isset($aContactAllAccess[$iIdContact]))&&
|
||||
\in_array($iType, array(PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES)))
|
||||
else if ((isset($aIdProps[$iIdProp]) || isset($aContactAllAccess[$iIdContact])) &&
|
||||
PropertyType::EMAIl === $iType)
|
||||
{
|
||||
if (!isset($aEmails[$iIdContact]))
|
||||
{
|
||||
|
@ -676,22 +1032,19 @@ class PdoAddressBook
|
|||
throw new \InvalidArgumentException('Empty Emails argument');
|
||||
}
|
||||
|
||||
$this->Sync();
|
||||
$this->SyncDatabase();
|
||||
$iUserID = $this->getUserId($sEmail);
|
||||
|
||||
$sTypes = \implode(',', array(
|
||||
PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER
|
||||
));
|
||||
|
||||
$aExists = array();
|
||||
$aEmailsToCreate = array();
|
||||
$aEmailsToUpdate = array();
|
||||
|
||||
if ($bCreateAuto)
|
||||
{
|
||||
$sSql = 'SELECT prop_value FROM rainloop_ab_properties WHERE id_user = :id_user AND prop_type IN ('.$sTypes.')';
|
||||
$sSql = 'SELECT prop_value FROM rainloop_ab_properties WHERE id_user = :id_user AND prop_type = :prop_type';
|
||||
$oStmt = $this->prepareAndExecute($sSql, array(
|
||||
':id_user' => array($iUserID, \PDO::PARAM_INT)
|
||||
':id_user' => array($iUserID, \PDO::PARAM_INT),
|
||||
':prop_type' => array(PropertyType::EMAIl, \PDO::PARAM_INT)
|
||||
));
|
||||
|
||||
if ($oStmt)
|
||||
|
@ -748,7 +1101,7 @@ class PdoAddressBook
|
|||
if ('' !== \trim($oEmail->GetEmail()))
|
||||
{
|
||||
$oPropEmail = new \RainLoop\Providers\AddressBook\Classes\Property();
|
||||
$oPropEmail->Type = \RainLoop\Providers\AddressBook\Enumerations\PropertyType::EMAIl_PERSONAL;
|
||||
$oPropEmail->Type = \RainLoop\Providers\AddressBook\Enumerations\PropertyType::EMAIl;
|
||||
$oPropEmail->Value = \strtolower(\trim($oEmail->GetEmail()));
|
||||
|
||||
$oContact->Properties[] = $oPropEmail;
|
||||
|
@ -797,7 +1150,7 @@ class PdoAddressBook
|
|||
}
|
||||
}
|
||||
|
||||
$sSql = 'UPDATE rainloop_ab_properties SET prop_frec = prop_frec + 1 WHERE id_user = :id_user AND prop_type IN ('.$sTypes;
|
||||
$sSql = 'UPDATE rainloop_ab_properties SET prop_frec = prop_frec + 1 WHERE id_user = :id_user AND prop_type = :prop_type';
|
||||
|
||||
$aEmailsQuoted = \array_map(function ($mItem) use ($self) {
|
||||
return $self->quoteValue($mItem);
|
||||
|
@ -805,15 +1158,16 @@ class PdoAddressBook
|
|||
|
||||
if (1 === \count($aEmailsQuoted))
|
||||
{
|
||||
$sSql .= ') AND prop_value = '.$aEmailsQuoted[0];
|
||||
$sSql .= ' AND prop_value = '.$aEmailsQuoted[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSql .= ') AND prop_value IN ('.\implode(',', $aEmailsQuoted).')';
|
||||
$sSql .= ' AND prop_value IN ('.\implode(',', $aEmailsQuoted).')';
|
||||
}
|
||||
|
||||
|
||||
return !!$this->prepareAndExecute($sSql, array(
|
||||
':id_user' => array($iUserID, \PDO::PARAM_INT),
|
||||
':prop_type' => array(PropertyType::EMAIl, \PDO::PARAM_INT)
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -825,7 +1179,7 @@ class PdoAddressBook
|
|||
$sResult = '';
|
||||
try
|
||||
{
|
||||
$this->Sync();
|
||||
$this->SyncDatabase();
|
||||
if (0 >= $this->getVersion($this->sDsnType.'-ab-version'))
|
||||
{
|
||||
$sResult = 'Unknown database error';
|
||||
|
@ -857,14 +1211,13 @@ class PdoAddressBook
|
|||
|
||||
CREATE TABLE IF NOT EXISTS rainloop_ab_contacts (
|
||||
|
||||
id_contact bigint UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
id_contact_str varchar(128) NOT NULL DEFAULT \'\',
|
||||
id_user int UNSIGNED NOT NULL,
|
||||
display_name varchar(255) NOT NULL DEFAULT '',
|
||||
display_email varchar(255) NOT NULL DEFAULT '',
|
||||
display varchar(255) NOT NULL DEFAULT '',
|
||||
changed int UNSIGNED NOT NULL DEFAULT 0,
|
||||
hash varchar(128) NOT NULL DEFAULT \'\',
|
||||
id_contact bigint UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
id_contact_str varchar(128) NOT NULL DEFAULT '',
|
||||
id_user int UNSIGNED NOT NULL,
|
||||
display varchar(255) NOT NULL DEFAULT '',
|
||||
changed int UNSIGNED NOT NULL DEFAULT 0,
|
||||
deleted tinyint UNSIGNED NOT NULL DEFAULT 0,
|
||||
etag varchar(128) /*!40101 CHARACTER SET ascii COLLATE ascii_general_ci */ NOT NULL DEFAULT '',
|
||||
|
||||
PRIMARY KEY(id_contact),
|
||||
INDEX id_user_rainloop_ab_contacts_index (id_user)
|
||||
|
@ -873,20 +1226,42 @@ CREATE TABLE IF NOT EXISTS rainloop_ab_contacts (
|
|||
|
||||
CREATE TABLE IF NOT EXISTS rainloop_ab_properties (
|
||||
|
||||
id_prop bigint UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
id_contact bigint UNSIGNED NOT NULL,
|
||||
id_user int UNSIGNED NOT NULL,
|
||||
prop_type tinyint UNSIGNED NOT NULL,
|
||||
prop_type_custom varchar(50) /*!40101 CHARACTER SET ascii COLLATE ascii_general_ci */ NOT NULL DEFAULT '',
|
||||
prop_value varchar(255) NOT NULL DEFAULT '',
|
||||
prop_value_custom varchar(255) NOT NULL DEFAULT '',
|
||||
prop_frec int UNSIGNED NOT NULL DEFAULT 0,
|
||||
id_prop bigint UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
id_contact bigint UNSIGNED NOT NULL,
|
||||
id_user int UNSIGNED NOT NULL,
|
||||
prop_type tinyint UNSIGNED NOT NULL,
|
||||
prop_type_str varchar(255) /*!40101 CHARACTER SET ascii COLLATE ascii_general_ci */ NOT NULL DEFAULT '',
|
||||
prop_value varchar(255) NOT NULL DEFAULT '',
|
||||
prop_value_custom varchar(255) NOT NULL DEFAULT '',
|
||||
prop_frec int UNSIGNED NOT NULL DEFAULT 0,
|
||||
|
||||
PRIMARY KEY(id_prop),
|
||||
INDEX id_user_rainloop_ab_properties_index (id_user),
|
||||
INDEX id_user_id_contact_rainloop_ab_properties_index (id_user, id_contact)
|
||||
|
||||
)/*!40000 ENGINE=INNODB *//*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS rainloop_ab_tags (
|
||||
|
||||
id_tag int UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
id_user int UNSIGNED NOT NULL,
|
||||
tag_name varchar(255) NOT NULL,
|
||||
|
||||
PRIMARY KEY(id_tag),
|
||||
INDEX id_user_rainloop_ab_tags_index (id_user),
|
||||
INDEX id_user_name_rainloop_ab_tags_index (id_user, tag_name)
|
||||
|
||||
)/*!40000 ENGINE=INNODB *//*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS rainloop_ab_tags_contacts (
|
||||
|
||||
id_tag int UNSIGNED NOT NULL,
|
||||
id_contact bigint UNSIGNED NOT NULL,
|
||||
|
||||
INDEX id_tag_rainloop_ab_tags_contacts_index (id_tag),
|
||||
INDEX id_contact_rainloop_ab_tags_contacts_index (id_contact)
|
||||
|
||||
)/*!40000 ENGINE=INNODB */;
|
||||
MYSQLINITIAL;
|
||||
break;
|
||||
|
||||
|
@ -894,31 +1269,48 @@ MYSQLINITIAL;
|
|||
$sInitial = <<<POSTGRESINITIAL
|
||||
|
||||
CREATE TABLE rainloop_ab_contacts (
|
||||
id_contact bigserial PRIMARY KEY,
|
||||
id_user integer NOT NULL,
|
||||
display_name varchar(128) NOT NULL DEFAULT '',
|
||||
display_email varchar(128) NOT NULL DEFAULT '',
|
||||
display varchar(128) NOT NULL DEFAULT '',
|
||||
changed integer NOT NULL default 0.
|
||||
hash varchar(128) NOT NULL DEFAULT ''
|
||||
id_contact bigserial PRIMARY KEY,
|
||||
id_contact_str varchar(128) NOT NULL DEFAULT '',
|
||||
id_user integer NOT NULL,
|
||||
display varchar(255) NOT NULL DEFAULT '',
|
||||
changed integer NOT NULL default 0,
|
||||
deleted integer NOT NULL default 0,
|
||||
etag varchar(128) NOT NULL DEFAULT ''
|
||||
);
|
||||
|
||||
CREATE INDEX id_user_rainloop_ab_contacts_index ON rainloop_ab_contacts (id_user);
|
||||
|
||||
CREATE TABLE rainloop_ab_properties (
|
||||
id_prop bigserial PRIMARY KEY,
|
||||
id_contact integer NOT NULL,
|
||||
id_user integer NOT NULL,
|
||||
prop_type integer NOT NULL,
|
||||
prop_type_custom varchar(50) NOT NULL DEFAULT '',
|
||||
prop_value varchar(128) NOT NULL DEFAULT '',
|
||||
prop_value_custom varchar(128) NOT NULL DEFAULT '',
|
||||
prop_frec integer NOT NULL default 0
|
||||
id_prop bigserial PRIMARY KEY,
|
||||
id_contact integer NOT NULL,
|
||||
id_user integer NOT NULL,
|
||||
prop_type integer NOT NULL,
|
||||
prop_type_str varchar(255) NOT NULL DEFAULT '',
|
||||
prop_value text NOT NULL DEFAULT '',
|
||||
prop_value_custom text NOT NULL DEFAULT '',
|
||||
prop_frec integer NOT NULL default 0
|
||||
);
|
||||
|
||||
CREATE INDEX id_user_rainloop_ab_properties_index ON rainloop_ab_properties (id_user);
|
||||
CREATE INDEX id_user_id_contact_rainloop_ab_properties_index ON rainloop_ab_properties (id_user, id_contact);
|
||||
|
||||
CREATE TABLE rainloop_ab_tags (
|
||||
id_tag serial PRIMARY KEY,
|
||||
id_user integer NOT NULL,
|
||||
tag_name varchar(255) NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX id_user_rainloop_ab_tags_index ON rainloop_ab_tags (id_user);
|
||||
CREATE INDEX id_user_name_rainloop_ab_tags_index ON rainloop_ab_tags (id_user, tag_name);
|
||||
|
||||
CREATE TABLE rainloop_ab_tags_contacts (
|
||||
id_tag integer NOT NULL,
|
||||
id_contact integer NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX id_tag_rainloop_ab_tags_index ON rainloop_ab_tags_contacts (id_tag);
|
||||
CREATE INDEX id_contact_rainloop_ab_tags_index ON rainloop_ab_tags_contacts (id_contact);
|
||||
|
||||
POSTGRESINITIAL;
|
||||
break;
|
||||
|
||||
|
@ -926,31 +1318,48 @@ POSTGRESINITIAL;
|
|||
$sInitial = <<<SQLITEINITIAL
|
||||
|
||||
CREATE TABLE rainloop_ab_contacts (
|
||||
id_contact integer NOT NULL PRIMARY KEY,
|
||||
id_user integer NOT NULL,
|
||||
display_name text NOT NULL DEFAULT '',
|
||||
display_email text NOT NULL DEFAULT '',
|
||||
display text NOT NULL DEFAULT '',
|
||||
changed integer NOT NULL DEFAULT 0,
|
||||
hash text NOT NULL DEFAULT ''
|
||||
id_contact integer NOT NULL PRIMARY KEY,
|
||||
id_contact_str text NOT NULL DEFAULT '',
|
||||
id_user integer NOT NULL,
|
||||
display text NOT NULL DEFAULT '',
|
||||
changed integer NOT NULL DEFAULT 0,
|
||||
deleted integer NOT NULL DEFAULT 0,
|
||||
etag text NOT NULL DEFAULT ''
|
||||
);
|
||||
|
||||
CREATE INDEX id_user_rainloop_ab_contacts_index ON rainloop_ab_contacts (id_user);
|
||||
|
||||
CREATE TABLE rainloop_ab_properties (
|
||||
id_prop integer NOT NULL PRIMARY KEY,
|
||||
id_contact integer NOT NULL,
|
||||
id_user integer NOT NULL,
|
||||
prop_type integer NOT NULL,
|
||||
prop_type_custom text NOT NULL DEFAULT '',
|
||||
prop_value text NOT NULL DEFAULT '',
|
||||
prop_value_custom text NOT NULL DEFAULT '',
|
||||
prop_frec integer NOT NULL DEFAULT 0
|
||||
id_prop integer NOT NULL PRIMARY KEY,
|
||||
id_contact integer NOT NULL,
|
||||
id_user integer NOT NULL,
|
||||
prop_type integer NOT NULL,
|
||||
prop_type_str text NOT NULL DEFAULT '',
|
||||
prop_value text NOT NULL DEFAULT '',
|
||||
prop_value_custom text NOT NULL DEFAULT '',
|
||||
prop_frec integer NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX id_user_rainloop_ab_properties_index ON rainloop_ab_properties (id_user);
|
||||
CREATE INDEX id_user_id_contact_rainloop_ab_properties_index ON rainloop_ab_properties (id_user, id_contact);
|
||||
|
||||
CREATE TABLE rainloop_ab_tags (
|
||||
id_tag integer NOT NULL PRIMARY KEY,
|
||||
id_user integer NOT NULL,
|
||||
tag_name text NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX id_user_rainloop_ab_tags_index ON rainloop_ab_tags (id_user);
|
||||
CREATE INDEX id_user_name_rainloop_ab_tags_index ON rainloop_ab_tags (id_user, tag_name);
|
||||
|
||||
CREATE TABLE rainloop_ab_tags_contacts (
|
||||
id_tag integer NOT NULL,
|
||||
id_contact integer NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX id_tag_rainloop_ab_tags_index ON rainloop_ab_tags_contacts (id_tag);
|
||||
CREATE INDEX id_contact_rainloop_ab_tags_index ON rainloop_ab_tags_contacts (id_contact);
|
||||
|
||||
SQLITEINITIAL;
|
||||
break;
|
||||
}
|
||||
|
@ -974,22 +1383,32 @@ SQLITEINITIAL;
|
|||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Sync()
|
||||
public function SyncDatabase()
|
||||
{
|
||||
static $mCache = null;
|
||||
if (null !== $mCache)
|
||||
{
|
||||
return $mCache;
|
||||
}
|
||||
|
||||
$mCache = false;
|
||||
switch ($this->sDsnType)
|
||||
{
|
||||
case 'mysql':
|
||||
return $this->dataBaseUpgrade($this->sDsnType.'-ab-version', array(
|
||||
$mCache = $this->dataBaseUpgrade($this->sDsnType.'-ab-version', array(
|
||||
1 => $this->getInitialTablesArray($this->sDsnType)
|
||||
));
|
||||
break;
|
||||
case 'pgsql':
|
||||
return $this->dataBaseUpgrade($this->sDsnType.'-ab-version', array(
|
||||
$mCache = $this->dataBaseUpgrade($this->sDsnType.'-ab-version', array(
|
||||
1 => $this->getInitialTablesArray($this->sDsnType)
|
||||
));
|
||||
break;
|
||||
case 'sqlite':
|
||||
return $this->dataBaseUpgrade($this->sDsnType.'-ab-version', array(
|
||||
$mCache = $this->dataBaseUpgrade($this->sDsnType.'-ab-version', array(
|
||||
1 => $this->getInitialTablesArray($this->sDsnType)
|
||||
));
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -1004,14 +1423,11 @@ SQLITEINITIAL;
|
|||
{
|
||||
$aResult = array();
|
||||
|
||||
$sTypes = \implode(',', array(
|
||||
PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES
|
||||
));
|
||||
|
||||
$sSql = 'SELECT prop_value, prop_frec FROM rainloop_ab_properties WHERE id_user = :id_user AND id_contact = :id_contact AND prop_type IN ('.$sTypes.')';
|
||||
$sSql = 'SELECT prop_value, prop_frec FROM rainloop_ab_properties WHERE id_user = :id_user AND id_contact = :id_contact AND prop_type = :type';
|
||||
$aParams = array(
|
||||
':id_user' => array($iUserID, \PDO::PARAM_INT),
|
||||
':id_contact' => array($iIdContact, \PDO::PARAM_INT)
|
||||
':id_contact' => array($iIdContact, \PDO::PARAM_INT),
|
||||
':type' => array(PropertyType::EMAIl, \PDO::PARAM_INT)
|
||||
);
|
||||
|
||||
$oStmt = $this->prepareAndExecute($sSql, $aParams);
|
||||
|
|
|
@ -18,16 +18,33 @@ class Storage extends \RainLoop\Providers\AbstractProvider
|
|||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account|null $oAccount
|
||||
* @param \RainLoop\Account|string|null $oAccount
|
||||
* @param int $iStorageType
|
||||
* @param string $iStorageType
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function verifyAccount($oAccount, $iStorageType)
|
||||
{
|
||||
if (\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY !== $iStorageType &&
|
||||
!($oAccount instanceof \RainLoop\Account || \is_string($oAccount)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account|string|null $oAccount
|
||||
* @param int $iStorageType
|
||||
* @param string $sKey
|
||||
* @param string $sValue
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function Put($oAccount, $iStorageType, $sKey, $sValue)
|
||||
{
|
||||
if (\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY !== $iStorageType && !($oAccount instanceof \RainLoop\Account))
|
||||
if (!$this->verifyAccount($oAccount, $iStorageType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -36,7 +53,7 @@ class Storage extends \RainLoop\Providers\AbstractProvider
|
|||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account|null $oAccount
|
||||
* @param \RainLoop\Account|string|null $oAccount
|
||||
* @param int $iStorageType
|
||||
* @param string $sKey
|
||||
* @param mixed $mDefault = false
|
||||
|
@ -45,7 +62,7 @@ class Storage extends \RainLoop\Providers\AbstractProvider
|
|||
*/
|
||||
public function Get($oAccount, $iStorageType, $sKey, $mDefault = false)
|
||||
{
|
||||
if (\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY !== $iStorageType && !($oAccount instanceof \RainLoop\Account))
|
||||
if (!$this->verifyAccount($oAccount, $iStorageType))
|
||||
{
|
||||
return $mDefault;
|
||||
}
|
||||
|
@ -54,7 +71,7 @@ class Storage extends \RainLoop\Providers\AbstractProvider
|
|||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account|null $oAccount
|
||||
* @param \RainLoop\Account|string|null $oAccount
|
||||
* @param int $iStorageType
|
||||
* @param string $sKey
|
||||
*
|
||||
|
@ -62,7 +79,7 @@ class Storage extends \RainLoop\Providers\AbstractProvider
|
|||
*/
|
||||
public function Clear($oAccount, $iStorageType, $sKey)
|
||||
{
|
||||
if (\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY !== $iStorageType && !($oAccount instanceof \RainLoop\Account))
|
||||
if (!$this->verifyAccount($oAccount, $iStorageType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ class DefaultStorage implements \RainLoop\Providers\Storage\StorageInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account|null $oAccount
|
||||
* @param \RainLoop\Account|string|null $oAccount
|
||||
* @param int $iStorageType
|
||||
* @param string $sKey
|
||||
* @param string $sValue
|
||||
|
@ -34,7 +34,7 @@ class DefaultStorage implements \RainLoop\Providers\Storage\StorageInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account|null $oAccount
|
||||
* @param \RainLoop\Account|string|null $oAccount
|
||||
* @param int $iStorageType
|
||||
* @param string $sKey
|
||||
* @param mixed $mDefault = false
|
||||
|
@ -54,7 +54,7 @@ class DefaultStorage implements \RainLoop\Providers\Storage\StorageInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account|null $oAccount
|
||||
* @param \RainLoop\Account|string|null $oAccount
|
||||
* @param int $iStorageType
|
||||
* @param string $sKey
|
||||
*
|
||||
|
@ -73,22 +73,27 @@ class DefaultStorage implements \RainLoop\Providers\Storage\StorageInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account|null $oAccount
|
||||
* @param \RainLoop\Account|string|null $mAccount
|
||||
* @param int $iStorageType
|
||||
* @param string $sKey
|
||||
* @param bool $bMkDir = false
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function generateFileName($oAccount, $iStorageType, $sKey, $bMkDir = false)
|
||||
private function generateFileName($mAccount, $iStorageType, $sKey, $bMkDir = false)
|
||||
{
|
||||
if (!$oAccount)
|
||||
if (null === $mAccount)
|
||||
{
|
||||
$iStorageType = \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY;
|
||||
}
|
||||
|
||||
$sEmail = $oAccount ? \preg_replace('/[^a-z0-9\-\.@]+/', '_',
|
||||
('' === $oAccount->ParentEmail() ? '' : $oAccount->ParentEmail().'/').$oAccount->Email()) : '';
|
||||
$sEmail = $mAccount instanceof \RainLoop\Account ? \preg_replace('/[^a-z0-9\-\.@]+/', '_',
|
||||
('' === $mAccount->ParentEmail() ? '' : $mAccount->ParentEmail().'/').$mAccount->Email()) : '';
|
||||
|
||||
if (\is_string($mAccount) && empty($sEmail))
|
||||
{
|
||||
$sEmail = \preg_replace('/[^a-z0-9\-\.@]+/', '_', $mAccount);
|
||||
}
|
||||
|
||||
$sTypePath = $sKeyPath = '';
|
||||
switch ($iStorageType)
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace RainLoop\SabreDAV;
|
||||
|
||||
class AuthBasic extends \Sabre\DAV\Auth\Backend\AbstractBasic
|
||||
{
|
||||
/**
|
||||
* @var \RainLoop\Providers\PersonalAddressBook
|
||||
*/
|
||||
private $oPersonalAddressBook;
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Providers\PersonalAddressBook $oPersonalAddressBook
|
||||
*/
|
||||
public function __construct($oPersonalAddressBook)
|
||||
{
|
||||
$this->oPersonalAddressBook = $oPersonalAddressBook;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sUserName
|
||||
* @param string $sPassword
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function validateUserPass($sUserName, $sPassword)
|
||||
{
|
||||
$sHash = '';
|
||||
try
|
||||
{
|
||||
$sHash = $this->oPersonalAddressBook->GetUserHashByEmail($sUserName, true);
|
||||
}
|
||||
catch (Exception $oException) {}
|
||||
|
||||
// var_dump($sHash);
|
||||
// exit();
|
||||
|
||||
if (!empty($sHash) && $sPassword === $sHash)
|
||||
{
|
||||
$this->currentUser = $sUserName;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace RainLoop\SabreDAV;
|
||||
|
||||
class AuthDigest extends \Sabre\DAV\Auth\Backend\AbstractDigest
|
||||
{
|
||||
/**
|
||||
* @var \RainLoop\Providers\PersonalAddressBook
|
||||
*/
|
||||
private $oPersonalAddressBook;
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Providers\PersonalAddressBook $oPersonalAddressBook
|
||||
*/
|
||||
public function __construct($oPersonalAddressBook)
|
||||
{
|
||||
$this->oPersonalAddressBook = $oPersonalAddressBook;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sRealm
|
||||
* @param string $sUserName
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getDigestHash($sRealm, $sUserName)
|
||||
{
|
||||
$sHash = '';
|
||||
try
|
||||
{
|
||||
$sHash = $this->oPersonalAddressBook->GetUserHashByEmail($sUserName, true);
|
||||
}
|
||||
catch (Exception $oException) {}
|
||||
|
||||
// var_dump($sHash);
|
||||
// exit();
|
||||
|
||||
if (!empty($sHash))
|
||||
{
|
||||
$this->currentUser = $sUserName;
|
||||
return \md5($sUserName.':'.$sRealm.':'.$sHash);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,421 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace RainLoop\SabreDAV;
|
||||
|
||||
class CardDAV implements \Sabre\CardDAV\Backend\BackendInterface
|
||||
{
|
||||
/**
|
||||
* @var \RainLoop\Providers\PersonalAddressBook
|
||||
*/
|
||||
private $oPersonalAddressBook;
|
||||
|
||||
/**
|
||||
* @var \RainLoop\SabreDAV\AuthBasic
|
||||
*/
|
||||
private $oAuthBackend;
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Providers\PersonalAddressBook $oPersonalAddressBook
|
||||
* @param \RainLoop\SabreDAV\AuthBasic $oAuthBackend
|
||||
*/
|
||||
public function __construct($oPersonalAddressBook, &$oAuthBackend)
|
||||
{
|
||||
$this->oPersonalAddressBook = $oPersonalAddressBook;
|
||||
$this->oPersonalAddressBook->ConsiderShare(false);
|
||||
$this->oAuthBackend = $oAuthBackend;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $mData
|
||||
*/
|
||||
private function writeLog($mData)
|
||||
{
|
||||
$this->oPersonalAddressBook->Logger()->WriteMixed($mData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sPrincipalUri
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getEmailFromPrincipalUri($sPrincipalUri)
|
||||
{
|
||||
$sEmail = '';
|
||||
$aMatch = array();
|
||||
if (\preg_match('/\/?principals\/([^@\/]+@[^@\/]+)/i', $sPrincipalUri, $aMatch) && !empty($aMatch[1]))
|
||||
{
|
||||
$sEmail = \trim($aMatch[1]);
|
||||
}
|
||||
|
||||
return $sEmail;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sPrincipalUri = ''
|
||||
* @param string $mAddressBookID = ''
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getAuthEmail($sPrincipalUri = '', $mAddressBookID = '')
|
||||
{
|
||||
$sGetCurrentUser = \trim($this->oAuthBackend->getCurrentUser());
|
||||
if (0 < \strlen($sPrincipalUri) && 0 < \strlen($sGetCurrentUser) &&
|
||||
$sGetCurrentUser !== $this->getEmailFromPrincipalUri($sPrincipalUri))
|
||||
{
|
||||
$sGetCurrentUser = '';
|
||||
}
|
||||
|
||||
if (0 < \strlen((string) $mAddressBookID) && 0 < \strlen($sGetCurrentUser) &&
|
||||
(string) $mAddressBookID !== (string) $this->oPersonalAddressBook->GetUserUidByEmail($sGetCurrentUser))
|
||||
{
|
||||
$sGetCurrentUser = '';
|
||||
}
|
||||
|
||||
return $sGetCurrentUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of addressbooks for a specific user.
|
||||
*
|
||||
* @param string $sPrincipalUri
|
||||
* @return array
|
||||
*/
|
||||
public function getAddressBooksForUser($sPrincipalUri)
|
||||
{
|
||||
$this->writeLog('::getAddressBooksForUser('.$sPrincipalUri.')');
|
||||
|
||||
$aAddressBooks = array();
|
||||
|
||||
$sEmail = $this->getAuthEmail($sPrincipalUri);
|
||||
if (0 < strlen($sEmail))
|
||||
{
|
||||
$mAddressBookID = $this->oPersonalAddressBook->GetUserUidByEmail($sEmail);
|
||||
if (!empty($mAddressBookID))
|
||||
{
|
||||
$aAddressBooks[] = array(
|
||||
'id' => $mAddressBookID,
|
||||
'uri' => 'default',
|
||||
'principaluri' => $sPrincipalUri,
|
||||
'{DAV:}displayname' => 'Personal Address Book',
|
||||
'{'.\Sabre\CardDAV\Plugin::NS_CARDDAV.'}addressbook-description' => 'Personal Address Book',
|
||||
'{http://calendarserver.org/ns/}getctag' => $this->oPersonalAddressBook->GetCtagByEmail($sEmail),
|
||||
'{'.\Sabre\CardDAV\Plugin::NS_CARDDAV.'}supported-address-data' => new \Sabre\CardDAV\Property\SupportedAddressData()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $aAddressBooks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an addressbook's properties
|
||||
*
|
||||
* See Sabre\DAV\IProperties for a description of the mutations array, as
|
||||
* well as the return value.
|
||||
*
|
||||
* @param mixed $mAddressBookID
|
||||
* @param array $aMutations
|
||||
* @see Sabre\DAV\IProperties::updateProperties
|
||||
* @return bool|array
|
||||
*/
|
||||
public function updateAddressBook($mAddressBookID, array $aMutations)
|
||||
{
|
||||
$this->writeLog('::updateAddressBook('.$mAddressBookID.', array $aMutations['.\count($aMutations).'])');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new address book
|
||||
*
|
||||
* @param string $sPrincipalUri
|
||||
* @param string $sUrl Just the 'basename' of the url.
|
||||
* @param array $aProperties
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function createAddressBook($sPrincipalUri, $sUrl, array $aProperties)
|
||||
{
|
||||
$this->writeLog('::createAddressBook('.$sPrincipalUri.', '.$sUrl.', array $aProperties['.\count($aProperties).'])');
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an entire addressbook and all its contents
|
||||
*
|
||||
* @param mixed $mAddressBookID
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deleteAddressBook($mAddressBookID)
|
||||
{
|
||||
$this->writeLog('::deleteAddressBook('.$mAddressBookID.')');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all cards for a specific addressbook id.
|
||||
*
|
||||
* This method should return the following properties for each card:
|
||||
* * carddata - raw vcard data
|
||||
* * uri - Some unique url
|
||||
* * lastmodified - A unix timestamp
|
||||
*
|
||||
* It's recommended to also return the following properties:
|
||||
* * etag - A unique etag. This must change every time the card changes.
|
||||
* * size - The size of the card in bytes.
|
||||
*
|
||||
* If these last two properties are provided, less time will be spent
|
||||
* calculating them. If they are specified, you can also ommit carddata.
|
||||
* This may speed up certain requests, especially with large cards.
|
||||
*
|
||||
* @param mixed $mAddressBookID
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCards($mAddressBookID)
|
||||
{
|
||||
$this->writeLog('::getCards('.$mAddressBookID.')');
|
||||
|
||||
$aResult = array();
|
||||
if (!empty($mAddressBookID))
|
||||
{
|
||||
$sEmail = $this->getAuthEmail('', $mAddressBookID);
|
||||
if (!empty($sEmail))
|
||||
{
|
||||
$aList = $this->oPersonalAddressBook->GetContacts($sEmail, 0, 5000);
|
||||
foreach ($aList as /* @var $oItem \RainLoop\Providers\PersonalAddressBook\Classes\Contact */ $oItem)
|
||||
{
|
||||
if (!$oItem->ReadOnly)
|
||||
{
|
||||
$aResult[] = array(
|
||||
'uri' => $oItem->VCardUri(),
|
||||
'lastmodified' => $oItem->Changed,
|
||||
'etag' => $oItem->CardDavHash,
|
||||
'size' => $oItem->CardDavSize
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specfic card.
|
||||
*
|
||||
* The same set of properties must be returned as with getCards. The only
|
||||
* exception is that 'carddata' is absolutely required.
|
||||
*
|
||||
* @param mixed $mAddressBookID
|
||||
* @param string $sCardUri
|
||||
* @return array
|
||||
*/
|
||||
public function getCard($mAddressBookID, $sCardUri)
|
||||
{
|
||||
$this->writeLog('::getCard('.$mAddressBookID.', '.$sCardUri.')');
|
||||
|
||||
$mResult = false;
|
||||
|
||||
$oContact = null;
|
||||
if (!empty($mAddressBookID) && !empty($sCardUri) && '.vcf' === \substr($sCardUri, -4))
|
||||
{
|
||||
$sEmail = $this->getAuthEmail('', $mAddressBookID);
|
||||
if (!empty($sEmail))
|
||||
{
|
||||
$oContact = $this->oPersonalAddressBook->GetContactByID($sEmail, \substr($sCardUri, 0, -4), true);
|
||||
}
|
||||
}
|
||||
|
||||
if ($oContact)
|
||||
{
|
||||
$mResult = array(
|
||||
'uri' => $oContact->VCardUri(),
|
||||
'lastmodified' => $oContact->Changed,
|
||||
'etag' => $oContact->CardDavHash,
|
||||
'size' => $oContact->CardDavSize,
|
||||
'carddata' => $oContact->CardDavData
|
||||
);
|
||||
}
|
||||
|
||||
return $mResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new card.
|
||||
*
|
||||
* The addressbook id will be passed as the first argument. This is the
|
||||
* same id as it is returned from the getAddressbooksForUser method.
|
||||
*
|
||||
* The cardUri is a base uri, and doesn't include the full path. The
|
||||
* cardData argument is the vcard body, and is passed as a string.
|
||||
*
|
||||
* It is possible to return an ETag from this method. This ETag is for the
|
||||
* newly created resource, and must be enclosed with double quotes (that
|
||||
* is, the string itself must contain the double quotes).
|
||||
*
|
||||
* You should only return the ETag if you store the carddata as-is. If a
|
||||
* subsequent GET request on the same card does not have the same body,
|
||||
* byte-by-byte and you did return an ETag here, clients tend to get
|
||||
* confused.
|
||||
*
|
||||
* If you don't return an ETag, you can just return null.
|
||||
*
|
||||
* @param mixed $mAddressBookID
|
||||
* @param string $sCardUri
|
||||
* @param string $sCardData
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function createCard($mAddressBookID, $sCardUri, $sCardData)
|
||||
{
|
||||
$this->writeLog('::createCard('.$mAddressBookID.', '.$sCardUri.', $sCardData)');
|
||||
$this->writeLog($sCardData);
|
||||
|
||||
$oVCard = null;
|
||||
if (!empty($mAddressBookID) && !empty($sCardUri) && '.vcf' === \substr($sCardUri, -4) && 0 < \strlen($sCardData))
|
||||
{
|
||||
try
|
||||
{
|
||||
$oVCard = \Sabre\VObject\Reader::read($sCardData);
|
||||
}
|
||||
catch (\Exception $oException)
|
||||
{
|
||||
$this->writeLog($oException);
|
||||
}
|
||||
|
||||
if ($oVCard)
|
||||
{
|
||||
$sEmail = $this->getAuthEmail('', $mAddressBookID);
|
||||
if (!empty($sEmail))
|
||||
{
|
||||
if (empty($oVCard->UID))
|
||||
{
|
||||
$oVCard->UID = \Sabre\DAV\UUIDUtil::getUUID();
|
||||
$sCardData = $oVCard->serialize();
|
||||
}
|
||||
|
||||
$oContact = new \RainLoop\Providers\PersonalAddressBook\Classes\Contact();
|
||||
$oContact->ParseVCard($oVCard, $sCardData);
|
||||
|
||||
$this->oPersonalAddressBook->ContactSave($sEmail, $oContact);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a card.
|
||||
*
|
||||
* The addressbook id will be passed as the first argument. This is the
|
||||
* same id as it is returned from the getAddressbooksForUser method.
|
||||
*
|
||||
* The cardUri is a base uri, and doesn't include the full path. The
|
||||
* cardData argument is the vcard body, and is passed as a string.
|
||||
*
|
||||
* It is possible to return an ETag from this method. This ETag should
|
||||
* match that of the updated resource, and must be enclosed with double
|
||||
* quotes (that is: the string itself must contain the actual quotes).
|
||||
*
|
||||
* You should only return the ETag if you store the carddata as-is. If a
|
||||
* subsequent GET request on the same card does not have the same body,
|
||||
* byte-by-byte and you did return an ETag here, clients tend to get
|
||||
* confused.
|
||||
*
|
||||
* If you don't return an ETag, you can just return null.
|
||||
*
|
||||
* @param mixed $mAddressBookID
|
||||
* @param string $sCardUri
|
||||
* @param string $sCardData
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function updateCard($mAddressBookID, $sCardUri, $sCardData)
|
||||
{
|
||||
$this->writeLog('::updateCard('.$mAddressBookID.', '.$sCardUri.', $sCardData)');
|
||||
$this->writeLog($sCardData);
|
||||
|
||||
if (!empty($mAddressBookID) && !empty($sCardUri) && '.vcf' === \substr($sCardUri, -4) && 0 < \strlen($sCardData))
|
||||
{
|
||||
try
|
||||
{
|
||||
$oVCard = \Sabre\VObject\Reader::read($sCardData);
|
||||
}
|
||||
catch (\Exception $oException)
|
||||
{
|
||||
$this->writeLog($oException);
|
||||
}
|
||||
|
||||
if ($oVCard)
|
||||
{
|
||||
$sEmail = $this->getAuthEmail('', $mAddressBookID);
|
||||
if (!empty($sEmail))
|
||||
{
|
||||
$iRev = 0;
|
||||
$aMatch = array();
|
||||
if (!empty($oVCard->REV) && \preg_match('/(20[0-9][0-9])([0-1][0-9])([0-3][0-9])T([0-2][0-9])([0-5][0-9])([0-5][0-9])Z/i', $oVCard->REV, $aMatch))
|
||||
{// 1Y 2m 3d 4H 5i 6s
|
||||
$iRev = \gmmktime($aMatch[4], $aMatch[5], $aMatch[6], $aMatch[2], $aMatch[3], $aMatch[1]);
|
||||
}
|
||||
|
||||
$oContact = $this->oPersonalAddressBook->GetContactByID($sEmail, \substr($sCardUri, 0, -4), true);
|
||||
if ($oContact && (0 === $iRev || $oContact->Changed < $iRev))
|
||||
{
|
||||
if (empty($oVCard->UID))
|
||||
{
|
||||
$oVCard->UID = \Sabre\DAV\UUIDUtil::getUUID();
|
||||
$sCardData = $oVCard->serialize();
|
||||
}
|
||||
|
||||
$oContact->ParseVCard($oVCard, $sCardData);
|
||||
if ($this->oPersonalAddressBook->ContactSave($sEmail, $oContact) && !empty($oContact->CardDavHash))
|
||||
{
|
||||
return '"'.$oContact->CardDavHash.'"';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($oContact && $oContact->Changed < $iRev)
|
||||
{
|
||||
$this->writeLog('Obsolete revision: ['.(empty($oVCard->REV) ? '' : $oVCard->REV).', '.$oContact->Changed.', '.$iRev.']');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a card
|
||||
*
|
||||
* @param mixed $mAddressBookID
|
||||
* @param string $sCardUri
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteCard($mAddressBookID, $sCardUri)
|
||||
{
|
||||
$this->writeLog('::deleteCard('.$mAddressBookID.', '.$sCardUri.')');
|
||||
|
||||
$bResult = false;
|
||||
$oContact = null;
|
||||
if (!empty($mAddressBookID) && !empty($sCardUri) && '.vcf' === \substr($sCardUri, -4))
|
||||
{
|
||||
$sEmail = $this->getAuthEmail('', $mAddressBookID);
|
||||
if (!empty($sEmail))
|
||||
{
|
||||
$oContact = $this->oPersonalAddressBook->GetContactByID($sEmail, \substr($sCardUri, 0, -4), true);
|
||||
}
|
||||
}
|
||||
|
||||
if ($oContact)
|
||||
{
|
||||
$bResult = $this->oPersonalAddressBook->DeleteContacts($sEmail, array($oContact->IdContact));
|
||||
}
|
||||
|
||||
return $bResult;
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace RainLoop\SabreDAV;
|
||||
|
||||
class Logger extends \Sabre\DAV\ServerPlugin
|
||||
{
|
||||
/**
|
||||
* @var \MailSo\Log\Logger
|
||||
*/
|
||||
private $oLogger;
|
||||
|
||||
/**
|
||||
* @param \MailSo\Log\Logger $oLogger
|
||||
*/
|
||||
public function __construct($oLogger)
|
||||
{
|
||||
$this->oLogger = null;
|
||||
if ($oLogger instanceof \MailSo\Log\Logger)
|
||||
{
|
||||
$this->oLogger = $oLogger;
|
||||
}
|
||||
}
|
||||
|
||||
public function initialize(\Sabre\DAV\Server $server)
|
||||
{
|
||||
$this->server = $server;
|
||||
$this->server->subscribeEvent('beforeMethod', array($this, 'beforeMethod'), 30);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a plugin name.
|
||||
*
|
||||
* Using this name other plugins will be able to access other plugins
|
||||
* using \Sabre\DAV\Server::getPlugin
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPluginName()
|
||||
{
|
||||
return 'logger';
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called before any HTTP method, but after authentication.
|
||||
*
|
||||
* @param string $sMethod
|
||||
* @param string $sPath
|
||||
* @throws \Sabre\DAV\Exception\NotAuthenticated
|
||||
* @return bool
|
||||
*/
|
||||
public function beforeMethod($sMethod, $sPath)
|
||||
{
|
||||
if ($this->oLogger)
|
||||
{
|
||||
if (true)
|
||||
{
|
||||
$body = $this->server->httpRequest->getBody(true);
|
||||
$this->server->httpRequest->setBody($body);
|
||||
$this->oLogger->Write($body, \MailSo\Log\Enumerations\Type::INFO, 'DAV');
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,205 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace RainLoop\SabreDAV;
|
||||
|
||||
class Principal extends \Sabre\DAVACL\PrincipalBackend\AbstractBackend
|
||||
{
|
||||
/**
|
||||
* @var \RainLoop\Providers\PersonalAddressBook
|
||||
*/
|
||||
private $oPersonalAddressBook;
|
||||
|
||||
/**
|
||||
* @var \RainLoop\SabreDAV\AuthBasic
|
||||
*/
|
||||
private $oAuthBackend;
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Providers\PersonalAddressBook $oPersonalAddressBook
|
||||
* @param \RainLoop\SabreDAV\AuthBasic $oAuthBackend
|
||||
*/
|
||||
public function __construct($oPersonalAddressBook, &$oAuthBackend)
|
||||
{
|
||||
$this->oPersonalAddressBook = $oPersonalAddressBook;
|
||||
$this->oAuthBackend = $oAuthBackend;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of principals based on a prefix.
|
||||
*
|
||||
* This prefix will often contain something like 'principals'. You are only
|
||||
* expected to return principals that are in this base path.
|
||||
*
|
||||
* You are expected to return at least a 'uri' for every user, you can
|
||||
* return any additional properties if you wish so. Common properties are:
|
||||
* {DAV:}displayname
|
||||
* {http://sabredav.org/ns}email-address - This is a custom SabreDAV
|
||||
* field that's actually injected in a number of other properties. If
|
||||
* you have an email address, use this property.
|
||||
*
|
||||
* @param string $prefixPath
|
||||
* @return array
|
||||
*/
|
||||
function getPrincipalsByPrefix($prefixPath)
|
||||
{
|
||||
$aResult = array();
|
||||
if (\preg_match('/^principals/', $prefixPath))
|
||||
{
|
||||
$sGetCurrentUser = $this->oAuthBackend->getCurrentUser();
|
||||
if (!empty($sGetCurrentUser))
|
||||
{
|
||||
$aResult[] = array(
|
||||
'uri' => 'principals/'.$sGetCurrentUser,
|
||||
'{DAV:}displayname' => $sGetCurrentUser,
|
||||
'{http://sabredav.org/ns}email-address' => $sGetCurrentUser
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specific principal, specified by it's path.
|
||||
* The returned structure should be the exact same as from
|
||||
* getPrincipalsByPrefix.
|
||||
*
|
||||
* @param string $sPath
|
||||
* @return array
|
||||
*/
|
||||
function getPrincipalByPath($sPath)
|
||||
{
|
||||
$sGetCurrentUser = $this->oAuthBackend->getCurrentUser();
|
||||
if ('principals/'.$sGetCurrentUser === $sPath)
|
||||
{
|
||||
return array(
|
||||
'uri' => 'principals/'.$sGetCurrentUser,
|
||||
'{DAV:}displayname' => $sGetCurrentUser,
|
||||
'{http://sabredav.org/ns}email-address' => $sGetCurrentUser
|
||||
);
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates one ore more webdav properties on a principal.
|
||||
*
|
||||
* The list of mutations is supplied as an array. Each key in the array is
|
||||
* a propertyname, such as {DAV:}displayname.
|
||||
*
|
||||
* Each value is the actual value to be updated. If a value is null, it
|
||||
* must be deleted.
|
||||
*
|
||||
* This method should be atomic. It must either completely succeed, or
|
||||
* completely fail. Success and failure can simply be returned as 'true' or
|
||||
* 'false'.
|
||||
*
|
||||
* It is also possible to return detailed failure information. In that case
|
||||
* an array such as this should be returned:
|
||||
*
|
||||
* array(
|
||||
* 200 => array(
|
||||
* '{DAV:}prop1' => null,
|
||||
* ),
|
||||
* 201 => array(
|
||||
* '{DAV:}prop2' => null,
|
||||
* ),
|
||||
* 403 => array(
|
||||
* '{DAV:}prop3' => null,
|
||||
* ),
|
||||
* 424 => array(
|
||||
* '{DAV:}prop4' => null,
|
||||
* ),
|
||||
* );
|
||||
*
|
||||
* In this previous example prop1 was successfully updated or deleted, and
|
||||
* prop2 was succesfully created.
|
||||
*
|
||||
* prop3 failed to update due to '403 Forbidden' and because of this prop4
|
||||
* also could not be updated with '424 Failed dependency'.
|
||||
*
|
||||
* This last example was actually incorrect. While 200 and 201 could appear
|
||||
* in 1 response, if there's any error (403) the other properties should
|
||||
* always fail with 423 (failed dependency).
|
||||
*
|
||||
* But anyway, if you don't want to scratch your head over this, just
|
||||
* return true or false.
|
||||
*
|
||||
* @param string $path
|
||||
* @param array $mutations
|
||||
* @return array|bool
|
||||
*/
|
||||
function updatePrincipal($path, $mutations)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to search for principals matching a set of
|
||||
* properties.
|
||||
*
|
||||
* This search is specifically used by RFC3744's principal-property-search
|
||||
* REPORT. You should at least allow searching on
|
||||
* http://sabredav.org/ns}email-address.
|
||||
*
|
||||
* The actual search should be a unicode-non-case-sensitive search. The
|
||||
* keys in searchProperties are the WebDAV property names, while the values
|
||||
* are the property values to search on.
|
||||
*
|
||||
* If multiple properties are being searched on, the search should be
|
||||
* AND'ed.
|
||||
*
|
||||
* This method should simply return an array with full principal uri's.
|
||||
*
|
||||
* If somebody attempted to search on a property the backend does not
|
||||
* support, you should simply return 0 results.
|
||||
*
|
||||
* You can also just return 0 results if you choose to not support
|
||||
* searching at all, but keep in mind that this may stop certain features
|
||||
* from working.
|
||||
*
|
||||
* @param string $prefixPath
|
||||
* @param array $searchProperties
|
||||
* @return array
|
||||
*/
|
||||
function searchPrincipals($prefixPath, array $searchProperties)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of members for a group-principal
|
||||
*
|
||||
* @param string $principal
|
||||
* @return array
|
||||
*/
|
||||
function getGroupMemberSet($principal)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of groups a principal is a member of
|
||||
*
|
||||
* @param string $principal
|
||||
* @return array
|
||||
*/
|
||||
function getGroupMembership($principal)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the list of group members for a group principal.
|
||||
*
|
||||
* The principals should be passed as a list of uri's.
|
||||
*
|
||||
* @param string $principal
|
||||
* @param array $members
|
||||
* @return void
|
||||
*/
|
||||
function setGroupMemberSet($principal, array $members)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -108,29 +108,14 @@ class Service
|
|||
|
||||
$bCached = false;
|
||||
$sResult = '';
|
||||
$sPathInfo = \trim(\trim($this->oHttp->GetServer('PATH_INFO', '')), ' /');
|
||||
if (!empty($sPathInfo))
|
||||
{
|
||||
if ('dav' !== \substr($sPathInfo, 0, 3))
|
||||
{
|
||||
$sPathInfo = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($sPathInfo))
|
||||
$sQuery = \trim(\trim($this->oHttp->GetServer('QUERY_STRING', '')), ' /');
|
||||
$iPos = \strpos($sQuery, '&');
|
||||
if (0 < $iPos)
|
||||
{
|
||||
$sQuery = \trim(\trim($this->oHttp->GetServer('QUERY_STRING', '')), ' /');
|
||||
$iPos = \strpos($sQuery, '&');
|
||||
if (0 < $iPos)
|
||||
{
|
||||
$sQuery = \substr($sQuery, 0, $iPos);
|
||||
}
|
||||
$sQuery = \substr($sQuery, 0, $iPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sQuery = $sPathInfo;
|
||||
}
|
||||
|
||||
|
||||
$this->oActions->Plugins()->RunHook('filter.http-query', array(&$sQuery));
|
||||
$aPaths = \explode('/', $sQuery);
|
||||
$this->oActions->Plugins()->RunHook('filter.http-paths', array(&$aPaths));
|
||||
|
|
|
@ -719,85 +719,6 @@ class ServiceActions
|
|||
));
|
||||
}
|
||||
|
||||
public function HostDav()
|
||||
{
|
||||
try
|
||||
{
|
||||
\set_error_handler(function ($errno, $errstr, $errfile, $errline ) {
|
||||
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
|
||||
});
|
||||
|
||||
$oPersonalAddressBookProvider = $this->oActions->PersonalAddressBookProvider();
|
||||
|
||||
$oAuthBackend = null;
|
||||
if ($this->Config()->Get('labs', 'sync_dav_digest_auth', false))
|
||||
{
|
||||
$oAuthBackend = new \RainLoop\SabreDAV\AuthDigest($oPersonalAddressBookProvider);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oAuthBackend = new \RainLoop\SabreDAV\AuthBasic($oPersonalAddressBookProvider);
|
||||
}
|
||||
|
||||
$oCarddavBackend = new \RainLoop\SabreDAV\CardDAV($oPersonalAddressBookProvider, $oAuthBackend);
|
||||
$oPrincipalBackend = new \RainLoop\SabreDAV\Principal($oPersonalAddressBookProvider, $oAuthBackend);
|
||||
|
||||
$oPrincipalCollection = new \Sabre\DAVACL\PrincipalCollection($oPrincipalBackend);
|
||||
$oPrincipalCollection->disableListing = true;
|
||||
|
||||
$oAddressBookRoot = new \Sabre\CardDAV\AddressBookRoot($oPrincipalBackend, $oCarddavBackend);
|
||||
|
||||
$aTree = array($oPrincipalCollection, $oAddressBookRoot);
|
||||
$this->Plugins()->RunHook('filter.sabre-dav-tree', array(&$aTree));
|
||||
|
||||
$oServer = new \Sabre\DAV\Server($aTree);
|
||||
|
||||
$sBaseUri = '/';
|
||||
if (false !== \strpos($this->oHttp->GetUrl(), '/index.php/dav/'))
|
||||
{
|
||||
$aPath = \trim($this->oHttp->GetPath(), '/\\ ');
|
||||
$sBaseUri = (0 < \strlen($aPath) ? '/'.$aPath : '').'/index.php/dav/';
|
||||
}
|
||||
|
||||
$this->Plugins()->RunHook('filter.sabre-dav-base-url', array(&$sBaseUri));
|
||||
|
||||
$oServer->setBaseUri($sBaseUri);
|
||||
|
||||
// Plugins
|
||||
$oServer->addPlugin(new \Sabre\DAV\Auth\Plugin($oAuthBackend, 'RainLoop'));
|
||||
$oServer->addPlugin(new \Sabre\CardDAV\Plugin());
|
||||
$oServer->addPlugin(new \Sabre\DAVACL\Plugin());
|
||||
$oServer->addPlugin(new \Sabre\CardDAV\VCFExportPlugin());
|
||||
$oServer->addPlugin(new \RainLoop\SabreDAV\Logger($this->Logger()));
|
||||
|
||||
if ($this->Config()->Get('labs', 'sync_use_dav_browser', false))
|
||||
{
|
||||
$oServer->addPlugin(new \Sabre\DAV\Browser\Plugin());
|
||||
}
|
||||
|
||||
$this->Plugins()->RunHook('filter.sabre-dav-before-exec', array(&$oServer));
|
||||
|
||||
$oServer->exec();
|
||||
}
|
||||
catch (\Exception $oException)
|
||||
{
|
||||
$this->Logger()->WriteException($oException);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function ServiceDav()
|
||||
{
|
||||
if ($this->oActions->Config()->Get('contacts', 'allow_sync', false))
|
||||
{
|
||||
$this->HostDav();
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
|
|
|
@ -315,6 +315,7 @@ class Client {
|
|||
// Return headers as part of the response
|
||||
CURLOPT_HEADER => true,
|
||||
CURLOPT_POSTFIELDS => $body,
|
||||
CURLOPT_USERAGENT => 'RainLoop DAV Client',
|
||||
// Automatically follow redirects
|
||||
CURLOPT_FOLLOWLOCATION => true,
|
||||
CURLOPT_MAXREDIRS => 5,
|
||||
|
|
|
@ -18,19 +18,21 @@
|
|||
<i data-bind="css: enableContacts() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
|
||||
Enable contacts
|
||||
</label>
|
||||
<label data-bind="click: function () { contactsSharing(!contactsSharing()); }">
|
||||
<!-- <label data-bind="click: function () { contactsSharing(!contactsSharing()); }">
|
||||
<i data-bind="css: contactsSharing() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
|
||||
Allow contacts sharing
|
||||
</label>
|
||||
<br />
|
||||
Allow contacts sharing (disabled)
|
||||
</label>-->
|
||||
<label data-bind="click: function () { contactsSync(!contactsSync()); }">
|
||||
<i data-bind="css: contactsSync() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
|
||||
Allow contacts sync server (CardDAV)
|
||||
Allow contacts sync (with external CardDAV server)
|
||||
</label>
|
||||
<a href="http://rainloop.net/docs/web-servers/" target="_blank">Web server configuration examples</a>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
</div>
|
||||
<div class="form-horizontal" data-bind="visible: contactsSupported">
|
||||
<div class="legend">
|
||||
Storage (PDO)
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label">
|
||||
Type
|
||||
|
@ -41,10 +43,8 @@
|
|||
<div data-bind="saveTrigger: contactsTypeTrigger"></div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div data-bind="visible: 'sqlite' !== contactsType()">
|
||||
<div class="legend">
|
||||
PDO (MySQL / PostgreSQL)
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label">
|
||||
Dsn
|
||||
|
@ -90,15 +90,12 @@
|
|||
</div>
|
||||
</div>
|
||||
<div data-bind="visible: 'sqlite' === contactsType()">
|
||||
<div class="legend">
|
||||
PDO (SQLite)
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<div class="alert alert-null-left-margin span8">
|
||||
<h4>Notice!</h4>
|
||||
<br />
|
||||
Don't use this type of database with a large number of active users.
|
||||
Don't use this database type with a large number of active users.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
</a>
|
||||
<a class="btn btn-dark-disabled-border button-delete" data-tooltip-placement="bottom" data-bind="command: deleteCommand, tooltip: 'MESSAGE_LIST/BUTTON_DELETE'">
|
||||
<i class="icon-trash"></i>
|
||||
<span data-bind="text: printableMessageCountForDeletion()"></span>
|
||||
<!--<span data-bind="text: printableMessageCountForDeletion()"></span>-->
|
||||
</a>
|
||||
</div>
|
||||
<div class="btn-group"> </div>
|
||||
|
|
|
@ -75,10 +75,10 @@
|
|||
|
||||
<span class="i18n" data-i18n-text="SEARCH/LABEL_ADV_FLAGGED"></span>
|
||||
</label>
|
||||
<label data-bind="click: function () { hasAttachments(!hasAttachments()); }">
|
||||
<i data-bind="css: hasAttachments() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
|
||||
<label data-bind="click: function () { hasAttachment(!hasAttachment()); }">
|
||||
<i data-bind="css: hasAttachment() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
|
||||
|
||||
<span class="i18n" data-i18n-text="SEARCH/LABEL_ADV_HAS_ATTACHMENTS"></span>
|
||||
<span class="i18n" data-i18n-text="SEARCH/LABEL_ADV_HAS_ATTACHMENT"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div class="modal-header b-header-toolbar g-ui-user-select-none">
|
||||
<button type="button" class="close" data-bind="command: cancelCommand">×</button>
|
||||
<a class="btn btn-large button-send" data-bind="command: sendCommand, css: {'btn-danger': sendError, 'btn-warning': sendSuccessButSaveError }">
|
||||
<i data-bind="css: {'icon-rocket': !sending(), 'icon-spinner animated': sending(), 'icon-white': sendError() || sendSuccessButSaveError()}"></i>
|
||||
<i data-bind="css: {'icon-paper-plane': !sending(), 'icon-spinner animated': sending(), 'icon-white': sendError() || sendSuccessButSaveError()}"></i>
|
||||
|
||||
<span class="i18n" data-i18n-text="COMPOSE/BUTTON_SEND"></span>
|
||||
</a>
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
|
||||
<div class="btn-group">
|
||||
<a class="btn dropdown-toggle buttonMore" data-toggle="dropdown">
|
||||
<i data-bind="css: {'icon-list': !contacts.importing(), 'icon-spinner animated': contacts.importing()}"></i>
|
||||
<i data-bind="css: {'icon-list': !contacts.importing() && !contacts.syncing(),
|
||||
'icon-spinner animated': contacts.importing() || contacts.syncing()}"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu g-ui-menu" role="menu">
|
||||
<li class="e-item">
|
||||
|
@ -24,6 +25,13 @@
|
|||
<span class="i18n" data-i18n-text="CONTACTS/BUTTON_IMPORT"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="e-item" data-bind="visible: enableContactsSync">
|
||||
<a class="e-link" data-bind="command: syncCommand">
|
||||
<i class="icon-sync"></i>
|
||||
|
||||
<span class="i18n" data-i18n-text="CONTACTS/BUTTON_SYNC"></span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
@ -147,32 +155,6 @@
|
|||
<i class="icon-lock iconsize24" data-tooltip-placement="left" data-bind="tooltip: 'CONTACTS/LABEL_READ_ONLY'"></i>
|
||||
</div>
|
||||
|
||||
<div class="e-share-sign" data-bind="visible: contactsSharingIsAllowed">
|
||||
<div class="btn-group pull-right">
|
||||
<a class="btn dropdown-toggle" data-tooltip-placement="left" data-toggle="dropdown" data-bind="tooltip: 'CONTACTS/LABEL_SHARE'">
|
||||
<i data-bind="css: shareIcon"></i>
|
||||
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu g-ui-menu" role="menu">
|
||||
<li class="e-item" data-bind="css: {'selected': shareToNone}">
|
||||
<a class="e-link" data-bind="click: setShareToNone">
|
||||
<i class="icon-none"></i>
|
||||
|
||||
<span class="i18n" data-i18n-text="CONTACTS/BUTTON_SHARE_NONE"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="e-item" data-bind="css: {'selected': shareToAll}">
|
||||
<a class="e-link" data-bind="click: setShareToAll">
|
||||
<i class="icon-earth"></i>
|
||||
|
||||
<span class="i18n" data-i18n-text="CONTACTS/BUTTON_SHARE_ALL"></span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn button-save-contact" data-bind="command: saveCommand, css: {'dirty': watchDirty}">
|
||||
<i data-bind="css: {'icon-ok': !viewSaving(), 'icon-spinner animated': viewSaving()}"></i>
|
||||
|
||||
|
|
|
@ -13,53 +13,52 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div class="form-horizontal" data-bind="visible: allowContactsSync">
|
||||
<div class="legend">
|
||||
<span class="i18n" data-i18n-text="SETTINGS_CONTACTS/LEGEND_MOBILE_SYNC"></span>
|
||||
<span class="i18n" data-i18n-text="SETTINGS_CONTACTS/LEGEND_CONTACTS_SYNC"></span>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" style="padding-top: 0;">
|
||||
<span class="i18n" data-i18n-text="SETTINGS_CONTACTS/LABEL_SYNC_SERVER"></span>
|
||||
<div class="controls">
|
||||
<label data-bind="click: function () { enableContactsSync(!enableContactsSync()); }">
|
||||
<i data-bind="css: enableContactsSync() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
|
||||
|
||||
<span class="i18n" data-i18n-text="SETTINGS_CONTACTS/LABEL_CONTACTS_SYNC_ENABLE"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="control-group">
|
||||
<label class="control-label">
|
||||
<span class="i18n" data-i18n-text="SETTINGS_CONTACTS/LABEL_CONTACTS_SYNC_SERVER"></span>
|
||||
</label>
|
||||
<div class="controls">
|
||||
<strong data-bind="text: contactsSyncServer"></strong>
|
||||
<input type="text" data-bind="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>-->
|
||||
<div class="control-group">
|
||||
<label class="control-label" style="padding-top: 0;">
|
||||
<span class="i18n" data-i18n-text="SETTINGS_CONTACTS/LABEL_SYNC_USERNAME"></span>
|
||||
<label class="control-label">
|
||||
<span class="i18n" data-i18n-text="SETTINGS_CONTACTS/LABEL_CONTACTS_SYNC_AB_URL"></span>
|
||||
</label>
|
||||
<div class="controls">
|
||||
<strong data-bind="text: contactsSyncUser"></strong>
|
||||
<input class="input-xxlarge" type="text" data-bind="value: contactsSyncUrl" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" style="padding-top: 0;">
|
||||
<span class="i18n" data-i18n-text="SETTINGS_CONTACTS/LABEL_SYNC_PASSWORD"></span>
|
||||
<label class="control-label">
|
||||
<span class="i18n" data-i18n-text="SETTINGS_CONTACTS/LABEL_CONTACTS_SYNC_USER"></span>
|
||||
</label>
|
||||
<div class="controls">
|
||||
<strong style="color:red" data-bind="text: contactsSyncPass, visible: showPassword"></strong>
|
||||
<span class="g-ui-link i18n" data-bind="visible: !showPassword(), click: toggleShowPassword"
|
||||
data-i18n-text="SETTINGS_CONTACTS/LINK_SHOW"></span>
|
||||
|
||||
<span class="g-ui-link i18n" data-bind="visible: showPassword, click: toggleShowPassword"
|
||||
data-i18n-text="SETTINGS_CONTACTS/LINK_HIDE"></span>
|
||||
<input type="text" data-bind="value: contactsSyncUser" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label">
|
||||
<span class="i18n" data-i18n-text="SETTINGS_CONTACTS/LABEL_CONTACTS_SYNC_PASSWORD"></span>
|
||||
</label>
|
||||
<div class="controls">
|
||||
<div class="alert alert-info span7" style="margin-left: 0">
|
||||
<p>
|
||||
<span class="i18n" data-i18n-text="SETTINGS_CONTACTS/DESC_FULL_PAB_URL"></span>
|
||||
</p>
|
||||
<p>
|
||||
<span class="i18n" data-i18n-text="SETTINGS_CONTACTS/LABEL_DESC_PAB"></span>:
|
||||
<br />
|
||||
<a href="javascript:void(0);" target="_blank" data-bind="text: contactsSyncPabUrl, attr: {'href': contactsSyncPabUrl}"></a>
|
||||
</p>
|
||||
</div>
|
||||
<br />
|
||||
<input type="password" data-bind="value: contactsSyncPass" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -22,6 +22,7 @@ LABEL_ADV_FROM = "Von"
|
|||
LABEL_ADV_TO = "An"
|
||||
LABEL_ADV_SUBJECT = "Thema"
|
||||
LABEL_ADV_TEXT = "Text"
|
||||
LABEL_ADV_HAS_ATTACHMENT = "Has attachment"
|
||||
LABEL_ADV_HAS_ATTACHMENTS = "Anhangdateien vorhanden"
|
||||
LABEL_ADV_FLAGGED = "Flagged"
|
||||
LABEL_ADV_UNSEEN = "Unseen"
|
||||
|
@ -161,6 +162,8 @@ CONTACT_VIEW_DESC = "Kontakt aus der Liste wählen um ihn anzuzeigen."
|
|||
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"
|
||||
PLACEHOLDER_ENTER_DISPLAY_NAME = "Enter display name"
|
||||
|
@ -170,6 +173,7 @@ LABEL_READ_ONLY = "Read only"
|
|||
LABEL_SHARE = "Share"
|
||||
BUTTON_SHARE_NONE = "None"
|
||||
BUTTON_SHARE_ALL = "Everyone"
|
||||
BUTTON_SYNC = "Synchronization (CardDAV)"
|
||||
|
||||
[COMPOSE]
|
||||
TITLE_FROM = "Von"
|
||||
|
@ -383,15 +387,13 @@ LABEL_CHROME_NOTIFICATION_DESC_DENIED = "(Vom Browser blockiert.)"
|
|||
|
||||
[SETTINGS_CONTACTS]
|
||||
LEGEND_CONTACTS = "Contacts"
|
||||
LEGEND_MOBILE_SYNC = "Mobile Sync"
|
||||
LABEL_SYNC_SERVER = "Server"
|
||||
LABEL_SYNC_USERNAME = "User Name"
|
||||
LABEL_SYNC_PASSWORD = "Password"
|
||||
LINK_HIDE = "hide"
|
||||
LINK_SHOW = "show"
|
||||
LABEL_DESC_PAB = "Pesonal Address Book"
|
||||
DESC_FULL_PAB_URL = "If your application (such as Mozilla Thunderbird (SOGo Connector Thunderbird extension) or Evolution) requires full path to the CardDAV address book, use the URL below."
|
||||
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 = "Vorlagen"
|
||||
|
@ -537,6 +539,7 @@ 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 = "Die Nachrichten-Liste ist nicht verfügbar"
|
||||
CANT_GET_MESSAGE = "Diese Nachricht ist nicht verfügbar"
|
||||
CANT_DELETE_MESSAGE = "Diese Nachricht kann nicht gelöscht werden"
|
||||
|
|
|
@ -22,6 +22,7 @@ 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"
|
||||
|
@ -161,6 +162,8 @@ CONTACT_VIEW_DESC = "Select contact in 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"
|
||||
PLACEHOLDER_ENTER_DISPLAY_NAME = "Enter display name"
|
||||
|
@ -170,6 +173,7 @@ LABEL_READ_ONLY = "Read only"
|
|||
LABEL_SHARE = "Share"
|
||||
BUTTON_SHARE_NONE = "None"
|
||||
BUTTON_SHARE_ALL = "Everyone"
|
||||
BUTTON_SYNC = "Synchronization (CardDAV)"
|
||||
|
||||
[COMPOSE]
|
||||
TITLE_FROM = "From"
|
||||
|
@ -385,15 +389,13 @@ LABEL_CHROME_NOTIFICATION_DESC_DENIED = "(Blocked by the browser)"
|
|||
|
||||
[SETTINGS_CONTACTS]
|
||||
LEGEND_CONTACTS = "Contacts"
|
||||
LEGEND_MOBILE_SYNC = "Mobile Sync"
|
||||
LABEL_SYNC_SERVER = "Server"
|
||||
LABEL_SYNC_USERNAME = "User Name"
|
||||
LABEL_SYNC_PASSWORD = "Password"
|
||||
LINK_HIDE = "hide"
|
||||
LINK_SHOW = "show"
|
||||
LABEL_DESC_PAB = "Pesonal Address Book"
|
||||
DESC_FULL_PAB_URL = "If your application (such as Mozilla Thunderbird (SOGo Connector Thunderbird extension) or Evolution) requires full path to the CardDAV address book, use the URL below."
|
||||
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"
|
||||
|
@ -539,6 +541,7 @@ 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"
|
||||
|
|
|
@ -22,6 +22,7 @@ LABEL_ADV_FROM = "De"
|
|||
LABEL_ADV_TO = "Para"
|
||||
LABEL_ADV_SUBJECT = "Asunto"
|
||||
LABEL_ADV_TEXT = "Texto"
|
||||
LABEL_ADV_HAS_ATTACHMENT = "Has attachment"
|
||||
LABEL_ADV_HAS_ATTACHMENTS = "Tiene adjuntos"
|
||||
LABEL_ADV_FLAGGED = "Flagged"
|
||||
LABEL_ADV_UNSEEN = "Unseen"
|
||||
|
@ -161,6 +162,8 @@ CONTACT_VIEW_DESC = "Seleccionar un contacto en la lista para verlo aquí."
|
|||
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"
|
||||
PLACEHOLDER_ENTER_DISPLAY_NAME = "Enter display name"
|
||||
|
@ -170,6 +173,7 @@ LABEL_READ_ONLY = "Read only"
|
|||
LABEL_SHARE = "Share"
|
||||
BUTTON_SHARE_NONE = "None"
|
||||
BUTTON_SHARE_ALL = "Everyone"
|
||||
BUTTON_SYNC = "Synchronization (CardDAV)"
|
||||
|
||||
[COMPOSE]
|
||||
TITLE_FROM = "De"
|
||||
|
@ -383,15 +387,13 @@ LABEL_CHROME_NOTIFICATION_DESC_DENIED = "(Bloqueado por el explorador)"
|
|||
|
||||
[SETTINGS_CONTACTS]
|
||||
LEGEND_CONTACTS = "Contacts"
|
||||
LEGEND_MOBILE_SYNC = "Mobile Sync"
|
||||
LABEL_SYNC_SERVER = "Server"
|
||||
LABEL_SYNC_USERNAME = "User Name"
|
||||
LABEL_SYNC_PASSWORD = "Password"
|
||||
LINK_HIDE = "hide"
|
||||
LINK_SHOW = "show"
|
||||
LABEL_DESC_PAB = "Pesonal Address Book"
|
||||
DESC_FULL_PAB_URL = "If your application (such as Mozilla Thunderbird (SOGo Connector Thunderbird extension) or Evolution) requires full path to the CardDAV address book, use the URL below."
|
||||
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 = "Temas"
|
||||
|
@ -537,6 +539,7 @@ 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 = "No se puede obtener la lista de mensajes"
|
||||
CANT_GET_MESSAGE = "No se puede obtener el mensaje"
|
||||
CANT_DELETE_MESSAGE = "No se puede eliminar el mensaje"
|
||||
|
|
|
@ -22,6 +22,7 @@ LABEL_ADV_FROM = "De"
|
|||
LABEL_ADV_TO = "A"
|
||||
LABEL_ADV_SUBJECT = "Sujet"
|
||||
LABEL_ADV_TEXT = "Texte"
|
||||
LABEL_ADV_HAS_ATTACHMENT = "Has attachment"
|
||||
LABEL_ADV_HAS_ATTACHMENTS = "Pièces jointes"
|
||||
LABEL_ADV_FLAGGED = "Flagged"
|
||||
LABEL_ADV_UNSEEN = "Unseen"
|
||||
|
@ -161,6 +162,8 @@ CONTACT_VIEW_DESC = "Sélectionner un contact dans la liste pour l'afficher ici.
|
|||
LABEL_DISPLAY_NAME = "Nom Affiché"
|
||||
LABEL_EMAIL = "Email"
|
||||
LABEL_PHONE = "Téléphone"
|
||||
LABEL_WEB = "Web"
|
||||
LABEL_BIRTHDAY = "Birthday"
|
||||
LINK_ADD_EMAIL = "Ajouter une adresse email"
|
||||
LINK_ADD_PHONE = "Ajouter un numéro de téléphone"
|
||||
PLACEHOLDER_ENTER_DISPLAY_NAME = "Entrez le nom à afficher"
|
||||
|
@ -170,6 +173,7 @@ LABEL_READ_ONLY = "Lire seulement"
|
|||
LABEL_SHARE = "Partager"
|
||||
BUTTON_SHARE_NONE = "Personne"
|
||||
BUTTON_SHARE_ALL = "Tout le monde"
|
||||
BUTTON_SYNC = "Synchronization (CardDAV)"
|
||||
|
||||
[COMPOSE]
|
||||
TITLE_FROM = "De"
|
||||
|
@ -383,15 +387,13 @@ LABEL_CHROME_NOTIFICATION_DESC_DENIED = "(Bloqué par le navigateur)"
|
|||
|
||||
[SETTINGS_CONTACTS]
|
||||
LEGEND_CONTACTS = "Contacts"
|
||||
LEGEND_MOBILE_SYNC = "Mobile Sync"
|
||||
LABEL_SYNC_SERVER = "Serveur"
|
||||
LABEL_SYNC_USERNAME = "Nom d'utilisateur"
|
||||
LABEL_SYNC_PASSWORD = "Mot de passe"
|
||||
LINK_HIDE = "cacher"
|
||||
LINK_SHOW = "montrer"
|
||||
LABEL_DESC_PAB = "Carnet d'adresses personnel"
|
||||
DESC_FULL_PAB_URL = "Si votre application (comme Mozilla Thunderbird (Extension SOGo Connector pour Thunderbird) ou une Evolution) nécessite le chemin complet vers le carnet d'adresses de CardDAV, utilisez l'URL ci-dessous."
|
||||
LABEL_CONTACTS_AUTOSAVE = "Ajouter automatiquement les destinataires de votre carnet d'adresses"
|
||||
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 = "Thèmes"
|
||||
|
@ -537,6 +539,7 @@ 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 = "Impossible d'obtenir la liste des messages"
|
||||
CANT_GET_MESSAGE = "Impossible d'obtenir le message"
|
||||
CANT_DELETE_MESSAGE = "Impossible de supprimer le message"
|
||||
|
|
|
@ -22,6 +22,7 @@ LABEL_ADV_FROM = "Feladó"
|
|||
LABEL_ADV_TO = "Címzett"
|
||||
LABEL_ADV_SUBJECT = "Tárgy"
|
||||
LABEL_ADV_TEXT = "Szöveg"
|
||||
LABEL_ADV_HAS_ATTACHMENT = "Has attachment"
|
||||
LABEL_ADV_HAS_ATTACHMENTS = "Mellékletek"
|
||||
LABEL_ADV_FLAGGED = "Megjelölve"
|
||||
LABEL_ADV_UNSEEN = "Észrevétlen"
|
||||
|
@ -161,6 +162,8 @@ CONTACT_VIEW_DESC = "Select contact in list to view it here."
|
|||
LABEL_DISPLAY_NAME = "Display name"
|
||||
LABEL_EMAIL = "E-mail"
|
||||
LABEL_PHONE = "Telefonszám"
|
||||
LABEL_WEB = "Web"
|
||||
LABEL_BIRTHDAY = "Birthday"
|
||||
LINK_ADD_EMAIL = "Adjunk meg e-mail címet"
|
||||
LINK_ADD_PHONE = "Adjunk meg telefonszámot"
|
||||
PLACEHOLDER_ENTER_DISPLAY_NAME = "Enter display name"
|
||||
|
@ -170,6 +173,7 @@ LABEL_READ_ONLY = "Read only"
|
|||
LABEL_SHARE = "Megosztás"
|
||||
BUTTON_SHARE_NONE = "None"
|
||||
BUTTON_SHARE_ALL = "Everyone"
|
||||
BUTTON_SYNC = "Synchronization (CardDAV)"
|
||||
|
||||
[COMPOSE]
|
||||
TITLE_FROM = "From"
|
||||
|
@ -383,15 +387,13 @@ LABEL_CHROME_NOTIFICATION_DESC_DENIED = "(Blocked by the browser)"
|
|||
|
||||
[SETTINGS_CONTACTS]
|
||||
LEGEND_CONTACTS = "Contacts"
|
||||
LEGEND_MOBILE_SYNC = "Mobile Sync"
|
||||
LABEL_SYNC_SERVER = "Server"
|
||||
LABEL_SYNC_USERNAME = "User Name"
|
||||
LABEL_SYNC_PASSWORD = "Password"
|
||||
LINK_HIDE = "hide"
|
||||
LINK_SHOW = "show"
|
||||
LABEL_DESC_PAB = "Pesonal Address Book"
|
||||
DESC_FULL_PAB_URL = "If your application (such as Mozilla Thunderbird (SOGo Connector Thunderbird extension) or Evolution) requires full path to the CardDAV address book, use the URL below."
|
||||
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"
|
||||
|
@ -537,6 +539,7 @@ 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"
|
||||
|
|
|
@ -22,6 +22,7 @@ LABEL_ADV_FROM = "Frá"
|
|||
LABEL_ADV_TO = "Til"
|
||||
LABEL_ADV_SUBJECT = "Viðfangsefni"
|
||||
LABEL_ADV_TEXT = "Texti"
|
||||
LABEL_ADV_HAS_ATTACHMENT = "Has attachment"
|
||||
LABEL_ADV_HAS_ATTACHMENTS = "Hefur viðhengi"
|
||||
LABEL_ADV_FLAGGED = "Flagged"
|
||||
LABEL_ADV_UNSEEN = "Unseen"
|
||||
|
@ -161,6 +162,8 @@ CONTACT_VIEW_DESC = "Veldu tengilið í listanum til að skoða hér."
|
|||
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"
|
||||
PLACEHOLDER_ENTER_DISPLAY_NAME = "Enter display name"
|
||||
|
@ -170,6 +173,7 @@ LABEL_READ_ONLY = "Read only"
|
|||
LABEL_SHARE = "Share"
|
||||
BUTTON_SHARE_NONE = "None"
|
||||
BUTTON_SHARE_ALL = "Everyone"
|
||||
BUTTON_SYNC = "Synchronization (CardDAV)"
|
||||
|
||||
[COMPOSE]
|
||||
TITLE_FROM = "Frá"
|
||||
|
@ -383,15 +387,13 @@ LABEL_CHROME_NOTIFICATION_DESC_DENIED = "(Lokað af vafra)"
|
|||
|
||||
[SETTINGS_CONTACTS]
|
||||
LEGEND_CONTACTS = "Contacts"
|
||||
LEGEND_MOBILE_SYNC = "Mobile Sync"
|
||||
LABEL_SYNC_SERVER = "Server"
|
||||
LABEL_SYNC_USERNAME = "User Name"
|
||||
LABEL_SYNC_PASSWORD = "Password"
|
||||
LINK_HIDE = "hide"
|
||||
LINK_SHOW = "show"
|
||||
LABEL_DESC_PAB = "Pesonal Address Book"
|
||||
DESC_FULL_PAB_URL = "If your application (such as Mozilla Thunderbird (SOGo Connector Thunderbird extension) or Evolution) requires full path to the CardDAV address book, use the URL below."
|
||||
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 = "Þemur"
|
||||
|
@ -537,6 +539,7 @@ 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 = "Get ekki sótt bréfa lista"
|
||||
CANT_GET_MESSAGE = "Get ekki sótt bréf"
|
||||
CANT_DELETE_MESSAGE = "Get ekki eytt bréfi"
|
||||
|
|
|
@ -22,6 +22,7 @@ LABEL_ADV_FROM = "Da"
|
|||
LABEL_ADV_TO = "A"
|
||||
LABEL_ADV_SUBJECT = "Oggetto"
|
||||
LABEL_ADV_TEXT = "Messaggio"
|
||||
LABEL_ADV_HAS_ATTACHMENT = "Has attachment"
|
||||
LABEL_ADV_HAS_ATTACHMENTS = "Ha allegati"
|
||||
LABEL_ADV_FLAGGED = "Preferiti"
|
||||
LABEL_ADV_UNSEEN = "Non letti"
|
||||
|
@ -161,6 +162,8 @@ CONTACT_VIEW_DESC = "Seleziona un contatto dalla lista per visualizzarlo qui"
|
|||
LABEL_DISPLAY_NAME = "Nome visualizzato"
|
||||
LABEL_EMAIL = "Email"
|
||||
LABEL_PHONE = "Telefono"
|
||||
LABEL_WEB = "Web"
|
||||
LABEL_BIRTHDAY = "Birthday"
|
||||
LINK_ADD_EMAIL = "Aggiungi un'indirizzo email"
|
||||
LINK_ADD_PHONE = "Aggiungi un numero di telefono"
|
||||
PLACEHOLDER_ENTER_DISPLAY_NAME = "Inserisci il nome visualizzato"
|
||||
|
@ -170,6 +173,7 @@ LABEL_READ_ONLY = "Sola lettura"
|
|||
LABEL_SHARE = "Condividi"
|
||||
BUTTON_SHARE_NONE = "Nessuno"
|
||||
BUTTON_SHARE_ALL = "Tutti"
|
||||
BUTTON_SYNC = "Synchronization (CardDAV)"
|
||||
|
||||
[COMPOSE]
|
||||
TITLE_FROM = "Da"
|
||||
|
@ -383,15 +387,13 @@ LABEL_CHROME_NOTIFICATION_DESC_DENIED = "(Bloccate dal browser)"
|
|||
|
||||
[SETTINGS_CONTACTS]
|
||||
LEGEND_CONTACTS = "Contatti"
|
||||
LEGEND_MOBILE_SYNC = "Sincronizzazione mobile"
|
||||
LABEL_SYNC_SERVER = "Server"
|
||||
LABEL_SYNC_USERNAME = "Username"
|
||||
LABEL_SYNC_PASSWORD = "Password"
|
||||
LINK_HIDE = "nascondi"
|
||||
LINK_SHOW = "mostra"
|
||||
LABEL_DESC_PAB = "Rubrica personale"
|
||||
DESC_FULL_PAB_URL = "Se la tua applicazione (come Mozilla Thunderbird (estensione SOGo Connector) o Evolution) richiedono il percorso completo alla rubrica CardDAV, utilizza l'URL in basso."
|
||||
LABEL_CONTACTS_AUTOSAVE = "Aggiungi automaticamente le persone che ti inviano mail alla rubrica"
|
||||
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 = "Temi"
|
||||
|
@ -537,6 +539,7 @@ 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 = "Impossibile ottenere la lista dei messaggi"
|
||||
CANT_GET_MESSAGE = "Impossibile ottenere il messaggio"
|
||||
CANT_DELETE_MESSAGE = "Impossibile cancellare il messaggio"
|
||||
|
|
|
@ -22,6 +22,7 @@ LABEL_ADV_FROM = "差出人"
|
|||
LABEL_ADV_TO = "宛先"
|
||||
LABEL_ADV_SUBJECT = "件名"
|
||||
LABEL_ADV_TEXT = "キーワード"
|
||||
LABEL_ADV_HAS_ATTACHMENT = "Has attachment"
|
||||
LABEL_ADV_HAS_ATTACHMENTS = "添付ファイルあり"
|
||||
LABEL_ADV_FLAGGED = "スター付き"
|
||||
LABEL_ADV_UNSEEN = "未読メール"
|
||||
|
@ -161,6 +162,8 @@ CONTACT_VIEW_DESC = "Select contact in 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"
|
||||
PLACEHOLDER_ENTER_DISPLAY_NAME = "Enter display name"
|
||||
|
@ -170,6 +173,7 @@ LABEL_READ_ONLY = "Read only"
|
|||
LABEL_SHARE = "Share"
|
||||
BUTTON_SHARE_NONE = "None"
|
||||
BUTTON_SHARE_ALL = "Everyone"
|
||||
BUTTON_SYNC = "Synchronization (CardDAV)"
|
||||
|
||||
[COMPOSE]
|
||||
TITLE_FROM = "差出人"
|
||||
|
@ -383,15 +387,13 @@ LABEL_CHROME_NOTIFICATION_DESC_DENIED = "(ブラウザでブロックされて
|
|||
|
||||
[SETTINGS_CONTACTS]
|
||||
LEGEND_CONTACTS = "Contacts"
|
||||
LEGEND_MOBILE_SYNC = "Mobile Sync"
|
||||
LABEL_SYNC_SERVER = "Server"
|
||||
LABEL_SYNC_USERNAME = "User Name"
|
||||
LABEL_SYNC_PASSWORD = "Password"
|
||||
LINK_HIDE = "hide"
|
||||
LINK_SHOW = "show"
|
||||
LABEL_DESC_PAB = "Pesonal Address Book"
|
||||
DESC_FULL_PAB_URL = "If your application (such as Mozilla Thunderbird (SOGo Connector Thunderbird extension) or Evolution) requires full path to the CardDAV address book, use the URL below."
|
||||
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"
|
||||
|
@ -537,6 +539,7 @@ 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"
|
||||
|
|
|
@ -22,6 +22,7 @@ LABEL_ADV_FROM = "보낸 이"
|
|||
LABEL_ADV_TO = "받는 이"
|
||||
LABEL_ADV_SUBJECT = "제목"
|
||||
LABEL_ADV_TEXT = "본문"
|
||||
LABEL_ADV_HAS_ATTACHMENT = "Has attachment"
|
||||
LABEL_ADV_HAS_ATTACHMENTS = "첨부파일이 있는 메시지"
|
||||
LABEL_ADV_FLAGGED = "Flagged"
|
||||
LABEL_ADV_UNSEEN = "Unseen"
|
||||
|
@ -161,6 +162,8 @@ CONTACT_VIEW_DESC = "선택한 연락처가 이 곳에 표시됩니다"
|
|||
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"
|
||||
PLACEHOLDER_ENTER_DISPLAY_NAME = "Enter display name"
|
||||
|
@ -170,6 +173,7 @@ LABEL_READ_ONLY = "Read only"
|
|||
LABEL_SHARE = "Share"
|
||||
BUTTON_SHARE_NONE = "None"
|
||||
BUTTON_SHARE_ALL = "Everyone"
|
||||
BUTTON_SYNC = "Synchronization (CardDAV)"
|
||||
|
||||
[COMPOSE]
|
||||
TITLE_FROM = "보낸 이"
|
||||
|
@ -380,15 +384,13 @@ LABEL_CHROME_NOTIFICATION_DESC_DENIED = "(브라우저에 의해 차단됨)"
|
|||
|
||||
[SETTINGS_CONTACTS]
|
||||
LEGEND_CONTACTS = "Contacts"
|
||||
LEGEND_MOBILE_SYNC = "Mobile Sync"
|
||||
LABEL_SYNC_SERVER = "Server"
|
||||
LABEL_SYNC_USERNAME = "User Name"
|
||||
LABEL_SYNC_PASSWORD = "Password"
|
||||
LINK_HIDE = "hide"
|
||||
LINK_SHOW = "show"
|
||||
LABEL_DESC_PAB = "Pesonal Address Book"
|
||||
DESC_FULL_PAB_URL = "If your application (such as Mozilla Thunderbird (SOGo Connector Thunderbird extension) or Evolution) requires full path to the CardDAV address book, use the URL below."
|
||||
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 = "테마"
|
||||
|
@ -534,6 +536,7 @@ 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 = "메시지 목록을 불러 올 수 없습니다."
|
||||
CANT_GET_MESSAGE = "메시지를 가져올 수 없습니다."
|
||||
CANT_DELETE_MESSAGE = "메시지를 삭제할 수 없습니다."
|
||||
|
|
|
@ -22,6 +22,7 @@ LABEL_ADV_FROM = "No"
|
|||
LABEL_ADV_TO = "Kam"
|
||||
LABEL_ADV_SUBJECT = "Tēma"
|
||||
LABEL_ADV_TEXT = "Teksts"
|
||||
LABEL_ADV_HAS_ATTACHMENT = "Has attachment"
|
||||
LABEL_ADV_HAS_ATTACHMENTS = "Ir pielikumi"
|
||||
LABEL_ADV_FLAGGED = "Flagged"
|
||||
LABEL_ADV_UNSEEN = "Unseen"
|
||||
|
@ -161,6 +162,8 @@ CONTACT_VIEW_DESC = "Izvēlaties kontaktu no saraksta lai to apskatītu."
|
|||
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"
|
||||
PLACEHOLDER_ENTER_DISPLAY_NAME = "Enter display name"
|
||||
|
@ -170,6 +173,7 @@ LABEL_READ_ONLY = "Read only"
|
|||
LABEL_SHARE = "Share"
|
||||
BUTTON_SHARE_NONE = "None"
|
||||
BUTTON_SHARE_ALL = "Everyone"
|
||||
BUTTON_SYNC = "Synchronization (CardDAV)"
|
||||
|
||||
[COMPOSE]
|
||||
TITLE_FROM = "No"
|
||||
|
@ -383,15 +387,13 @@ LABEL_CHROME_NOTIFICATION_DESC_DENIED = "(Parlūkprogramma bloķēja)"
|
|||
|
||||
[SETTINGS_CONTACTS]
|
||||
LEGEND_CONTACTS = "Contacts"
|
||||
LEGEND_MOBILE_SYNC = "Mobile Sync"
|
||||
LABEL_SYNC_SERVER = "Server"
|
||||
LABEL_SYNC_USERNAME = "User Name"
|
||||
LABEL_SYNC_PASSWORD = "Password"
|
||||
LINK_HIDE = "hide"
|
||||
LINK_SHOW = "show"
|
||||
LABEL_DESC_PAB = "Pesonal Address Book"
|
||||
DESC_FULL_PAB_URL = "If your application (such as Mozilla Thunderbird (SOGo Connector Thunderbird extension) or Evolution) requires full path to the CardDAV address book, use the URL below."
|
||||
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 = "Tēmas"
|
||||
|
@ -537,6 +539,7 @@ 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 = "Nevar ielādēt ziņojumu sarakstu"
|
||||
CANT_GET_MESSAGE = "Nevar ielādēt ziņojumu"
|
||||
CANT_DELETE_MESSAGE = "Nevar izdzēst ziņojumu"
|
||||
|
|
|
@ -22,6 +22,7 @@ LABEL_ADV_FROM = "Van"
|
|||
LABEL_ADV_TO = "Naar"
|
||||
LABEL_ADV_SUBJECT = "Onderwerp"
|
||||
LABEL_ADV_TEXT = "Tekst"
|
||||
LABEL_ADV_HAS_ATTACHMENT = "Has attachment"
|
||||
LABEL_ADV_HAS_ATTACHMENTS = "Heeft bijlages"
|
||||
LABEL_ADV_FLAGGED = "Flagged"
|
||||
LABEL_ADV_UNSEEN = "Unseen"
|
||||
|
@ -161,6 +162,8 @@ CONTACT_VIEW_DESC = "Selecteer het contact in de lijst om hier te bekijken."
|
|||
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"
|
||||
PLACEHOLDER_ENTER_DISPLAY_NAME = "Enter display name"
|
||||
|
@ -170,6 +173,7 @@ LABEL_READ_ONLY = "Read only"
|
|||
LABEL_SHARE = "Share"
|
||||
BUTTON_SHARE_NONE = "None"
|
||||
BUTTON_SHARE_ALL = "Everyone"
|
||||
BUTTON_SYNC = "Synchronization (CardDAV)"
|
||||
|
||||
[COMPOSE]
|
||||
TITLE_FROM = "Van"
|
||||
|
@ -383,15 +387,13 @@ LABEL_CHROME_NOTIFICATION_DESC_DENIED = "(Geblokkeerd door de browser)"
|
|||
|
||||
[SETTINGS_CONTACTS]
|
||||
LEGEND_CONTACTS = "Contacts"
|
||||
LEGEND_MOBILE_SYNC = "Mobile Sync"
|
||||
LABEL_SYNC_SERVER = "Server"
|
||||
LABEL_SYNC_USERNAME = "User Name"
|
||||
LABEL_SYNC_PASSWORD = "Password"
|
||||
LINK_HIDE = "hide"
|
||||
LINK_SHOW = "show"
|
||||
LABEL_DESC_PAB = "Pesonal Address Book"
|
||||
DESC_FULL_PAB_URL = "If your application (such as Mozilla Thunderbird (SOGo Connector Thunderbird extension) or Evolution) requires full path to the CardDAV address book, use the URL below."
|
||||
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"
|
||||
|
@ -537,6 +539,7 @@ 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 = "Kan bericht niet verwijderen"
|
||||
|
|
|
@ -22,6 +22,7 @@ LABEL_ADV_FROM = "Fra"
|
|||
LABEL_ADV_TO = "Til"
|
||||
LABEL_ADV_SUBJECT = "Emne"
|
||||
LABEL_ADV_TEXT = "Tekst"
|
||||
LABEL_ADV_HAS_ATTACHMENT = "Has attachment"
|
||||
LABEL_ADV_HAS_ATTACHMENTS = "Har vedlegg"
|
||||
LABEL_ADV_FLAGGED = "Markert"
|
||||
LABEL_ADV_UNSEEN = "Ulest"
|
||||
|
@ -161,6 +162,8 @@ CONTACT_VIEW_DESC = "Velg kontakt i listen for å vise det her ."
|
|||
LABEL_DISPLAY_NAME = "Navn"
|
||||
LABEL_EMAIL = "E-post"
|
||||
LABEL_PHONE = "Telefon"
|
||||
LABEL_WEB = "Web"
|
||||
LABEL_BIRTHDAY = "Birthday"
|
||||
LINK_ADD_EMAIL = "Legg til en e-postadresse"
|
||||
LINK_ADD_PHONE = "Legg til en telefon"
|
||||
PLACEHOLDER_ENTER_DISPLAY_NAME = "Enter display name"
|
||||
|
@ -170,6 +173,7 @@ LABEL_READ_ONLY = "Read only"
|
|||
LABEL_SHARE = "Share"
|
||||
BUTTON_SHARE_NONE = "None"
|
||||
BUTTON_SHARE_ALL = "Everyone"
|
||||
BUTTON_SYNC = "Synchronization (CardDAV)"
|
||||
|
||||
[COMPOSE]
|
||||
TITLE_FROM = "Fra"
|
||||
|
@ -383,15 +387,13 @@ LABEL_CHROME_NOTIFICATION_DESC_DENIED = "( Blokkert av nettleseren )"
|
|||
|
||||
[SETTINGS_CONTACTS]
|
||||
LEGEND_CONTACTS = "Contacts"
|
||||
LEGEND_MOBILE_SYNC = "Mobile Sync"
|
||||
LABEL_SYNC_SERVER = "Server"
|
||||
LABEL_SYNC_USERNAME = "User Name"
|
||||
LABEL_SYNC_PASSWORD = "Password"
|
||||
LINK_HIDE = "hide"
|
||||
LINK_SHOW = "show"
|
||||
LABEL_DESC_PAB = "Pesonal Address Book"
|
||||
DESC_FULL_PAB_URL = "If your application (such as Mozilla Thunderbird (SOGo Connector Thunderbird extension) or Evolution) requires full path to the CardDAV address book, use the URL below."
|
||||
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 = "Tema"
|
||||
|
@ -537,6 +539,7 @@ 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 = "Kan ikke få meldingsliste"
|
||||
CANT_GET_MESSAGE = "Kan ikke få meldingen"
|
||||
CANT_DELETE_MESSAGE = "Kan ikke slette meldingen"
|
||||
|
|
|
@ -22,6 +22,7 @@ LABEL_ADV_FROM = "Od"
|
|||
LABEL_ADV_TO = "Do"
|
||||
LABEL_ADV_SUBJECT = "Temat"
|
||||
LABEL_ADV_TEXT = "Tekst"
|
||||
LABEL_ADV_HAS_ATTACHMENT = "Has attachment"
|
||||
LABEL_ADV_HAS_ATTACHMENTS = "Ma załączniki"
|
||||
LABEL_ADV_FLAGGED = "Oznaczona"
|
||||
LABEL_ADV_UNSEEN = "Nieodczytana"
|
||||
|
@ -160,6 +161,8 @@ CONTACT_VIEW_DESC = "Wybierz kontakt z listy w celu jego wyświetlenia"
|
|||
LABEL_DISPLAY_NAME = "Wyświetlana nazwa"
|
||||
LABEL_EMAIL = "Email"
|
||||
LABEL_PHONE = "Telefon"
|
||||
LABEL_WEB = "Web"
|
||||
LABEL_BIRTHDAY = "Birthday"
|
||||
LINK_ADD_EMAIL = "Dodaj adres email"
|
||||
LINK_ADD_PHONE = "Dodaj nr Tel"
|
||||
PLACEHOLDER_ENTER_DISPLAY_NAME = "Nazwa wyświetlana"
|
||||
|
@ -169,6 +172,7 @@ LABEL_READ_ONLY = "Tylko do odczytu"
|
|||
LABEL_SHARE = "Udostępnij kontakt"
|
||||
BUTTON_SHARE_NONE = "Nikomu"
|
||||
BUTTON_SHARE_ALL = "Wszystkim"
|
||||
BUTTON_SYNC = "Synchronization (CardDAV)"
|
||||
|
||||
[COMPOSE]
|
||||
TITLE_FROM = "Od"
|
||||
|
@ -382,15 +386,13 @@ LABEL_CHROME_NOTIFICATION_DESC_DENIED = "(Zablokowane przez przeglądarkę)"
|
|||
|
||||
[SETTINGS_CONTACTS]
|
||||
LEGEND_CONTACTS = "Kontakty"
|
||||
LEGEND_MOBILE_SYNC = "Synchronizacja mobilna"
|
||||
LABEL_SYNC_SERVER = "Serwer"
|
||||
LABEL_SYNC_USERNAME = "Użytkownik"
|
||||
LABEL_SYNC_PASSWORD = "Hasło"
|
||||
LINK_HIDE = "ukryj"
|
||||
LINK_SHOW = "pokaż"
|
||||
LABEL_DESC_PAB = "Książka adresowa"
|
||||
DESC_FULL_PAB_URL = "Jeżeli twoja aplikacja (taka jak Mozilla Thunderbird (rozszerzenie-SOGo Connector Thunderbird) lub pokrewne) wymaga pełnej ścieżki dostępu do książki adresowej CardDAV, użyj poniższego adresu URL."
|
||||
LABEL_CONTACTS_AUTOSAVE = "Automatycznie dodaj nieznanych nadawców i odbiorców do książki adresowej"
|
||||
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 = "Wygląd"
|
||||
|
@ -536,6 +538,7 @@ 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 = "Nie jest możliwe pobranie listy wiadomości"
|
||||
CANT_GET_MESSAGE = "Nie można pobrać wiadomości"
|
||||
CANT_DELETE_MESSAGE = "Nie można usunąć wiadomości"
|
||||
|
|
|
@ -22,6 +22,7 @@ LABEL_ADV_FROM = "De"
|
|||
LABEL_ADV_TO = "Para"
|
||||
LABEL_ADV_SUBJECT = "Assunto"
|
||||
LABEL_ADV_TEXT = "Texto"
|
||||
LABEL_ADV_HAS_ATTACHMENT = "Has attachment"
|
||||
LABEL_ADV_HAS_ATTACHMENTS = "Tem Anexos"
|
||||
LABEL_ADV_FLAGGED = "Flagged"
|
||||
LABEL_ADV_UNSEEN = "Unseen"
|
||||
|
@ -161,6 +162,8 @@ CONTACT_VIEW_DESC = "Selecione o contato na lista para visualizá-lo."
|
|||
LABEL_DISPLAY_NAME = "Nome público"
|
||||
LABEL_EMAIL = "Email"
|
||||
LABEL_PHONE = "Telefone"
|
||||
LABEL_WEB = "Web"
|
||||
LABEL_BIRTHDAY = "Birthday"
|
||||
LINK_ADD_EMAIL = "Adicionar um endereço e-mail"
|
||||
LINK_ADD_PHONE = "Adicionar um telefone"
|
||||
PLACEHOLDER_ENTER_DISPLAY_NAME = "Digite um nome público"
|
||||
|
@ -170,6 +173,7 @@ LABEL_READ_ONLY = "Ler somente"
|
|||
LABEL_SHARE = "Compartilhar"
|
||||
BUTTON_SHARE_NONE = "Ninguém"
|
||||
BUTTON_SHARE_ALL = "Todo mundo"
|
||||
BUTTON_SYNC = "Synchronization (CardDAV)"
|
||||
|
||||
[COMPOSE]
|
||||
TITLE_FROM = "De"
|
||||
|
@ -383,15 +387,13 @@ LABEL_CHROME_NOTIFICATION_DESC_DENIED = "(Bloqueado pelo navegador)"
|
|||
|
||||
[SETTINGS_CONTACTS]
|
||||
LEGEND_CONTACTS = "Contatos"
|
||||
LEGEND_MOBILE_SYNC = "Sincronia Mobile"
|
||||
LABEL_SYNC_SERVER = "Servidor"
|
||||
LABEL_SYNC_USERNAME = "Usuário"
|
||||
LABEL_SYNC_PASSWORD = "Senha"
|
||||
LINK_HIDE = "esconder"
|
||||
LINK_SHOW = "mostrar"
|
||||
LABEL_DESC_PAB = "Lista de endereços pessoais"
|
||||
DESC_FULL_PAB_URL = "Se o seu aplicativo (como o Mozilla Thunderbird (SOGo conector extensão Thunderbird) ou Evolution) requer caminho completo para o livro de endereços CardDAV, use a URL abaixo."
|
||||
LABEL_CONTACTS_AUTOSAVE = "Adicionar automaticamente destinatários a sua lista de endereços"
|
||||
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 = "Temas"
|
||||
|
@ -536,6 +538,7 @@ 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 = "Não é possível obter a lista de mensagens"
|
||||
CANT_GET_MESSAGE = "Não é possível obter a mensagem"
|
||||
CANT_DELETE_MESSAGE = "Não é possível excluir a mensagem"
|
||||
|
|
|
@ -22,6 +22,7 @@ LABEL_ADV_FROM = "De"
|
|||
LABEL_ADV_TO = "Para"
|
||||
LABEL_ADV_SUBJECT = "Assunto"
|
||||
LABEL_ADV_TEXT = "Texto"
|
||||
LABEL_ADV_HAS_ATTACHMENT = "Has attachment"
|
||||
LABEL_ADV_HAS_ATTACHMENTS = "Tem Anexos"
|
||||
LABEL_ADV_FLAGGED = "Flagged"
|
||||
LABEL_ADV_UNSEEN = "Unseen"
|
||||
|
@ -161,6 +162,8 @@ CONTACT_VIEW_DESC = "Selecione o contato na lista para visualizá-lo."
|
|||
LABEL_DISPLAY_NAME = "Nome público"
|
||||
LABEL_EMAIL = "Email"
|
||||
LABEL_PHONE = "Telefone"
|
||||
LABEL_WEB = "Web"
|
||||
LABEL_BIRTHDAY = "Birthday"
|
||||
LINK_ADD_EMAIL = "Adicionar um endereço e-mail"
|
||||
LINK_ADD_PHONE = "Adicionar um telefone"
|
||||
PLACEHOLDER_ENTER_DISPLAY_NAME = "Digite um nome público"
|
||||
|
@ -170,6 +173,7 @@ LABEL_READ_ONLY = "Ler somente"
|
|||
LABEL_SHARE = "Compartilhar"
|
||||
BUTTON_SHARE_NONE = "Ninguém"
|
||||
BUTTON_SHARE_ALL = "Todo mundo"
|
||||
BUTTON_SYNC = "Synchronization (CardDAV)"
|
||||
|
||||
[COMPOSE]
|
||||
TITLE_FROM = "De"
|
||||
|
@ -383,15 +387,13 @@ LABEL_CHROME_NOTIFICATION_DESC_DENIED = "(Bloqueado pelo navegador)"
|
|||
|
||||
[SETTINGS_CONTACTS]
|
||||
LEGEND_CONTACTS = "Contatos"
|
||||
LEGEND_MOBILE_SYNC = "Sincronia Mobile"
|
||||
LABEL_SYNC_SERVER = "Servidor"
|
||||
LABEL_SYNC_USERNAME = "Usuário"
|
||||
LABEL_SYNC_PASSWORD = "Senha"
|
||||
LINK_HIDE = "esconder"
|
||||
LINK_SHOW = "mostrar"
|
||||
LABEL_DESC_PAB = "Lista de endereços pessoais"
|
||||
DESC_FULL_PAB_URL = "Se o seu aplicativo (como o Mozilla Thunderbird (SOGo conector extensão Thunderbird) ou Evolution) requer caminho completo para o livro de endereços CardDAV, use a URL abaixo."
|
||||
LABEL_CONTACTS_AUTOSAVE = "Adicionar automaticamente destinatários a sua lista de endereços"
|
||||
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 = "Temas"
|
||||
|
@ -537,6 +539,7 @@ 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 = "Não é possível obter a lista de mensagens"
|
||||
CANT_GET_MESSAGE = "Não é possível obter a mensagem"
|
||||
CANT_DELETE_MESSAGE = "Não é possível excluir a mensagem"
|
||||
|
|
|
@ -22,6 +22,7 @@ LABEL_ADV_FROM = "De la"
|
|||
LABEL_ADV_TO = "către"
|
||||
LABEL_ADV_SUBJECT = "Subiect"
|
||||
LABEL_ADV_TEXT = "Conținut"
|
||||
LABEL_ADV_HAS_ATTACHMENT = "Has attachment"
|
||||
LABEL_ADV_HAS_ATTACHMENTS = "Atașamente"
|
||||
LABEL_ADV_FLAGGED = "Importante"
|
||||
LABEL_ADV_UNSEEN = "Necitit"
|
||||
|
@ -160,6 +161,8 @@ CONTACT_VIEW_DESC = "Selectați un contact pentru al vizualiza"
|
|||
LABEL_DISPLAY_NAME = "Nume complet"
|
||||
LABEL_EMAIL = "Adresa de eMail"
|
||||
LABEL_PHONE = "Тelefon"
|
||||
LABEL_WEB = "Web"
|
||||
LABEL_BIRTHDAY = "Birthday"
|
||||
LINK_ADD_EMAIL = "Adugă Mail nou"
|
||||
LINK_ADD_PHONE = "Adaugă un număr nou"
|
||||
PLACEHOLDER_ENTER_DISPLAY_NAME = "Introduceți numele complet"
|
||||
|
@ -169,6 +172,7 @@ LABEL_READ_ONLY = "Doar pentru citire"
|
|||
LABEL_SHARE = "Distribuie"
|
||||
BUTTON_SHARE_NONE = "Nimic"
|
||||
BUTTON_SHARE_ALL = "Toate"
|
||||
BUTTON_SYNC = "Synchronization (CardDAV)"
|
||||
|
||||
[COMPOSE]
|
||||
TITLE_FROM = "De la"
|
||||
|
@ -382,15 +386,13 @@ LABEL_CHROME_NOTIFICATION_DESC_DENIED = "(browser-ul blocat)"
|
|||
|
||||
[SETTINGS_CONTACTS]
|
||||
LEGEND_CONTACTS = "Contacte"
|
||||
LEGEND_MOBILE_SYNC = "Sincronizați cu mobilul"
|
||||
LABEL_SYNC_SERVER = "Server"
|
||||
LABEL_SYNC_USERNAME = "Utilizator"
|
||||
LABEL_SYNC_PASSWORD = "Parolă"
|
||||
LINK_HIDE = "Ascunde"
|
||||
LINK_SHOW = "Arată"
|
||||
LABEL_DESC_PAB = "Agendă personală"
|
||||
DESC_FULL_PAB_URL = "Dacă cerea dumneavoastră (cum ar fi Mozilla Thunderbird (Extensie Sogo Conector Thunderbird) sau Evolution) are nevoie de calea completă la agenda CardDAV, utilizați URL-ul de mai jos."
|
||||
LABEL_CONTACTS_AUTOSAVE = "Adaugă automat destinatarii la agenda de scrisori"
|
||||
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 = "Tematică"
|
||||
|
@ -536,6 +538,7 @@ 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 = "Nu găsesc o lista de scrisori"
|
||||
CANT_GET_MESSAGE = "Nu pot obține scrisoarea. Încercați din nou"
|
||||
CANT_DELETE_MESSAGE = "Nu pot șterge scrisoarea. Încercați din nou"
|
||||
|
|
|
@ -22,6 +22,7 @@ LABEL_ADV_FROM = "От"
|
|||
LABEL_ADV_TO = "Кому"
|
||||
LABEL_ADV_SUBJECT = "Тема"
|
||||
LABEL_ADV_TEXT = "Текст"
|
||||
LABEL_ADV_HAS_ATTACHMENT = "С файлами"
|
||||
LABEL_ADV_HAS_ATTACHMENTS = "С файлами"
|
||||
LABEL_ADV_FLAGGED = "Помеченные"
|
||||
LABEL_ADV_UNSEEN = "Непрочитанные"
|
||||
|
@ -161,6 +162,8 @@ CONTACT_VIEW_DESC = "Выберите контакт для просмотра."
|
|||
LABEL_DISPLAY_NAME = "Полное имя"
|
||||
LABEL_EMAIL = "Электронная почта"
|
||||
LABEL_PHONE = "Телефон"
|
||||
LABEL_WEB = "Сайт"
|
||||
LABEL_BIRTHDAY = "День рождения"
|
||||
LINK_ADD_EMAIL = "Добавьте адрес электронной почты"
|
||||
LINK_ADD_PHONE = "Добавьте телефон"
|
||||
PLACEHOLDER_ENTER_DISPLAY_NAME = "Введите полное имя"
|
||||
|
@ -170,6 +173,7 @@ LABEL_READ_ONLY = "Read only"
|
|||
LABEL_SHARE = "Поделиться"
|
||||
BUTTON_SHARE_NONE = "Отменить"
|
||||
BUTTON_SHARE_ALL = "Всем"
|
||||
BUTTON_SYNC = "Синхронизация (CardDAV)"
|
||||
|
||||
[COMPOSE]
|
||||
TITLE_FROM = "От"
|
||||
|
@ -383,15 +387,13 @@ LABEL_CHROME_NOTIFICATION_DESC_DENIED = "(Блокировано браузер
|
|||
|
||||
[SETTINGS_CONTACTS]
|
||||
LEGEND_CONTACTS = "Контакты"
|
||||
LEGEND_MOBILE_SYNC = "Мобильная Синхронизация"
|
||||
LABEL_SYNC_SERVER = "Сервер"
|
||||
LABEL_SYNC_USERNAME = "Пользователь"
|
||||
LABEL_SYNC_PASSWORD = "Пароль"
|
||||
LINK_HIDE = "спрятать"
|
||||
LINK_SHOW = "показать"
|
||||
LABEL_DESC_PAB = "Персональная адресная книга"
|
||||
DESC_FULL_PAB_URL = "Если вашему приложению (например как Mozilla Thunderbird (SOGo Connector Thunderbird extension) или Evolution) необходим полный путь к CardDAV адресной книге, используйте URL ниже."
|
||||
LABEL_CONTACTS_AUTOSAVE = "Автоматически добавлять получателей писем в адресную книгу"
|
||||
LEGEND_CONTACTS_SYNC = "Синхронизация (CardDAV)"
|
||||
LABEL_CONTACTS_SYNC_ENABLE = "Включить синхронизация"
|
||||
LABEL_CONTACTS_SYNC_SERVER = "Сервер"
|
||||
LABEL_CONTACTS_SYNC_AB_URL = "Адресная книга (URL)"
|
||||
LABEL_CONTACTS_SYNC_USER = "Пользователь"
|
||||
LABEL_CONTACTS_SYNC_PASSWORD = "Пароль"
|
||||
|
||||
[SETTINGS_THEMES]
|
||||
LEGEND_THEMES = "Темы Оформления"
|
||||
|
@ -538,6 +540,7 @@ CURRENT_PASSWORD_INCORRECT = "Текущий пароль неверный"
|
|||
NEW_PASSWORD_SHORT = "Пароль слишком короткий"
|
||||
NEW_PASSWORD_WEAK = "Пароль слишком простой"
|
||||
NEW_PASSWORD_FORBIDDENT = "Пароль содержит запрещенные символы"
|
||||
CONTACTS_SYNC_ERROR = "Contacts synchronization error"
|
||||
CANT_GET_MESSAGE_LIST = "Не могу получить список писем"
|
||||
CANT_GET_MESSAGE = "Не могу получить письмо"
|
||||
CANT_DELETE_MESSAGE = "Не могу удалить письмо"
|
||||
|
|
|
@ -22,6 +22,7 @@ LABEL_ADV_FROM = "Odosielateľ"
|
|||
LABEL_ADV_TO = "Príjemca"
|
||||
LABEL_ADV_SUBJECT = "Predmet"
|
||||
LABEL_ADV_TEXT = "Text"
|
||||
LABEL_ADV_HAS_ATTACHMENT = "Has attachment"
|
||||
LABEL_ADV_HAS_ATTACHMENTS = "S prílohami"
|
||||
LABEL_ADV_FLAGGED = "Označené hviezdičkou"
|
||||
LABEL_ADV_UNSEEN = "Neprečítané"
|
||||
|
@ -161,6 +162,8 @@ CONTACT_VIEW_DESC = "Zvoľte kontakt zo zoznamu pre jeho zobrazenie tu."
|
|||
LABEL_DISPLAY_NAME = "Zobraziť ako"
|
||||
LABEL_EMAIL = "Email"
|
||||
LABEL_PHONE = "Telefón"
|
||||
LABEL_WEB = "Web"
|
||||
LABEL_BIRTHDAY = "Birthday"
|
||||
LINK_ADD_EMAIL = "Pridať emailovú adresu"
|
||||
LINK_ADD_PHONE = "Pridať telefón"
|
||||
PLACEHOLDER_ENTER_DISPLAY_NAME = "Zadajte Zobrazované meno"
|
||||
|
@ -170,6 +173,7 @@ LABEL_READ_ONLY = "Len pre čítanie"
|
|||
LABEL_SHARE = "Zdielať"
|
||||
BUTTON_SHARE_NONE = "Žiadne"
|
||||
BUTTON_SHARE_ALL = "Všetko"
|
||||
BUTTON_SYNC = "Synchronization (CardDAV)"
|
||||
|
||||
[COMPOSE]
|
||||
TITLE_FROM = "Odosielateľ"
|
||||
|
@ -383,15 +387,13 @@ LABEL_CHROME_NOTIFICATION_DESC_DENIED = "(Zablokované prehliadačom)"
|
|||
|
||||
[SETTINGS_CONTACTS]
|
||||
LEGEND_CONTACTS = "Kontakty"
|
||||
LEGEND_MOBILE_SYNC = "Mobilná synchronizácia"
|
||||
LABEL_SYNC_SERVER = "Server"
|
||||
LABEL_SYNC_USERNAME = "Používateľské meno"
|
||||
LABEL_SYNC_PASSWORD = "Heslo"
|
||||
LINK_HIDE = "skryť"
|
||||
LINK_SHOW = "zobraziť"
|
||||
LABEL_DESC_PAB = "Osobný adresár"
|
||||
DESC_FULL_PAB_URL = "Ak vaša aplikácia (ako napríklad Mozilla Thunderbird (Rozšírenie SOGo Connector Thunderbird) alebo Evolution) vyžaduje úplnú cestu ku CardDAV Adresáru, použite nižšie uvedenú adresu."
|
||||
LABEL_CONTACTS_AUTOSAVE = "Automaticky pridávať príjemcov správ do Adresára"
|
||||
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 = "Motívy"
|
||||
|
@ -537,6 +539,7 @@ 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 = "Chyba pri vytváraní zoznamu správ."
|
||||
CANT_GET_MESSAGE = "Správu sa nepodarilo načítať"
|
||||
CANT_DELETE_MESSAGE = "Správu sa nepodarilo odstrániť"
|
||||
|
|
|
@ -22,6 +22,7 @@ LABEL_ADV_FROM = "发送自"
|
|||
LABEL_ADV_TO = "发送到"
|
||||
LABEL_ADV_SUBJECT = "主题"
|
||||
LABEL_ADV_TEXT = "内容"
|
||||
LABEL_ADV_HAS_ATTACHMENT = "Has attachment"
|
||||
LABEL_ADV_HAS_ATTACHMENTS = "有附件"
|
||||
LABEL_ADV_FLAGGED = "Flagged"
|
||||
LABEL_ADV_UNSEEN = "Unseen"
|
||||
|
@ -161,6 +162,8 @@ CONTACT_VIEW_DESC = "在此查看在列表中选中的联系人。"
|
|||
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"
|
||||
PLACEHOLDER_ENTER_DISPLAY_NAME = "Enter display name"
|
||||
|
@ -170,6 +173,7 @@ LABEL_READ_ONLY = "Read only"
|
|||
LABEL_SHARE = "Share"
|
||||
BUTTON_SHARE_NONE = "None"
|
||||
BUTTON_SHARE_ALL = "Everyone"
|
||||
BUTTON_SYNC = "Synchronization (CardDAV)"
|
||||
|
||||
[COMPOSE]
|
||||
TITLE_FROM = "发送自"
|
||||
|
@ -383,15 +387,13 @@ LABEL_CHROME_NOTIFICATION_DESC_DENIED = "(被浏览器阻止)"
|
|||
|
||||
[SETTINGS_CONTACTS]
|
||||
LEGEND_CONTACTS = "Contacts"
|
||||
LEGEND_MOBILE_SYNC = "Mobile Sync"
|
||||
LABEL_SYNC_SERVER = "Server"
|
||||
LABEL_SYNC_USERNAME = "User Name"
|
||||
LABEL_SYNC_PASSWORD = "Password"
|
||||
LINK_HIDE = "hide"
|
||||
LINK_SHOW = "show"
|
||||
LABEL_DESC_PAB = "Pesonal Address Book"
|
||||
DESC_FULL_PAB_URL = "If your application (such as Mozilla Thunderbird (SOGo Connector Thunderbird extension) or Evolution) requires full path to the CardDAV address book, use the URL below."
|
||||
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 = "主题"
|
||||
|
@ -537,6 +539,7 @@ 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 = "无法获取邮件列表"
|
||||
CANT_GET_MESSAGE = "无法获取邮件"
|
||||
CANT_DELETE_MESSAGE = "无法删除邮件"
|
||||
|
|
|
@ -637,7 +637,7 @@
|
|||
border-radius: 8px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*! normalize.css 2012-03-11T12:53 UTC - http://github.com/necolas/normalize.css */
|
||||
|
||||
/* =============================================================================
|
||||
|
@ -1142,7 +1142,7 @@ table {
|
|||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
|
||||
@charset "UTF-8";
|
||||
|
||||
@font-face {
|
||||
|
@ -1483,7 +1483,22 @@ table {
|
|||
.icon-filter:before {
|
||||
content: "\e063";
|
||||
}
|
||||
|
||||
.icon-resize:before {
|
||||
content: "\e064";
|
||||
}
|
||||
.icon-sync:before {
|
||||
content: "\e065";
|
||||
}
|
||||
.icon-ellipsis-alt:before {
|
||||
content: "\e066";
|
||||
}
|
||||
.icon-cloud-up:before {
|
||||
content: "\e067";
|
||||
}
|
||||
.icon-cloud-down:before {
|
||||
content: "\e068";
|
||||
}
|
||||
|
||||
/** initial setup **/
|
||||
.nano {
|
||||
/*
|
||||
|
@ -1600,7 +1615,7 @@ table {
|
|||
.nano > .pane2:hover > .slider2, .nano > .pane2.active > .slider2 {
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
|
||||
/* Magnific Popup CSS */
|
||||
.mfp-bg {
|
||||
top: 0;
|
||||
|
@ -1965,7 +1980,7 @@ img.mfp-img {
|
|||
right: 0;
|
||||
padding-top: 0; }
|
||||
|
||||
|
||||
|
||||
|
||||
/* overlay at start */
|
||||
.mfp-fade.mfp-bg {
|
||||
|
@ -2011,7 +2026,7 @@ img.mfp-img {
|
|||
-moz-transform: translateX(50px);
|
||||
transform: translateX(50px);
|
||||
}
|
||||
|
||||
|
||||
.simple-pace {
|
||||
-webkit-pointer-events: none;
|
||||
pointer-events: none;
|
||||
|
@ -2082,7 +2097,7 @@ img.mfp-img {
|
|||
@keyframes simple-pace-stripe-animation {
|
||||
0% { transform: none; transform: none; }
|
||||
100% { transform: translate(-32px, 0); transform: translate(-32px, 0); }
|
||||
}
|
||||
}
|
||||
.inputosaurus-container {
|
||||
background-color:#fff;
|
||||
border:1px solid #bcbec0;
|
||||
|
@ -2150,7 +2165,7 @@ img.mfp-img {
|
|||
box-shadow:none;
|
||||
}
|
||||
.inputosaurus-input-hidden { display:none; }
|
||||
|
||||
|
||||
.flag-wrapper {
|
||||
width: 24px;
|
||||
height: 16px;
|
||||
|
@ -2194,7 +2209,7 @@ img.mfp-img {
|
|||
.flag.flag-pt-br {background-position: -192px -11px}
|
||||
|
||||
.flag.flag-cn, .flag.flag-zh-tw, .flag.flag-zh-cn, .flag.flag-zh-hk {background-position: -208px -22px}
|
||||
|
||||
|
||||
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||
.clearfix {
|
||||
*zoom: 1;
|
||||
|
|
2
rainloop/v/0.0.0/static/css/app.min.css
vendored
2
rainloop/v/0.0.0/static/css/app.min.css
vendored
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -107,4 +107,9 @@
|
|||
<glyph unicode="" d="M456 343c0 1 0 1 0 1 0 5-2 10-5 13l0 1-40 69c-1 6-6 10-13 10 0 0 0 0-1 0l0 0-283 0 0 0c0 0 0 0 0 0-5 0-9-3-12-7l0 0-42-72 0 0c-3-4-4-9-4-14 0 0 0 0 0-1l0-247c0 0 0 0 0 0 0-12 9-21 20-21 1 0 1 0 1 0l358 0c0 0 0 0 0 0 12 0 21 9 21 21 0 0 0 0 0 0l0 247z m-131-125l-64-90c-1-1-3-2-5-2 0 0 0 0 0 0-2 0-4 1-5 2l-64 90c-1 2-1 4 0 6 1 2 3 3 5 3l30 0 0 81c0 3 3 6 6 6l56 0c3 0 6-3 6-6l0-81 30 0c2 0 4-1 5-3 1-2 1-4 0-6z m-231 147l27 47 270 0 27-47z"/>
|
||||
<glyph unicode="" d="M96 288l64 0 0-32-64 0z m0-64l64 0 0-32-64 0z m384 160l-448 0c-18 0-32-14-32-32l0-224c0-18 14-32 32-32l448 0c18 0 32 14 32 32l0 224c0 18-14 32-32 32m-288-224l-128 0 0 160 128 0z m128 0l-96 0 0 160 32 0 0-128 32 0 0 128 32 0z m128 64l-32 0 0-64-32 0 0 64-32 0 0 96 32 0 0-64 32 0 0 64 32 0z"/>
|
||||
<glyph unicode="" d="M456 428c3-8 2-15-4-20l-141-141 0-212c0-8-4-14-11-17-3-1-5-1-7-1-6 0-10 1-13 5l-73 73c-4 4-6 8-6 13l0 139-141 141c-6 5-7 12-4 20 4 7 9 11 17 11l366 0c8 0 13-4 17-11z"/>
|
||||
<glyph unicode="" d="M148 367l-111-111 111-111 0 74 216 0 0-74 111 111-111 111 0-74-216 0z"/>
|
||||
<glyph unicode="" d="M341 94c0-2-1-4-2-6-2-2-4-3-6-3l-256 0c-2 0-3 1-4 1-1 0-2 1-2 2-1 1-1 1-2 2 0 0 0 1 0 3-1 1-1 2-1 3l0 160-51 0c-5 0-9 2-12 5-3 3-5 7-5 12 0 4 1 8 4 11l85 102c4 4 8 6 13 6 6 0 10-2 13-6l86-102c2-3 4-7 4-11 0-5-2-9-5-12-4-3-8-5-12-5l-51 0 0-102 153 0c3 0 5-1 7-3l42-52c2-1 2-3 2-5z m171 111c0-4-1-8-4-11l-85-103c-4-4-8-6-13-6-6 0-10 2-13 6l-86 103c-2 3-4 7-4 11 0 4 2 8 5 12 4 3 8 5 12 5l51 0 0 102-153 0c-3 0-5 1-7 3l-42 52c-2 1-2 3-2 5 0 2 1 4 2 6 2 2 4 3 6 3l256 0c2 0 3-1 4-1 1 0 2-1 2-2 1-1 1-1 2-2 0-1 0-2 0-3 1-2 1-3 1-3l0-160 51 0c5 0 9-2 12-5 3-4 5-8 5-12z"/>
|
||||
<glyph unicode="" d="M311 155l0-54c0-8-3-15-8-20-5-5-12-8-20-8l-54 0c-8 0-15 3-20 8-5 5-8 12-8 20l0 54c0 8 3 15 8 20 5 5 12 8 20 8l54 0c8 0 15-3 20-8 5-5 8-12 8-20z m0 147l0-55c0-8-3-14-8-20-5-5-12-8-20-8l-54 0c-8 0-15 3-20 8-5 6-8 12-8 20l0 55c0 7 3 14 8 19 5 5 12 8 20 8l54 0c8 0 15-3 20-8 5-5 8-12 8-19z m0 146l0-55c0-7-3-14-8-19-5-6-12-8-20-8l-54 0c-8 0-15 2-20 8-5 5-8 12-8 19l0 55c0 8 3 14 8 19 5 6 12 8 20 8l54 0c8 0 15-2 20-8 5-5 8-11 8-19z"/>
|
||||
<glyph unicode="" d="M341 265c0 2 0 4-2 6l-94 94c-2 1-4 2-6 2-3 0-5-1-6-2l-94-94c-2-2-2-4-2-6 0-3 0-5 2-7 2-1 4-2 6-2l60 0 0-94c0-2 1-4 2-6 2-2 4-2 6-2l52 0c2 0 4 0 6 2 1 2 2 4 2 6l0 94 60 0c2 0 4 1 6 3 1 1 2 3 2 6z m171-77c0-29-10-53-30-73-20-20-44-30-72-30l-291 0c-32 0-61 12-84 35-23 24-35 52-35 85 0 23 6 44 19 64 12 19 29 34 50 44-1 5-1 9-1 11 0 38 14 70 40 97 27 26 59 40 97 40 28 0 53-8 76-23 23-16 40-36 50-62 13 11 28 17 44 17 19 0 35-7 49-20 13-14 20-30 20-49 0-13-4-26-11-37 23-5 42-17 57-36 15-18 22-39 22-63z"/>
|
||||
<glyph unicode="" d="M341 247c0 3 0 5-2 7-2 1-4 2-6 2l-60 0 0 94c0 2-1 4-2 6-2 2-4 2-6 2l-52 0c-2 0-4 0-6-2-1-2-2-4-2-6l0-94-60 0c-2 0-4-1-6-3-2-1-2-3-2-6 0-2 0-4 2-6l94-94c1-1 3-2 6-2 2 0 4 1 6 2l94 94c1 2 2 4 2 6z m171-59c0-29-10-53-30-73-20-20-44-30-72-30l-291 0c-32 0-61 12-84 35-23 24-35 52-35 85 0 23 6 44 19 64 12 19 29 34 50 44-1 5-1 9-1 11 0 38 14 70 40 97 27 26 59 40 97 40 28 0 53-8 76-23 23-16 40-36 50-62 13 11 28 17 44 17 19 0 35-7 49-20 13-14 20-30 20-49 0-13-4-26-11-37 23-5 42-17 57-36 15-18 22-39 22-63z"/>
|
||||
</font></defs></svg>
|
||||
|
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 40 KiB |
Binary file not shown.
Binary file not shown.
|
@ -1,5 +1,5 @@
|
|||
/*! RainLoop Webmail Admin Module (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||
(function (window, $, ko, crossroads, hasher, _) {
|
||||
/*! RainLoop Webmail Admin Module (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||
(function (window, $, ko, crossroads, hasher, _) {
|
||||
|
||||
'use strict';
|
||||
|
||||
|
@ -75,14 +75,14 @@ var
|
|||
$document = $(window.document),
|
||||
|
||||
NotificationClass = window.Notification && window.Notification.requestPermission ? window.Notification : null
|
||||
;
|
||||
;
|
||||
/*jshint onevar: false*/
|
||||
/**
|
||||
* @type {?AdminApp}
|
||||
*/
|
||||
var RL = null;
|
||||
/*jshint onevar: true*/
|
||||
|
||||
|
||||
/**
|
||||
* @type {?}
|
||||
*/
|
||||
|
@ -231,7 +231,7 @@ if (Globals.bAllowPdfPreview && navigator && navigator.mimeTypes)
|
|||
return oType && 'application/pdf' === oType.type;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Consts.Defaults = {};
|
||||
Consts.Values = {};
|
||||
Consts.DataImages = {};
|
||||
|
@ -246,7 +246,7 @@ Consts.Defaults.MessagesPerPage = 20;
|
|||
* @const
|
||||
* @type {number}
|
||||
*/
|
||||
Consts.Defaults.ContactsPerPage = 20;
|
||||
Consts.Defaults.ContactsPerPage = 50;
|
||||
|
||||
/**
|
||||
* @const
|
||||
|
@ -278,6 +278,12 @@ Consts.Defaults.SendMessageAjaxTimeout = 300000;
|
|||
*/
|
||||
Consts.Defaults.SaveMessageAjaxTimeout = 200000;
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {number}
|
||||
*/
|
||||
Consts.Defaults.ContactsSyncAjaxTimeout = 200000;
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {string}
|
||||
|
@ -349,7 +355,7 @@ Consts.DataImages.UserDotPic = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA
|
|||
* @type {string}
|
||||
*/
|
||||
Consts.DataImages.TranspPic = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQIW2NkAAIAAAoAAggA9GkAAAAASUVORK5CYII=';
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
|
@ -613,14 +619,6 @@ Enums.Layout = {
|
|||
'BottomPreview': 2
|
||||
};
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
*/
|
||||
Enums.ContactScopeType = {
|
||||
'Default': 0,
|
||||
'ShareAll': 2
|
||||
};
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
*/
|
||||
|
@ -650,17 +648,9 @@ Enums.ContactPropertyType = {
|
|||
'NamePrefix': 20,
|
||||
'NameSuffix': 21,
|
||||
|
||||
'EmailPersonal': 30,
|
||||
'EmailBussines': 31,
|
||||
|
||||
'PhonePersonal': 50,
|
||||
'PhoneBussines': 51,
|
||||
|
||||
'MobilePersonal': 60,
|
||||
'MobileBussines': 61,
|
||||
|
||||
'FaxPesonal': 70,
|
||||
'FaxBussines': 71,
|
||||
'Email': 30,
|
||||
'Phone': 31,
|
||||
'Web': 32,
|
||||
|
||||
'Facebook': 90,
|
||||
'Skype': 91,
|
||||
|
@ -694,6 +684,8 @@ Enums.Notification = {
|
|||
'NewPasswordShort': 132,
|
||||
'NewPasswordWeak': 133,
|
||||
'NewPasswordForbidden': 134,
|
||||
|
||||
'ContactsSyncError': 140,
|
||||
|
||||
'CantGetMessageList': 201,
|
||||
'CantGetMessage': 202,
|
||||
|
@ -735,7 +727,7 @@ Enums.Notification = {
|
|||
'UnknownNotification': 999,
|
||||
'UnknownError': 999
|
||||
};
|
||||
|
||||
|
||||
Utils.trim = $.trim;
|
||||
Utils.inArray = $.inArray;
|
||||
Utils.isArray = _.isArray;
|
||||
|
@ -1313,6 +1305,8 @@ Utils.initNotificationLanguage = function ()
|
|||
NotificationI18N[Enums.Notification.NewPasswordWeak] = Utils.i18n('NOTIFICATIONS/NEW_PASSWORD_WEAK');
|
||||
NotificationI18N[Enums.Notification.NewPasswordForbidden] = Utils.i18n('NOTIFICATIONS/NEW_PASSWORD_FORBIDDENT');
|
||||
|
||||
NotificationI18N[Enums.Notification.ContactsSyncError] = Utils.i18n('NOTIFICATIONS/CONTACTS_SYNC_ERROR');
|
||||
|
||||
NotificationI18N[Enums.Notification.CantGetMessageList] = Utils.i18n('NOTIFICATIONS/CANT_GET_MESSAGE_LIST');
|
||||
NotificationI18N[Enums.Notification.CantGetMessage] = Utils.i18n('NOTIFICATIONS/CANT_GET_MESSAGE');
|
||||
NotificationI18N[Enums.Notification.CantDeleteMessage] = Utils.i18n('NOTIFICATIONS/CANT_DELETE_MESSAGE');
|
||||
|
@ -2098,6 +2092,15 @@ Utils.fakeMd5 = function(iLen)
|
|||
return sResult;
|
||||
};
|
||||
|
||||
/* jshint ignore:start */
|
||||
|
||||
/**
|
||||
* @param {string} s
|
||||
* @return {string}
|
||||
*/
|
||||
Utils.md5 = function(s){function L(k,d){return(k<<d)|(k>>>(32-d))}function K(G,k){var I,d,F,H,x;F=(G&2147483648);H=(k&2147483648);I=(G&1073741824);d=(k&1073741824);x=(G&1073741823)+(k&1073741823);if(I&d){return(x^2147483648^F^H)}if(I|d){if(x&1073741824){return(x^3221225472^F^H)}else{return(x^1073741824^F^H)}}else{return(x^F^H)}}function r(d,F,k){return(d&F)|((~d)&k)}function q(d,F,k){return(d&k)|(F&(~k))}function p(d,F,k){return(d^F^k)}function n(d,F,k){return(F^(d|(~k)))}function u(G,F,aa,Z,k,H,I){G=K(G,K(K(r(F,aa,Z),k),I));return K(L(G,H),F)}function f(G,F,aa,Z,k,H,I){G=K(G,K(K(q(F,aa,Z),k),I));return K(L(G,H),F)}function D(G,F,aa,Z,k,H,I){G=K(G,K(K(p(F,aa,Z),k),I));return K(L(G,H),F)}function t(G,F,aa,Z,k,H,I){G=K(G,K(K(n(F,aa,Z),k),I));return K(L(G,H),F)}function e(G){var Z;var F=G.length;var x=F+8;var k=(x-(x%64))/64;var I=(k+1)*16;var aa=Array(I-1);var d=0;var H=0;while(H<F){Z=(H-(H%4))/4;d=(H%4)*8;aa[Z]=(aa[Z]|(G.charCodeAt(H)<<d));H++}Z=(H-(H%4))/4;d=(H%4)*8;aa[Z]=aa[Z]|(128<<d);aa[I-2]=F<<3;aa[I-1]=F>>>29;return aa}function B(x){var k="",F="",G,d;for(d=0;d<=3;d++){G=(x>>>(d*8))&255;F="0"+G.toString(16);k=k+F.substr(F.length-2,2)}return k}function J(k){k=k.replace(/rn/g,"n");var d="";for(var F=0;F<k.length;F++){var x=k.charCodeAt(F);if(x<128){d+=String.fromCharCode(x)}else{if((x>127)&&(x<2048)){d+=String.fromCharCode((x>>6)|192);d+=String.fromCharCode((x&63)|128)}else{d+=String.fromCharCode((x>>12)|224);d+=String.fromCharCode(((x>>6)&63)|128);d+=String.fromCharCode((x&63)|128)}}}return d}var C=Array();var P,h,E,v,g,Y,X,W,V;var S=7,Q=12,N=17,M=22;var A=5,z=9,y=14,w=20;var o=4,m=11,l=16,j=23;var U=6,T=10,R=15,O=21;s=J(s);C=e(s);Y=1732584193;X=4023233417;W=2562383102;V=271733878;for(P=0;P<C.length;P+=16){h=Y;E=X;v=W;g=V;Y=u(Y,X,W,V,C[P+0],S,3614090360);V=u(V,Y,X,W,C[P+1],Q,3905402710);W=u(W,V,Y,X,C[P+2],N,606105819);X=u(X,W,V,Y,C[P+3],M,3250441966);Y=u(Y,X,W,V,C[P+4],S,4118548399);V=u(V,Y,X,W,C[P+5],Q,1200080426);W=u(W,V,Y,X,C[P+6],N,2821735955);X=u(X,W,V,Y,C[P+7],M,4249261313);Y=u(Y,X,W,V,C[P+8],S,1770035416);V=u(V,Y,X,W,C[P+9],Q,2336552879);W=u(W,V,Y,X,C[P+10],N,4294925233);X=u(X,W,V,Y,C[P+11],M,2304563134);Y=u(Y,X,W,V,C[P+12],S,1804603682);V=u(V,Y,X,W,C[P+13],Q,4254626195);W=u(W,V,Y,X,C[P+14],N,2792965006);X=u(X,W,V,Y,C[P+15],M,1236535329);Y=f(Y,X,W,V,C[P+1],A,4129170786);V=f(V,Y,X,W,C[P+6],z,3225465664);W=f(W,V,Y,X,C[P+11],y,643717713);X=f(X,W,V,Y,C[P+0],w,3921069994);Y=f(Y,X,W,V,C[P+5],A,3593408605);V=f(V,Y,X,W,C[P+10],z,38016083);W=f(W,V,Y,X,C[P+15],y,3634488961);X=f(X,W,V,Y,C[P+4],w,3889429448);Y=f(Y,X,W,V,C[P+9],A,568446438);V=f(V,Y,X,W,C[P+14],z,3275163606);W=f(W,V,Y,X,C[P+3],y,4107603335);X=f(X,W,V,Y,C[P+8],w,1163531501);Y=f(Y,X,W,V,C[P+13],A,2850285829);V=f(V,Y,X,W,C[P+2],z,4243563512);W=f(W,V,Y,X,C[P+7],y,1735328473);X=f(X,W,V,Y,C[P+12],w,2368359562);Y=D(Y,X,W,V,C[P+5],o,4294588738);V=D(V,Y,X,W,C[P+8],m,2272392833);W=D(W,V,Y,X,C[P+11],l,1839030562);X=D(X,W,V,Y,C[P+14],j,4259657740);Y=D(Y,X,W,V,C[P+1],o,2763975236);V=D(V,Y,X,W,C[P+4],m,1272893353);W=D(W,V,Y,X,C[P+7],l,4139469664);X=D(X,W,V,Y,C[P+10],j,3200236656);Y=D(Y,X,W,V,C[P+13],o,681279174);V=D(V,Y,X,W,C[P+0],m,3936430074);W=D(W,V,Y,X,C[P+3],l,3572445317);X=D(X,W,V,Y,C[P+6],j,76029189);Y=D(Y,X,W,V,C[P+9],o,3654602809);V=D(V,Y,X,W,C[P+12],m,3873151461);W=D(W,V,Y,X,C[P+15],l,530742520);X=D(X,W,V,Y,C[P+2],j,3299628645);Y=t(Y,X,W,V,C[P+0],U,4096336452);V=t(V,Y,X,W,C[P+7],T,1126891415);W=t(W,V,Y,X,C[P+14],R,2878612391);X=t(X,W,V,Y,C[P+5],O,4237533241);Y=t(Y,X,W,V,C[P+12],U,1700485571);V=t(V,Y,X,W,C[P+3],T,2399980690);W=t(W,V,Y,X,C[P+10],R,4293915773);X=t(X,W,V,Y,C[P+1],O,2240044497);Y=t(Y,X,W,V,C[P+8],U,1873313359);V=t(V,Y,X,W,C[P+15],T,4264355552);W=t(W,V,Y,X,C[P+6],R,2734768916);X=t(X,W,V,Y,C[P+13],O,1309151649);Y=t(Y,X,W,V,C[P+4],U,4149444226);V=t(V,Y,X,W,C[P+11],T,3174756917);W=t(W,V,Y,X,C[P+2],R,718787259);X=t(X,W,V,Y,C[P+9],O,3951481745);Y=K(Y,h);X=K(X,E);W=K(W,v);V=K(V,g)}var i=B(Y)+B(X)+B(W)+B(V);return i.toLowerCase()};
|
||||
/* jshint ignore:end */
|
||||
|
||||
Utils.convertPlainTextToHtml = function (sPlain)
|
||||
{
|
||||
return sPlain.toString()
|
||||
|
@ -2112,11 +2115,12 @@ Utils.draggeblePlace = function ()
|
|||
|
||||
Utils.defautOptionsAfterRender = function (oOption, oItem)
|
||||
{
|
||||
if (oItem && !Utils.isUnd(oItem.disabled))
|
||||
if (oItem && !Utils.isUnd(oItem.disabled) && oOption)
|
||||
{
|
||||
ko.applyBindingsToNode(oOption, {
|
||||
'disabled': oItem.disabled
|
||||
}, oItem);
|
||||
$(oOption)
|
||||
.toggleClass('disabled', oItem.disabled)
|
||||
.prop('disabled', oItem.disabled)
|
||||
;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2511,7 +2515,7 @@ Utils.detectDropdownVisibility = _.debounce(function () {
|
|||
Globals.dropdownVisibility(!!_.find(BootstrapDropdowns, function (oItem) {
|
||||
return oItem.hasClass('open');
|
||||
}));
|
||||
}, 50);
|
||||
}, 50);
|
||||
// Base64 encode / decode
|
||||
// http://www.webtoolkit.info/
|
||||
|
||||
|
@ -2674,7 +2678,7 @@ Base64 = {
|
|||
}
|
||||
};
|
||||
|
||||
/*jslint bitwise: false*/
|
||||
/*jslint bitwise: false*/
|
||||
ko.bindingHandlers.tooltip = {
|
||||
'init': function (oElement, fValueAccessor) {
|
||||
if (!Globals.bMobileDevice)
|
||||
|
@ -3381,7 +3385,7 @@ ko.observable.fn.validateFunc = function (fFunc)
|
|||
return this;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
|
@ -3679,7 +3683,7 @@ LinkBuilder.prototype.socialFacebook = function ()
|
|||
{
|
||||
return this.sServer + 'SocialFacebook' + ('' !== this.sSpecSuffix ? '/' + this.sSpecSuffix + '/' : '');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
*/
|
||||
|
@ -3773,7 +3777,7 @@ Plugins.settingsGet = function (sPluginSection, sName)
|
|||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
|
@ -3847,7 +3851,7 @@ CookieDriver.prototype.get = function (sKey)
|
|||
|
||||
return mResult;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
|
@ -3918,7 +3922,7 @@ LocalStorageDriver.prototype.get = function (sKey)
|
|||
|
||||
return mResult;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
|
@ -3961,7 +3965,7 @@ LocalStorage.prototype.get = function (iKey)
|
|||
{
|
||||
return this.oDriver ? this.oDriver.get('p' + iKey) : null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
|
@ -3974,7 +3978,7 @@ KnoinAbstractBoot.prototype.bootstart = function ()
|
|||
{
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string=} sPosition = ''
|
||||
* @param {string=} sTemplate = ''
|
||||
|
@ -4060,7 +4064,7 @@ KnoinAbstractViewModel.prototype.registerPopupEscapeKey = function ()
|
|||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} sScreenName
|
||||
* @param {?=} aViewModels = []
|
||||
|
@ -4136,7 +4140,7 @@ KnoinAbstractScreen.prototype.__start = function ()
|
|||
this.oCross = oRoute;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
|
@ -4534,7 +4538,7 @@ Knoin.prototype.bootstart = function ()
|
|||
};
|
||||
|
||||
kn = new Knoin();
|
||||
|
||||
|
||||
/**
|
||||
* @param {string=} sEmail
|
||||
* @param {string=} sName
|
||||
|
@ -4898,7 +4902,7 @@ EmailModel.prototype.inputoTagLine = function ()
|
|||
{
|
||||
return 0 < this.name.length ? this.name + ' (' + this.email + ')' : this.email;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends KnoinAbstractViewModel
|
||||
|
@ -5116,7 +5120,7 @@ PopupsDomainViewModel.prototype.clearForm = function ()
|
|||
this.smtpAuth(true);
|
||||
this.whiteList('');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends KnoinAbstractViewModel
|
||||
|
@ -5253,7 +5257,7 @@ PopupsPluginViewModel.prototype.onBuild = function ()
|
|||
}
|
||||
}, this));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends KnoinAbstractViewModel
|
||||
|
@ -5369,7 +5373,7 @@ PopupsActivateViewModel.prototype.validateSubscriptionKey = function ()
|
|||
{
|
||||
var sValue = this.key();
|
||||
return '' === sValue || !!/^RL[\d]+-[A-Z0-9\-]+Z$/.test(Utils.trim(sValue));
|
||||
};
|
||||
};
|
||||
/**
|
||||
* @constructor
|
||||
* @extends KnoinAbstractViewModel
|
||||
|
@ -5429,7 +5433,7 @@ PopupsLanguagesViewModel.prototype.changeLanguage = function (sLang)
|
|||
RL.data().mainLanguage(sLang);
|
||||
this.cancelCommand();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends KnoinAbstractViewModel
|
||||
|
@ -5535,7 +5539,7 @@ PopupsAskViewModel.prototype.onBuild = function ()
|
|||
}, this));
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends KnoinAbstractViewModel
|
||||
|
@ -5622,7 +5626,7 @@ AdminLoginViewModel.prototype.onHide = function ()
|
|||
{
|
||||
this.loginFocus(false);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {?} oScreen
|
||||
*
|
||||
|
@ -5644,7 +5648,7 @@ AdminMenuViewModel.prototype.link = function (sRoute)
|
|||
{
|
||||
return '#/' + sRoute;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends KnoinAbstractViewModel
|
||||
|
@ -5666,7 +5670,7 @@ AdminPaneViewModel.prototype.logoutClick = function ()
|
|||
RL.remote().adminLogout(function () {
|
||||
RL.loginAndLogoutReload();
|
||||
});
|
||||
};
|
||||
};
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
|
@ -5766,7 +5770,7 @@ AdminGeneral.prototype.selectLanguage = function ()
|
|||
{
|
||||
kn.showScreenPopup(PopupsLanguagesViewModel);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
|
@ -5818,7 +5822,7 @@ AdminLogin.prototype.onBuild = function ()
|
|||
|
||||
}, 50);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
|
@ -5887,7 +5891,7 @@ AdminBranding.prototype.onBuild = function ()
|
|||
|
||||
}, 50);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
|
@ -6078,7 +6082,7 @@ AdminContacts.prototype.onBuild = function ()
|
|||
'ContactsSync': bValue ? '1' : '0'
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
self.contactsType.subscribe(function (sValue) {
|
||||
RL.remote().saveAdminConfig(f5, {
|
||||
'ContactsPdoType': sValue
|
||||
|
@ -6107,7 +6111,7 @@ AdminContacts.prototype.onBuild = function ()
|
|||
|
||||
}, 50);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
|
@ -6196,7 +6200,7 @@ AdminDomains.prototype.onDomainListChangeRequest = function ()
|
|||
{
|
||||
RL.reloadDomainList();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
|
@ -6291,7 +6295,7 @@ AdminSecurity.prototype.phpInfoLink = function ()
|
|||
{
|
||||
return RL.link().phpInfo();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
|
@ -6407,7 +6411,7 @@ AdminSocial.prototype.onBuild = function ()
|
|||
|
||||
}, 50);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
|
@ -6504,7 +6508,7 @@ AdminPlugins.prototype.onPluginDisableRequest = function (sResult, oData)
|
|||
|
||||
RL.reloadPluginList();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
|
@ -6602,7 +6606,7 @@ AdminPackages.prototype.installPackage = function (oPackage)
|
|||
RL.remote().packageInstall(this.requestHelper(oPackage, true), oPackage);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
|
@ -6653,7 +6657,7 @@ AdminLicensing.prototype.licenseExpiredMomentValue = function ()
|
|||
{
|
||||
var oDate = moment.unix(this.licenseExpired());
|
||||
return oDate.format('LL') + ' (' + oDate.from(moment()) + ')';
|
||||
};
|
||||
};
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
|
@ -6778,7 +6782,7 @@ AbstractData.prototype.populateDataOnStart = function()
|
|||
|
||||
this.contactsIsAllowed(!!RL.settingsGet('ContactsIsAllowed'));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends AbstractData
|
||||
|
@ -6812,7 +6816,7 @@ _.extend(AdminDataStorage.prototype, AbstractData.prototype);
|
|||
AdminDataStorage.prototype.populateDataOnStart = function()
|
||||
{
|
||||
AbstractData.prototype.populateDataOnStart.call(this);
|
||||
};
|
||||
};
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
|
@ -7086,7 +7090,7 @@ AbstractAjaxRemoteStorage.prototype.jsVersion = function (fCallback, sVersion)
|
|||
'Version': sVersion
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends AbstractAjaxRemoteStorage
|
||||
|
@ -7330,7 +7334,7 @@ AdminAjaxRemoteStorage.prototype.adminPing = function (fCallback)
|
|||
{
|
||||
this.defaultRequest(fCallback, 'AdminPing');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
|
@ -7339,6 +7343,7 @@ function AbstractCacheStorage()
|
|||
this.oEmailsPicsHashes = {};
|
||||
this.oServices = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
*/
|
||||
|
@ -7359,26 +7364,36 @@ AbstractCacheStorage.prototype.clear = function ()
|
|||
* @param {string} sEmail
|
||||
* @return {string}
|
||||
*/
|
||||
AbstractCacheStorage.prototype.getUserPic = function (sEmail)
|
||||
AbstractCacheStorage.prototype.getUserPic = function (sEmail, fCallback)
|
||||
{
|
||||
sEmail = Utils.trim(sEmail);
|
||||
|
||||
var
|
||||
sUrl = '',
|
||||
sService = '',
|
||||
sEmailLower = sEmail.toLowerCase(),
|
||||
sPicHash = Utils.isUnd(this.oEmailsPicsHashes[sEmail]) ? '' : this.oEmailsPicsHashes[sEmail]
|
||||
sPicHash = Utils.isUnd(this.oEmailsPicsHashes[sEmailLower]) ? '' : this.oEmailsPicsHashes[sEmailLower]
|
||||
;
|
||||
|
||||
if ('' === sPicHash)
|
||||
|
||||
if ('' !== sPicHash)
|
||||
{
|
||||
sUrl = RL.link().getUserPicUrlFromHash(sPicHash);
|
||||
}
|
||||
else
|
||||
{
|
||||
sService = sEmailLower.substr(sEmail.indexOf('@') + 1);
|
||||
sUrl = '' !== sService && this.oServices[sService] ? this.oServices[sService] : '';
|
||||
}
|
||||
else
|
||||
{
|
||||
sUrl = RL.link().getUserPicUrlFromHash(sPicHash);
|
||||
}
|
||||
|
||||
|
||||
return sUrl;
|
||||
// if ('' === sUrl) // Gravatar // TODO
|
||||
// {
|
||||
// fCallback('//secure.gravatar.com/avatar/' + Utils.md5(sEmailLower) + '.jpg?s=80&d=mm', sEmail);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
fCallback(sUrl, sEmail);
|
||||
// }
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -7396,7 +7411,7 @@ AbstractCacheStorage.prototype.setEmailsPicsHashesData = function (oData)
|
|||
{
|
||||
this.oEmailsPicsHashes = oData;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends AbstractCacheStorage
|
||||
|
@ -7407,7 +7422,7 @@ function AdminCacheStorage()
|
|||
}
|
||||
|
||||
_.extend(AdminCacheStorage.prototype, AbstractCacheStorage.prototype);
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array} aViewModels
|
||||
* @constructor
|
||||
|
@ -7585,7 +7600,7 @@ AbstractSettings.prototype.routes = function ()
|
|||
['', oRules]
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends KnoinAbstractScreen
|
||||
|
@ -7600,7 +7615,7 @@ _.extend(AdminLoginScreen.prototype, KnoinAbstractScreen.prototype);
|
|||
AdminLoginScreen.prototype.onShow = function ()
|
||||
{
|
||||
RL.setTitle('');
|
||||
};
|
||||
};
|
||||
/**
|
||||
* @constructor
|
||||
* @extends AbstractSettings
|
||||
|
@ -7620,7 +7635,7 @@ AdminSettingsScreen.prototype.onShow = function ()
|
|||
// AbstractSettings.prototype.onShow.call(this);
|
||||
|
||||
RL.setTitle('');
|
||||
};
|
||||
};
|
||||
/**
|
||||
* @constructor
|
||||
* @extends KnoinAbstractBoot
|
||||
|
@ -7940,7 +7955,7 @@ AbstractApp.prototype.bootstart = function ()
|
|||
|
||||
ssm.ready();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends AbstractApp
|
||||
|
@ -8179,7 +8194,7 @@ AdminApp.prototype.bootstart = function ()
|
|||
* @type {AdminApp}
|
||||
*/
|
||||
RL = new AdminApp();
|
||||
|
||||
|
||||
$html.addClass(Globals.bMobileDevice ? 'mobile' : 'no-mobile');
|
||||
|
||||
$window.keydown(Utils.killCtrlAandS).keyup(Utils.killCtrlAandS);
|
||||
|
@ -8230,9 +8245,9 @@ window['__RLBOOT'] = function (fCall) {
|
|||
window['__RLBOOT'] = null;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
if (window.SimplePace) {
|
||||
window.SimplePace.add(10);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}(window, jQuery, ko, crossroads, hasher, _));
|
8
rainloop/v/0.0.0/static/js/admin.min.js
vendored
8
rainloop/v/0.0.0/static/js/admin.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
18
rainloop/v/0.0.0/static/js/app.min.js
vendored
18
rainloop/v/0.0.0/static/js/app.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
vendors/fontastic/fonts/rainloop.eot
vendored
BIN
vendors/fontastic/fonts/rainloop.eot
vendored
Binary file not shown.
5
vendors/fontastic/fonts/rainloop.svg
vendored
5
vendors/fontastic/fonts/rainloop.svg
vendored
|
@ -107,4 +107,9 @@
|
|||
<glyph unicode="" d="M456 343c0 1 0 1 0 1 0 5-2 10-5 13l0 1-40 69c-1 6-6 10-13 10 0 0 0 0-1 0l0 0-283 0 0 0c0 0 0 0 0 0-5 0-9-3-12-7l0 0-42-72 0 0c-3-4-4-9-4-14 0 0 0 0 0-1l0-247c0 0 0 0 0 0 0-12 9-21 20-21 1 0 1 0 1 0l358 0c0 0 0 0 0 0 12 0 21 9 21 21 0 0 0 0 0 0l0 247z m-131-125l-64-90c-1-1-3-2-5-2 0 0 0 0 0 0-2 0-4 1-5 2l-64 90c-1 2-1 4 0 6 1 2 3 3 5 3l30 0 0 81c0 3 3 6 6 6l56 0c3 0 6-3 6-6l0-81 30 0c2 0 4-1 5-3 1-2 1-4 0-6z m-231 147l27 47 270 0 27-47z"/>
|
||||
<glyph unicode="" d="M96 288l64 0 0-32-64 0z m0-64l64 0 0-32-64 0z m384 160l-448 0c-18 0-32-14-32-32l0-224c0-18 14-32 32-32l448 0c18 0 32 14 32 32l0 224c0 18-14 32-32 32m-288-224l-128 0 0 160 128 0z m128 0l-96 0 0 160 32 0 0-128 32 0 0 128 32 0z m128 64l-32 0 0-64-32 0 0 64-32 0 0 96 32 0 0-64 32 0 0 64 32 0z"/>
|
||||
<glyph unicode="" d="M456 428c3-8 2-15-4-20l-141-141 0-212c0-8-4-14-11-17-3-1-5-1-7-1-6 0-10 1-13 5l-73 73c-4 4-6 8-6 13l0 139-141 141c-6 5-7 12-4 20 4 7 9 11 17 11l366 0c8 0 13-4 17-11z"/>
|
||||
<glyph unicode="" d="M148 367l-111-111 111-111 0 74 216 0 0-74 111 111-111 111 0-74-216 0z"/>
|
||||
<glyph unicode="" d="M341 94c0-2-1-4-2-6-2-2-4-3-6-3l-256 0c-2 0-3 1-4 1-1 0-2 1-2 2-1 1-1 1-2 2 0 0 0 1 0 3-1 1-1 2-1 3l0 160-51 0c-5 0-9 2-12 5-3 3-5 7-5 12 0 4 1 8 4 11l85 102c4 4 8 6 13 6 6 0 10-2 13-6l86-102c2-3 4-7 4-11 0-5-2-9-5-12-4-3-8-5-12-5l-51 0 0-102 153 0c3 0 5-1 7-3l42-52c2-1 2-3 2-5z m171 111c0-4-1-8-4-11l-85-103c-4-4-8-6-13-6-6 0-10 2-13 6l-86 103c-2 3-4 7-4 11 0 4 2 8 5 12 4 3 8 5 12 5l51 0 0 102-153 0c-3 0-5 1-7 3l-42 52c-2 1-2 3-2 5 0 2 1 4 2 6 2 2 4 3 6 3l256 0c2 0 3-1 4-1 1 0 2-1 2-2 1-1 1-1 2-2 0-1 0-2 0-3 1-2 1-3 1-3l0-160 51 0c5 0 9-2 12-5 3-4 5-8 5-12z"/>
|
||||
<glyph unicode="" d="M311 155l0-54c0-8-3-15-8-20-5-5-12-8-20-8l-54 0c-8 0-15 3-20 8-5 5-8 12-8 20l0 54c0 8 3 15 8 20 5 5 12 8 20 8l54 0c8 0 15-3 20-8 5-5 8-12 8-20z m0 147l0-55c0-8-3-14-8-20-5-5-12-8-20-8l-54 0c-8 0-15 3-20 8-5 6-8 12-8 20l0 55c0 7 3 14 8 19 5 5 12 8 20 8l54 0c8 0 15-3 20-8 5-5 8-12 8-19z m0 146l0-55c0-7-3-14-8-19-5-6-12-8-20-8l-54 0c-8 0-15 2-20 8-5 5-8 12-8 19l0 55c0 8 3 14 8 19 5 6 12 8 20 8l54 0c8 0 15-2 20-8 5-5 8-11 8-19z"/>
|
||||
<glyph unicode="" d="M341 265c0 2 0 4-2 6l-94 94c-2 1-4 2-6 2-3 0-5-1-6-2l-94-94c-2-2-2-4-2-6 0-3 0-5 2-7 2-1 4-2 6-2l60 0 0-94c0-2 1-4 2-6 2-2 4-2 6-2l52 0c2 0 4 0 6 2 1 2 2 4 2 6l0 94 60 0c2 0 4 1 6 3 1 1 2 3 2 6z m171-77c0-29-10-53-30-73-20-20-44-30-72-30l-291 0c-32 0-61 12-84 35-23 24-35 52-35 85 0 23 6 44 19 64 12 19 29 34 50 44-1 5-1 9-1 11 0 38 14 70 40 97 27 26 59 40 97 40 28 0 53-8 76-23 23-16 40-36 50-62 13 11 28 17 44 17 19 0 35-7 49-20 13-14 20-30 20-49 0-13-4-26-11-37 23-5 42-17 57-36 15-18 22-39 22-63z"/>
|
||||
<glyph unicode="" d="M341 247c0 3 0 5-2 7-2 1-4 2-6 2l-60 0 0 94c0 2-1 4-2 6-2 2-4 2-6 2l-52 0c-2 0-4 0-6-2-1-2-2-4-2-6l0-94-60 0c-2 0-4-1-6-3-2-1-2-3-2-6 0-2 0-4 2-6l94-94c1-1 3-2 6-2 2 0 4 1 6 2l94 94c1 2 2 4 2 6z m171-59c0-29-10-53-30-73-20-20-44-30-72-30l-291 0c-32 0-61 12-84 35-23 24-35 52-35 85 0 23 6 44 19 64 12 19 29 34 50 44-1 5-1 9-1 11 0 38 14 70 40 97 27 26 59 40 97 40 28 0 53-8 76-23 23-16 40-36 50-62 13 11 28 17 44 17 19 0 35-7 49-20 13-14 20-30 20-49 0-13-4-26-11-37 23-5 42-17 57-36 15-18 22-39 22-63z"/>
|
||||
</font></defs></svg>
|
||||
|
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 40 KiB |
BIN
vendors/fontastic/fonts/rainloop.ttf
vendored
BIN
vendors/fontastic/fonts/rainloop.ttf
vendored
Binary file not shown.
BIN
vendors/fontastic/fonts/rainloop.woff
vendored
BIN
vendors/fontastic/fonts/rainloop.woff
vendored
Binary file not shown.
40
vendors/fontastic/icons-reference.html
vendored
40
vendors/fontastic/icons-reference.html
vendored
|
@ -445,6 +445,26 @@ h2{font-size:18px;padding:0 0 21px 5px;margin:45px 0 0 0;text-transform:uppercas
|
|||
<div data-icon="" class="icon"></div>
|
||||
<input type="text" readonly="readonly" value="&#xe063;">
|
||||
</li>
|
||||
<li>
|
||||
<div data-icon="" class="icon"></div>
|
||||
<input type="text" readonly="readonly" value="&#xe064;">
|
||||
</li>
|
||||
<li>
|
||||
<div data-icon="" class="icon"></div>
|
||||
<input type="text" readonly="readonly" value="&#xe065;">
|
||||
</li>
|
||||
<li>
|
||||
<div data-icon="" class="icon"></div>
|
||||
<input type="text" readonly="readonly" value="&#xe066;">
|
||||
</li>
|
||||
<li>
|
||||
<div data-icon="" class="icon"></div>
|
||||
<input type="text" readonly="readonly" value="&#xe067;">
|
||||
</li>
|
||||
<li>
|
||||
<div data-icon="" class="icon"></div>
|
||||
<input type="text" readonly="readonly" value="&#xe068;">
|
||||
</li>
|
||||
</ul>
|
||||
<h2>CSS mapping</h2>
|
||||
<ul class="glyphs css-mapping">
|
||||
|
@ -848,6 +868,26 @@ h2{font-size:18px;padding:0 0 21px 5px;margin:45px 0 0 0;text-transform:uppercas
|
|||
<div class="icon icon-filter"></div>
|
||||
<input type="text" readonly="readonly" value="filter">
|
||||
</li>
|
||||
<li>
|
||||
<div class="icon icon-resize"></div>
|
||||
<input type="text" readonly="readonly" value="resize">
|
||||
</li>
|
||||
<li>
|
||||
<div class="icon icon-sync"></div>
|
||||
<input type="text" readonly="readonly" value="sync">
|
||||
</li>
|
||||
<li>
|
||||
<div class="icon icon-ellipsis-alt"></div>
|
||||
<input type="text" readonly="readonly" value="ellipsis-alt">
|
||||
</li>
|
||||
<li>
|
||||
<div class="icon icon-cloud-up"></div>
|
||||
<input type="text" readonly="readonly" value="cloud-up">
|
||||
</li>
|
||||
<li>
|
||||
<div class="icon icon-cloud-down"></div>
|
||||
<input type="text" readonly="readonly" value="cloud-down">
|
||||
</li>
|
||||
</ul>
|
||||
</div><script type="text/javascript">
|
||||
(function() {
|
||||
|
|
15
vendors/fontastic/styles.css
vendored
15
vendors/fontastic/styles.css
vendored
|
@ -338,3 +338,18 @@
|
|||
.icon-filter:before {
|
||||
content: "\e063";
|
||||
}
|
||||
.icon-resize:before {
|
||||
content: "\e064";
|
||||
}
|
||||
.icon-sync:before {
|
||||
content: "\e065";
|
||||
}
|
||||
.icon-ellipsis-alt:before {
|
||||
content: "\e066";
|
||||
}
|
||||
.icon-cloud-up:before {
|
||||
content: "\e067";
|
||||
}
|
||||
.icon-cloud-down:before {
|
||||
content: "\e068";
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue