merge of '419aa9c6f9c2f99bd8f553de4a4cc7e43960b964'

and 'c3411f7017bb6e32f1e36f27be244fc31dc045fb'

Monotone-Parent: 419aa9c6f9c2f99bd8f553de4a4cc7e43960b964
Monotone-Parent: c3411f7017bb6e32f1e36f27be244fc31dc045fb
Monotone-Revision: d8051095a654a9aefa21bff1eaec9672b5ddb438

Monotone-Author: flachapelle@inverse.ca
Monotone-Date: 2011-10-26T19:33:25
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
Francis Lachapelle 2011-10-26 19:33:25 +00:00
commit 7779b20e7c
16 changed files with 205 additions and 29 deletions

View File

@ -1,3 +1,11 @@
2011-10-26 Francis Lachapelle <flachapelle@inverse.ca>
* SoObjects/SOGo/SQLSource.m
(-checkLogin:password:perr:expire:grace:): authentication can be
performed against any database column defined in the new
LoginFieldNames defaults parameter.
(-_lookupContactEntry:considerEmail:): idem.
2011-10-26 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* OpenChange/MAPIStoreMessage.m
@ -14,6 +22,13 @@
* OpenChange/MAPIStoreSOGo.m (sogo_message_create_attachment):
implemented new backend method.
2011-10-25 Francis Lachapelle <flachapelle@inverse.ca>
* UI/MainUI/SOGoRootPage.m (-cookieUsername)
(-cookieWithUsername:): getter/setter for the new SOGoLogin
cookie. This is used for the new "Remember username" checkbox that
appears on the login page.
2011-10-25 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* OpenChange/EOQualifier+MAPIFS.[hm]: now evaluates

17
NEWS
View File

@ -1,4 +1,4 @@
2.0-20111004 (2.0.0beta1 - branched from upcoming v1.3.9)
1.3-201110DD (1.3.9)
---------------------
New Features
- new user defaults SOGoDefaultCalendar to specify which calendar is used when
@ -7,11 +7,26 @@ New Features
automatically added to the free-busy information
- new indicator in the link banner when a vacation message (auto-reply) is active
- new snooze function for events alarms in Web interface
- new "Remember login" checkbox on the login page
- authentication with SQL sources can now be performed on any database column
using the new LoginFieldNames parameter
Enhancements
- added support for the CalDAV move operation
- phone numbers in the contacts web module are now links (tel:)
- revamp of the modules link banner (15-pixel taller)
- updated CKEditor to version 3.6.2
- updated unread and flagged icons in Webmail module
- new dependency on GNUstep 1.23
Bug Fixes
- fixed support for Apple iOS 5
- fixed handling of untagged IMAP responses
- fixed handling of commas in email addresses when composing a message
- fixed creation of clickable links for URLs surrounded by square brackets
- fixed behaviour of combo box for contacts categories
- fixed Swedish translation classes
- fixed bug when setting no ACL on a calendar
1.3-20110726 (1.3.8b)
---------------------

View File

@ -90,7 +90,7 @@
allowsNull = YES;
},
{
columnName = c_telephoneNumber;
columnName = c_telephonenumber;
sqlType = "VARCHAR2(255)";
allowsNull = YES;
},

View File

@ -761,7 +761,7 @@
else
cacheUid = aUID;
jsonUser = [[SOGoCache sharedCache] userAttributesForLogin: cacheUid];
currentUser = [jsonUser objectFromJSONString];
currentUser = [jsonUser objectFromJSONString];
if (!([currentUser objectForKey: @"emails"]
&& [currentUser objectForKey: @"cn"]))
{

View File

@ -38,6 +38,7 @@
NSString *_sourceID;
NSString *_domain;
NSString *_authenticationFilter;
NSArray *_loginFields;
NSArray *_mailFields;
NSString *_imapLoginField;
NSString *_userPasswordAlgorithm;

View File

@ -81,6 +81,7 @@
{
_sourceID = nil;
_authenticationFilter = nil;
_loginFields = nil;
_mailFields = nil;
_userPasswordAlgorithm = nil;
_viewURL = nil;
@ -95,6 +96,7 @@
{
[_sourceID release];
[_authenticationFilter release];
[_loginFields release];
[_mailFields release];
[_userPasswordAlgorithm release];
[_viewURL release];
@ -111,6 +113,7 @@
ASSIGN(_sourceID, [udSource objectForKey: @"id"]);
ASSIGN(_authenticationFilter, [udSource objectForKey: @"authenticationFilter"]);
ASSIGN(_loginFields, [udSource objectForKey: @"LoginFieldNames"]);
ASSIGN(_mailFields, [udSource objectForKey: @"MailFieldNames"]);
ASSIGN(_userPasswordAlgorithm, [udSource objectForKey: @"userPasswordAlgorithm"]);
ASSIGN(_imapLoginField, [udSource objectForKey: @"IMAPLoginFieldName"]);
@ -227,9 +230,31 @@
channel = [cm acquireOpenChannelForURL: _viewURL];
if (channel)
{
qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"c_uid"
operatorSelector: EOQualifierOperatorEqual
value: _login];
if (_loginFields)
{
NSMutableArray *qualifiers;
NSString *field;
EOQualifier *loginQualifier;
int i;
qualifiers = [NSMutableArray arrayWithCapacity: [_loginFields count]];
for (i = 0; i < [_loginFields count]; i++)
{
field = [_loginFields objectAtIndex: i];
loginQualifier = [[EOKeyValueQualifier alloc] initWithKey: field
operatorSelector: EOQualifierOperatorEqual
value: _login];
[loginQualifier autorelease];
[qualifiers addObject: loginQualifier];
}
qualifier = [[EOOrQualifier alloc] initWithQualifierArray: qualifiers];
}
else
{
qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"c_uid"
operatorSelector: EOQualifierOperatorEqual
value: _login];
}
[qualifier autorelease];
sql = [NSMutableString stringWithFormat: @"SELECT c_password"
@" FROM %@"
@ -353,12 +378,14 @@
considerEmail: (BOOL) b
{
NSMutableDictionary *response;
NSMutableArray *qualifiers;
EOAdaptorChannel *channel;
EOQualifier *qualifier;
EOQualifier *loginQualifier, *qualifier;
GCSChannelManager *cm;
NSMutableString *sql;
NSString *value;
NSString *value, *field;
NSException *ex;
int i;
response = nil;
@ -367,25 +394,65 @@
channel = [cm acquireOpenChannelForURL: _viewURL];
if (channel)
{
if (!b)
sql = [NSMutableString stringWithFormat: (@"SELECT *"
@" FROM %@"
@" WHERE c_uid = '%@'"),
[_viewURL gcsTableName], theID];
else
{
sql = [NSMutableString stringWithFormat: (@"SELECT *"
@" FROM %@"
@" WHERE c_uid = '%@' OR"
@" LOWER(mail) = '%@'"),
[_viewURL gcsTableName], theID, [theID lowercaseString]];
qualifiers = [NSMutableArray arrayWithCapacity: [_loginFields count] + 1];
// Always compare against the c_uid field
loginQualifier = [[EOKeyValueQualifier alloc] initWithKey: @"c_uid"
operatorSelector: EOQualifierOperatorEqual
value: theID];
[loginQualifier autorelease];
[qualifiers addObject: loginQualifier];
if (_loginFields)
{
for (i = 0; i < [_loginFields count]; i++)
{
field = [_loginFields objectAtIndex: i];
if ([field caseInsensitiveCompare: @"c_uid"] != NSOrderedSame)
{
loginQualifier = [[EOKeyValueQualifier alloc] initWithKey: field
operatorSelector: EOQualifierOperatorEqual
value: theID];
[loginQualifier autorelease];
[qualifiers addObject: loginQualifier];
}
}
}
if (b)
{
// Always compare againts the mail field
loginQualifier = [[EOKeyValueQualifier alloc] initWithKey: @"mail"
operatorSelector: EOQualifierOperatorEqual
value: [theID lowercaseString]];
[loginQualifier autorelease];
[qualifiers addObject: loginQualifier];
if (_mailFields && [_mailFields count] > 0)
if (_mailFields)
{
[sql appendString: [self _whereClauseFromArray: _mailFields value: [theID lowercaseString] exact: YES]];
}
for (i = 0; i < [_mailFields count]; i++)
{
field = [_mailFields objectAtIndex: i];
if ([field caseInsensitiveCompare: @"mail"] != NSOrderedSame
&& ![_loginFields containsObject: field])
{
loginQualifier = [[EOKeyValueQualifier alloc] initWithKey: field
operatorSelector: EOQualifierOperatorEqual
value: [theID lowercaseString]];
[loginQualifier autorelease];
[qualifiers addObject: loginQualifier];
}
}
}
}
sql = [NSMutableString stringWithFormat: @"SELECT *"
@" FROM %@"
@" WHERE ",
[_viewURL gcsTableName]];
qualifier = [[EOOrQualifier alloc] initWithQualifierArray: qualifiers];
[qualifier _gcsAppendToString: sql];
ex = [channel evaluateExpressionX: sql];
if (!ex)
{

View File

@ -5,6 +5,7 @@
"Username:" = "Username:";
"Password:" = "Password:";
"Domain:" = "Domain:";
"Remember username" = "Remember username";
"Connect" = "Connect";

View File

@ -5,6 +5,7 @@
"Username:" = "Nom d'utilisateur :";
"Password:" = "Mot de passe :";
"Domain:" = "Domaine :";
"Remember username" = "Se souvenir de moi";
"Connect" = "Connexion";

View File

@ -28,6 +28,7 @@
@interface SOGoRootPage : UIxComponent
{
id item;
NSString *cookieLogin;
}
@end

View File

@ -58,6 +58,22 @@
@implementation SOGoRootPage
- (id) init
{
if ((self = [super init]))
{
cookieLogin = nil;
}
return self;
}
- (void) dealloc
{
[cookieLogin release];
[super dealloc];
}
/* accessors */
- (NSString *) connectURL
@ -65,6 +81,25 @@
return [NSString stringWithFormat: @"%@/connect", [self applicationPath]];
}
- (NSString *) cookieUsername
{
NSString *value;
if (cookieLogin == nil)
{
value = [[context request] cookieValueForKey: @"SOGoLogin"];
cookieLogin = [value isNotNull]? [value stringByDecodingBase64] : @"";
[cookieLogin retain];
}
return cookieLogin;
}
- (BOOL) rememberLogin
{
return ([[self cookieUsername] length]);
}
- (WOCookie *) _cookieWithUsername: (NSString *) username
andPassword: (NSString *) password
forAuthenticator: (SOGoWebAuthenticator *) auth
@ -105,6 +140,32 @@
return authCookie;
}
- (WOCookie *) _cookieWithUsername: (NSString *) username
{
WOCookie *loginCookie;
NSString *appName;
NSCalendarDate *date;
appName = [[context request] applicationName];
if (username)
{
loginCookie = [WOCookie cookieWithName: @"SOGoLogin"
value: [username stringByEncodingBase64]];
}
else
{
loginCookie = [WOCookie cookieWithName: @"SOGoLogin"
value: nil];
date = [NSCalendarDate calendarDate];
[date setTimeZone: [NSTimeZone timeZoneWithAbbreviation: @"GMT"]];
[loginCookie setExpires: [date yesterday]];
}
[loginCookie setPath: [NSString stringWithFormat: @"/%@/", appName]];
return loginCookie;
}
- (WOCookie *) _casLocationCookie: (BOOL) cookieReset
{
WOCookie *locationCookie;
@ -155,7 +216,7 @@
SOGoPasswordPolicyError err;
int expire, grace;
BOOL b;
BOOL rememberLogin, b;
err = PolicyNoError;
expire = grace = -1;
@ -166,6 +227,7 @@
username = [request formValueForKey: @"userName"];
password = [request formValueForKey: @"password"];
language = [request formValueForKey: @"language"];
rememberLogin = [[request formValueForKey: @"rememberLogin"] boolValue];
domain = [request formValueForKey: @"domain"];
if ((b = [auth checkLogin: username password: password domain: &domain
@ -220,6 +282,11 @@
response = [self _responseWithLDAPPolicyError: err];
}
if (rememberLogin)
[response addCookie: [self _cookieWithUsername: username]];
else
[response addCookie: [self _cookieWithUsername: nil]];
return response;
}

View File

@ -38,7 +38,7 @@
<td id="loginCell" width="230">
<label><var:string label:value="Username:"/><br/>
<input class="textField" id="userName" name="userName"
type="text" var:value="userName" /></label>
type="text" var:value="cookieUsername" /></label>
<label><var:string label:value="Password:"/><br/>
<input class="textField" id="password"
name="password" type="password" var:value="password" /></label>
@ -61,6 +61,7 @@
string="item"
/></label>
</var:if>
<label><input id="rememberLogin" type="checkbox" class="checkBox" var:checked="rememberLogin"/> <var:string label:value="Remember username"/></label>
<label>
<a href="#" class="button" id="submit" name="submit">
<span><var:string label:value="Connect" /></span></a>

View File

@ -94,7 +94,7 @@ DIV#administrationModules UL LI
DIV#rightPanel
{
position: absolute;
top: 6em;
top: 80px;
left: 15em;
margin-left: 5px;
right: 0px;

View File

@ -29,7 +29,6 @@ function initLogin() {
submit.observe("click", onLoginClick);
var userName = $("userName");
userName.focus();
userName.observe("keydown", onFieldKeyDown);
var passw = $("password");
@ -40,6 +39,11 @@ function initLogin() {
var submitBtn = $("submit");
submitBtn.disabled = false;
if (userName.value.empty())
userName.focus();
else
passw.focus();
}
function onFieldKeyDown(event) {
@ -82,6 +86,9 @@ function onLoginClick(event) {
: ("&language=" + language.value));
if (domain)
parameters += "&domain=" + domain.value;
if ($("rememberLogin").checked)
parameters += "&rememberLogin=1";
/// Discarded as it seems to create a cookie for nothing. To discard
// a cookie in JS, have a look here: http://www.quirksmode.org/js/cookies.html
//document.cookie = "";\

View File

@ -10,7 +10,7 @@ Group: Productivity/Groupware
Source: SOGo-%{sogo_version}.tar.gz
Prefix: /usr
AutoReqProv: off
Requires: gnustep-base, sope%{sope_major_version}%{sope_minor_version}-core, httpd, sope%{sope_major_version}%{sope_minor_version}-core, sope%{sope_major_version}%{sope_minor_version}-appserver, sope%{sope_major_version}%{sope_minor_version}-ldap, sope%{sope_major_version}%{sope_minor_version}-cards >= %{sogo_version}, sope%{sope_major_version}%{sope_minor_version}-gdl1-contentstore >= %{sogo_version}, sope%{sope_major_version}%{sope_minor_version}-sbjson, memcached, libmemcached
Requires: gnustep-base >= 1.23, sope%{sope_major_version}%{sope_minor_version}-core, httpd, sope%{sope_major_version}%{sope_minor_version}-core, sope%{sope_major_version}%{sope_minor_version}-appserver, sope%{sope_major_version}%{sope_minor_version}-ldap, sope%{sope_major_version}%{sope_minor_version}-cards >= %{sogo_version}, sope%{sope_major_version}%{sope_minor_version}-gdl1-contentstore >= %{sogo_version}, sope%{sope_major_version}%{sope_minor_version}-sbjson, memcached, libmemcached
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}
BuildPreReq: gcc-objc gnustep-base gnustep-make sope%{sope_major_version}%{sope_minor_version}-appserver-devel sope%{sope_major_version}%{sope_minor_version}-core-devel sope%{sope_major_version}%{sope_minor_version}-ldap-devel sope%{sope_major_version}%{sope_minor_version}-mime-devel sope%{sope_major_version}%{sope_minor_version}-xml-devel sope%{sope_major_version}%{sope_minor_version}-gdl1-devel sope%{sope_major_version}%{sope_minor_version}-sbjson-devel libmemcached-devel samba4 openchange