Monotone-Parent: 717b1106bd82a838188f97c4b88f9caa35e59586

Monotone-Revision: 459d0175f983b6e31e8957fa80969a4b335469cb

Monotone-Author: flachapelle@inverse.ca
Monotone-Date: 2008-10-03T23:12:11
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
Francis Lachapelle 2008-10-03 23:12:11 +00:00
parent 53a1764c22
commit c8778a820d
9 changed files with 158 additions and 63 deletions

View File

@ -1,3 +1,32 @@
2008-10-03 Francis Lachapelle <flachapelle@inverse.ca>
* UI/MainUI/SOGoUserHomePage.m ([WOResponse
_foldersResponseForResults]): include the value of the attribute value
from user defaults SOGoLDAPContactInfoAttribute.
* UI/Contacts/UIxContactFoldersView.m ([WOActionResults
allContactSearchAction]): return a dictionary with the found
contacts and the original search string.
([WOActionResults contactSearchAction]): idem.
* SoObjects/SOGo/LDAPUserManager.m ([NSArray
_compactAndCompleteContacts:]): add the attribute from user
defaults SOGoLDAPContactInfoAttribute for each returned contact.
* SoObjects/SOGo/LDAPSource.m ([EOQualifier _qualifierForFilter:
]): the filter doesn't match only the beginning of the attribute's
value anymore.
([NSArray _searchAttributes]): add the attribute from user
defaults SOGoLDAPContactInfoAttribute if not already included.
* SoObjects/Contacts/SOGoContactLDAPFolder.m ([NSArray
_flattenedRecords]): added the key "contactInfo" with the value of
the attribute from user defaults SOGoLDAPContactInfoAttribute.
* UI/Contacts/UIxContactFoldersView.m ([NSDictionary
_responseForResults:]): returns a dictionary instead of a
WOResponse. Currently only called by contactSearchAction.
2008-10-03 Cyril Robert <crobert@inverse.ca>
* SoObjects/Mailer/SOGoMailFolder.m
Added copyUIDs and moveUIDs

View File

@ -1,6 +1,6 @@
/* SOGoContactLDAPFolder.m - this file is part of SOGo
*
* Copyright (C) 2006 Inverse inc.
* Copyright (C) 2006-2008 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
@ -24,6 +24,7 @@
#import <Foundation/NSDictionary.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSString.h>
#import <Foundation/NSUserDefaults.h>
#import <NGObjWeb/NSException+HTTP.h>
#import <NGObjWeb/WOApplication.h>
@ -187,8 +188,10 @@
NSEnumerator *oldRecords;
NSDictionary *oldRecord;
NSMutableDictionary *newRecord;
NSString *data;
NSString *data, *contactInfo;
NSUserDefaults *ud;
ud = [NSUserDefaults standardUserDefaults];
newRecords = [[NSMutableArray alloc] initWithCapacity: [records count]];
[newRecords autorelease];
@ -237,6 +240,13 @@
data = @"";
[newRecord setObject: data forKey: @"phone"];
contactInfo = [ud stringForKey: @"SOGoLDAPContactInfoAttribute"];
if ([contactInfo length] > 0) {
data = [oldRecord objectForKey: contactInfo];
if ([data length] > 0)
[newRecord setObject: data forKey: @"contactInfo"];
}
[newRecords addObject: newRecord];
oldRecord = [oldRecords nextObject];
}

View File

@ -23,6 +23,7 @@
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSUserDefaults.h>
#import <EOControl/EOControl.h>
#import <NGLdap/NGLdapConnection.h>
@ -36,6 +37,7 @@
#import "LDAPSource.h"
static NSArray *commonSearchFields;
static NSString *LDAPContactInfoAttribute = nil;
static int timeLimit;
static int sizeLimit;
@ -48,6 +50,7 @@ static int sizeLimit;
if (!commonSearchFields)
{
ud = [NSUserDefaults standardUserDefaults];
LDAPContactInfoAttribute = [ud stringForKey: @"SOGoLDAPContactInfoAttribute"];
sizeLimit = [ud integerForKey: @"SOGoLDAPQueryLimit"];
timeLimit = [ud integerForKey: @"SOGoLDAPQueryTimeout"];
@ -121,6 +124,7 @@ static int sizeLimit;
@"calFBURL", @"proxyAddresses",
nil];
[LDAPContactInfoAttribute retain];
[commonSearchFields retain];
}
}
@ -341,7 +345,7 @@ static int sizeLimit;
NSString *qs, *mailFormat, *fieldFormat;
EOQualifier *qualifier;
fieldFormat = [NSString stringWithFormat: @"(%%@='%@*')", filter];
fieldFormat = [NSString stringWithFormat: @"(%%@='*%@*')", filter];
mailFormat = [[mailFields stringsWithFormat: fieldFormat]
componentsJoinedByString: @" OR "];
@ -394,8 +398,12 @@ static int sizeLimit;
- (NSArray *) _searchAttributes
{
NSUserDefaults *ud;
NSString *contactInfo;
if (!searchAttributes)
{
ud = [NSUserDefaults standardUserDefaults];
searchAttributes = [NSMutableArray new];
if (CNField)
[searchAttributes addObject: CNField];
@ -404,6 +412,12 @@ static int sizeLimit;
[searchAttributes addObjectsFromArray: mailFields];
[searchAttributes addObjectsFromArray: [self _contraintsFields]];
[searchAttributes addObjectsFromArray: commonSearchFields];
// Add SOGoLDAPContactInfoAttribute from user defaults
contactInfo = [ud stringForKey: @"SOGoLDAPContactInfoAttribute"];
if ([contactInfo length] > 0 &&
![searchAttributes containsObject: contactInfo])
[searchAttributes addObject: contactInfo];
}
return searchAttributes;

View File

@ -34,6 +34,7 @@
#import "LDAPUserManager.h"
static NSString *defaultMailDomain = nil;
static NSString *LDAPContactInfoAttribute = nil;
static BOOL defaultMailDomainIsConfigured = NO;
static BOOL forceImapLoginWithEmail = NO;
@ -49,13 +50,16 @@ static BOOL forceImapLoginWithEmail = NO;
defaultMailDomain = [ud stringForKey: @"SOGoDefaultMailDomain"];
[defaultMailDomain retain];
defaultMailDomainIsConfigured = YES;
}
if (!defaultMailDomain)
{
[self warnWithFormat:
@"no domain specified for SOGoDefaultMailDomain,"
@" value set to 'localhost'"];
defaultMailDomain = @"localhost";
if (!defaultMailDomain)
{
[self warnWithFormat:
@"no domain specified for SOGoDefaultMailDomain,"
@" value set to 'localhost'"];
defaultMailDomain = @"localhost";
}
LDAPContactInfoAttribute = [ud stringForKey: @"SOGoLDAPContactInfoAttribute"];
}
if (!forceImapLoginWithEmail)
forceImapLoginWithEmail = [ud boolForKey: @"SOGoForceIMAPLoginWithEmail"];
@ -498,6 +502,11 @@ static BOOL forceImapLoginWithEmail = NO;
email = [userEntry objectForKey: @"xmozillasecondemail"];
if (email && ![emails containsObject: email])
[emails addObject: email];
if ([LDAPContactInfoAttribute length] > 0 &&
[[returnContact objectForKey: LDAPContactInfoAttribute] length] > 0 &&
[userEntry objectForKey: LDAPContactInfoAttribute] != nil)
[returnContact setObject: [userEntry objectForKey: LDAPContactInfoAttribute]
forKey: LDAPContactInfoAttribute];
}
userEntry = [contacts nextObject];

View File

@ -1,6 +1,6 @@
/* UIxContactFoldersView.m - this file is part of SOGo
*
* Copyright (C) 2006 Inverse inc.
* Copyright (C) 2006-2008 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
@ -140,23 +140,23 @@ withSearchOn: (NSString *) contact
return email;
}
- (WOResponse *) _responseForResults: (NSArray *) results
- (NSDictionary *) _responseForResults: (NSArray *) results
{
WOResponse *response;
NSEnumerator *contacts;
NSString *email;
NSString *email, *infoKey, *info;
NSDictionary *contact;
NSMutableArray *formattedContacts;
NSMutableDictionary *formattedContact;
NSUserDefaults *sud;
response = [context response];
formattedContacts = [NSMutableArray arrayWithCapacity: [results count]];
if ([results count] > 0)
{
[response setStatus: 200];
sud = [NSUserDefaults standardUserDefaults];
infoKey = [sud stringForKey: @"SOGoLDAPContactInfoAttribute"];
contacts = [results objectEnumerator];
contact = [contacts nextObject];
formattedContacts = [[NSMutableArray alloc] initWithCapacity: [results count]];
while (contact)
{
email = [contact objectForKey: @"c_email"];
@ -169,17 +169,20 @@ withSearchOn: (NSString *) contact
forKey: @"name"];
[formattedContact setObject: email
forKey: @"email"];
if ([infoKey length] > 0)
{
info = [contact objectForKey: infoKey];
if (info != nil)
[formattedContact setObject: info
forKey: @"contactInfo"];
}
[formattedContacts addObject: formattedContact];
}
contact = [contacts nextObject];
}
[response appendContentString: [formattedContacts jsonRepresentation]];
[formattedContacts release];
}
else
[response setStatus: 404];
return response;
return formattedContacts;
}
- (id <WOActionResults>) allContactSearchAction
@ -187,7 +190,7 @@ withSearchOn: (NSString *) contact
id <WOActionResults> result;
id <SOGoContactFolder> folder;
NSString *searchText, *mail;
NSDictionary *contact;
NSDictionary *contact, *data;
NSArray *folders, *contacts, *descriptors, *sortedContacts;
NSMutableDictionary *uniqueContacts;
unsigned int i, j;
@ -214,21 +217,20 @@ withSearchOn: (NSString *) contact
if ([mail isNotNull] && [uniqueContacts objectForKey: mail] == nil)
[uniqueContacts setObject: contact forKey: [contact objectForKey: @"mail"]];
}
}
result = [context response];
}
if ([uniqueContacts count] > 0)
{
// Sort the contacts by display name
displayNameDescriptor = [[[NSSortDescriptor alloc] initWithKey: @"displayName"
ascending:YES] autorelease];
descriptors = [NSArray arrayWithObjects: displayNameDescriptor, nil];
sortedContacts = [[uniqueContacts allValues] sortedArrayUsingDescriptors: descriptors];
[(WOResponse*)result appendContentString: [sortedContacts jsonRepresentation]];
sortedContacts = [[uniqueContacts allValues] sortedArrayUsingDescriptors: descriptors];
}
else
[(WOResponse*)result setStatus: 404];
data = [NSDictionary dictionaryWithObjectsAndKeys: searchText, @"searchText",
sortedContacts, @"contacts",
nil];
result = [context response];
[(WOResponse*)result appendContentString: [data jsonRepresentation]];
}
else
result = [NSException exceptionWithHTTPStatus: 400
@ -239,16 +241,22 @@ withSearchOn: (NSString *) contact
- (id <WOActionResults>) contactSearchAction
{
NSString *contact;
NSDictionary *contacts, *data;
NSString *searchText;
id <WOActionResults> result;
LDAPUserManager *um;
contact = [self queryParameterForKey: @"search"];
if ([contact length] > 0)
searchText = [self queryParameterForKey: @"search"];
if ([searchText length] > 0)
{
um = [LDAPUserManager sharedUserManager];
result
= [self _responseForResults: [um fetchContactsMatching: contact]];
contacts
= [self _responseForResults: [um fetchContactsMatching: searchText]];
data = [NSDictionary dictionaryWithObjectsAndKeys: searchText, @"searchText",
contacts, @"contacts",
nil];
result = [context response];
[(WOResponse*)result appendContentString: [data jsonRepresentation]];
}
else
result = [NSException exceptionWithHTTPStatus: 400

View File

@ -1,6 +1,6 @@
/* SOGoUserHomePage.m - this file is part of SOGo
*
* Copyright (C) 2007 Inverse inc.
* Copyright (C) 2007, 2008 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
@ -45,6 +45,7 @@
#define intervalSeconds 900 /* 15 minutes */
static NSString *defaultModule = nil;
static NSString *LDAPContactInfoAttribute = nil;
@interface SOGoUserHomePage : UIxComponent
@ -59,6 +60,7 @@ static NSString *defaultModule = nil;
if (!defaultModule)
{
ud = [NSUserDefaults standardUserDefaults];
defaultModule = [ud stringForKey: @"SOGoUIxDefaultModule"];
if (defaultModule)
{
@ -75,6 +77,9 @@ static NSString *defaultModule = nil;
defaultModule = @"Calendar";
[self logWithFormat: @"default module set to '%@'", defaultModule];
[defaultModule retain];
LDAPContactInfoAttribute = [ud stringForKey: @"SOGoLDAPContactInfoAttribute"];
[LDAPContactInfoAttribute retain];
}
}
@ -287,9 +292,11 @@ static NSString *defaultModule = nil;
folders = [results objectForKey: contact];
foldersString
= [self _foldersStringForFolders: [folders objectEnumerator]];
[responseString appendFormat: @"%@:%@:%@%@\n", uid,
[responseString appendFormat: @"%@:%@:%@:%@%@\n", uid,
[contact objectForKey: @"cn"],
[contact objectForKey: @"c_email"],
([LDAPContactInfoAttribute length] > 0 && [contact objectForKey: LDAPContactInfoAttribute] != nil) ?
[contact objectForKey: LDAPContactInfoAttribute] : @"",
foldersString];
}
[response appendContentString: responseString];

View File

@ -69,23 +69,23 @@ function onContactKeydown(event) {
}
else if ($('attendeesMenu').getStyle('visibility') == 'visible') {
attendeesEditor.currentField = this;
if (event.keyCode == 38) { // Up arrow
if (event.keyCode == Event.KEY_UP) { // Up arrow
if (attendeesEditor.selectedIndex > 0) {
var attendees = $('attendeesMenu').select("li");
attendees[attendeesEditor.selectedIndex--].removeClassName("selected");
attendees[attendeesEditor.selectedIndex].addClassName("selected");
this.value = this.confirmedValue = attendees[attendeesEditor.selectedIndex].firstChild.nodeValue.trim();
this.value = this.confirmedValue = attendees[attendeesEditor.selectedIndex].readAttribute("address");
this.uid = attendees[attendeesEditor.selectedIndex].uid;
}
}
else if (event.keyCode == 40) { // Down arrow
else if (event.keyCode == Event.KEY_DOWN) { // Down arrow
var attendees = $('attendeesMenu').select("li");
if (attendees.size() - 1 > attendeesEditor.selectedIndex) {
if (attendeesEditor.selectedIndex >= 0)
attendees[attendeesEditor.selectedIndex].removeClassName("selected");
attendeesEditor.selectedIndex++;
attendees[attendeesEditor.selectedIndex].addClassName("selected");
this.value = this.confirmedValue = attendees[attendeesEditor.selectedIndex].firstChild.nodeValue.trim();
this.value = this.confirmedValue = attendees[attendeesEditor.selectedIndex].readAttribute("address");
this.uid = attendees[attendeesEditor.selectedIndex].uid;
}
}
@ -121,19 +121,27 @@ function performSearchCallback(http) {
var start = input.value.length;
var data = http.responseText.evalJSON(true);
if (data.length > 1) {
if (data.contacts.length > 1) {
$(list.childNodesWithTag("li")).each(function(item) {
item.remove();
});
// Populate popup menu
for (var i = 0; i < data.length; i++) {
var contact = data[i];
for (var i = 0; i < data.contacts.length; i++) {
var contact = data.contacts[i];
var completeEmail = contact["name"] + " <" + contact["email"] + ">";
var node = document.createElement("li");
var node = new Element('li', { 'address': completeEmail });
var matchPosition = completeEmail.toLowerCase().indexOf(data.searchText.toLowerCase());
var matchBefore = completeEmail.substring(0, matchPosition);
var matchText = completeEmail.substring(matchPosition, matchPosition + data.searchText.length);
var matchAfter = completeEmail.substring(matchPosition + data.searchText.length);
list.appendChild(node);
node.uid = contact["uid"];
node.appendChild(document.createTextNode(completeEmail));
node.appendChild(document.createTextNode(matchBefore));
node.appendChild(new Element('strong').update(matchText));
node.appendChild(document.createTextNode(matchAfter));
if (contact["contactInfo"])
node.appendChild(document.createTextNode(" (" + contact["contactInfo"] + ")"));
$(node).observe("mousedown", onAttendeeResultClick);
}
@ -145,7 +153,7 @@ function performSearchCallback(http) {
var heightDiff = window.height() - offset[1];
var nodeHeight = node.getHeight();
if ((data.length * nodeHeight) > heightDiff)
if ((data.contacts.length * nodeHeight) > heightDiff)
// Limit the size of the popup to the window height, minus 12 pixels
height = parseInt(heightDiff/nodeHeight) * nodeHeight - 12 + 'px';
@ -162,9 +170,9 @@ function performSearchCallback(http) {
if (document.currentPopupMenu)
hideMenu(document.currentPopupMenu);
if (data.length == 1) {
if (data.contacts.length == 1) {
// Single result
var contact = data[0];
var contact = data.contacts[0];
if (contact["uid"].length > 0)
input.uid = contact["uid"];
var completeEmail = contact["name"] + " <" + contact["email"] + ">";
@ -192,7 +200,7 @@ function performSearchCallback(http) {
function onAttendeeResultClick(event) {
if (attendeesEditor.currentField) {
attendeesEditor.currentField.uid = this.uid;
attendeesEditor.currentField.value = this.firstChild.nodeValue.trim();
attendeesEditor.currentField.value = $(this).readAttribute("address");
attendeesEditor.currentField.confirmedValue = attendeesEditor.currentField.value;
attendeesEditor.currentField.blur(); // triggers checkAttendee function call
}

View File

@ -25,6 +25,8 @@ function addLineToTree(tree, parent, line) {
var parentNode = nodes[0];
var userInfos = parentNode.split(":");
var email = userInfos[1] + " &lt;" + userInfos[2] + "&gt;";
if (!userInfos[3].empty())
email += " (" + userInfos[3] + ")"; // extra contact info
tree.add(parent, 0, email, 0, '#', userInfos[0], 'person',
'', '',
ResourcesURL + '/abcard.gif',

View File

@ -387,7 +387,7 @@ function onContactKeydown(event) {
if (MailEditor.selectedIndex > 0) {
var contacts = $('contactsMenu').select("li");
contacts[MailEditor.selectedIndex--].removeClassName("selected");
this.value = contacts[MailEditor.selectedIndex].firstChild.nodeValue.trim();
this.value = contacts[MailEditor.selectedIndex].readAttribute("address");
contacts[MailEditor.selectedIndex].addClassName("selected");
}
}
@ -397,7 +397,7 @@ function onContactKeydown(event) {
if (MailEditor.selectedIndex >= 0)
contacts[MailEditor.selectedIndex].removeClassName("selected");
MailEditor.selectedIndex++;
this.value = contacts[MailEditor.selectedIndex].firstChild.nodeValue.trim();
this.value = contacts[MailEditor.selectedIndex].readAttribute("address");
contacts[MailEditor.selectedIndex].addClassName("selected");
}
}
@ -431,20 +431,28 @@ function performSearchCallback(http) {
if (http.status == 200) {
var start = input.value.length;
var data = http.responseText.evalJSON(true);
if (data.length > 1) {
if (data.contacts.length > 1) {
list.select("li").each(function(item) {
item.remove();
});
// Populate popup menu
for (var i = 0; i < data.length; i++) {
var contact = data[i];
for (var i = 0; i < data.contacts.length; i++) {
var contact = data.contacts[i];
var completeEmail = contact["displayName"] + " <" + contact["mail"] + ">";
var node = document.createElement("li");
var node = new Element('li', { 'address': completeEmail });
var matchPosition = completeEmail.toLowerCase().indexOf(data.searchText.toLowerCase());
var matchBefore = completeEmail.substring(0, matchPosition);
var matchText = completeEmail.substring(matchPosition, matchPosition + data.searchText.length);
var matchAfter = completeEmail.substring(matchPosition + data.searchText.length);
list.appendChild(node);
node.uid = contact["c_uid"];
node.appendChild(document.createTextNode(completeEmail));
node.appendChild(document.createTextNode(matchBefore));
node.appendChild(new Element('strong').update(matchText));
node.appendChild(document.createTextNode(matchAfter));
if (contact["contactInfo"])
node.appendChild(document.createTextNode(" (" + contact["contactInfo"] + ")"));
$(node).observe("mousedown", onAddressResultClick);
}
@ -456,7 +464,7 @@ function performSearchCallback(http) {
var heightDiff = window.height() - offset[1];
var nodeHeight = node.getHeight();
if ((data.length * nodeHeight) > heightDiff)
if ((data.contacts.length * nodeHeight) > heightDiff)
// Limit the size of the popup to the window height, minus 12 pixels
height = parseInt(heightDiff/nodeHeight) * nodeHeight - 12 + 'px';
@ -473,9 +481,9 @@ function performSearchCallback(http) {
if (document.currentPopupMenu)
hideMenu(document.currentPopupMenu);
if (data.length == 1) {
if (data.contacts.length == 1) {
// Single result
var contact = data[0];
var contact = data.contacts[0];
if (contact["c_uid"].length > 0)
input.uid = contact["c_uid"];
var completeEmail = contact["displayName"] + " <" + contact["mail"] + ">";
@ -504,7 +512,7 @@ function performSearchCallback(http) {
function onAddressResultClick(event) {
if (MailEditor.currentField) {
MailEditor.currentField.uid = this.uid;
MailEditor.currentField.value = this.firstChild.nodeValue.trim();
MailEditor.currentField.value = $(this).readAttribute("address");
MailEditor.currentField.confirmedValue = MailEditor.currentField.value;
}
}