See ChangeLog

Monotone-Parent: ed15d4f340fd47347d881c8826eb40a2dc22763d
Monotone-Revision: d669b0b3e321e22c68d092f984d543560ae1af0e

Monotone-Author: flachapelle@inverse.ca
Monotone-Date: 2012-01-12T20:01:34
maint-2.0.2
Francis Lachapelle 2012-01-12 20:01:34 +00:00
parent 335ba606b4
commit ccf847f555
19 changed files with 886 additions and 36 deletions

View File

@ -1,3 +1,36 @@
2012-01-12 Francis Lachapelle <flachapelle@inverse.ca>
* SoObjects/SOGo/SOGoSource.h (-bindDN, -bindPassword)
(-MSExchangeHostname): new accessors to the SOGoDNSource protocol.
* SoObjects/SOGo/LDAPSource.m (-_convertLDAPEntryToContact:):
added a reference to the instance source in the returned dictionary.
* SoObjects/SOGo/SOGoUserManager.m
(-_compactAndCompleteContacts:): keep the source instance in the
returned dictionary.
* UI/MainUI/SOGoUserHomePage.m (-readFreeBusyAction): the http
post can now include an optional "uid" parameter to perform the
freebusy lookup on the user corresponding to the specified
uid. This covers the special case where we want to query a user
from a contact source (not an authentication source) and for which
external freebusy information is available (currently limited to a
Microsoft Exchange server with Web Services enabled).
* SoObjects/Appointments/SOGoFreeBusyObject.m
(-fetchFreeBusyInfosFrom:to:forUser:): new method currently
limited perform a SOAP request to a MS Exhange server to retrieve
the freebusy information of a user.
* UI/WebServerResources/UIxAttendeesEditor.js
(performSearchCallback): if a matching contact has the
"isMSExchange" attribute, prefix the uid with the login uid.
(_performAjaxRequest): query the freebusy information from the
login user (/SOGo/so/<loginuser>/freebusy.ifb/ajaxRead?uid=<contact>)
when a contact uid is specified. Otherwise, perform the query on
the user instance as usual (/SOGo/so/<contactuser>/freebusy.ifb/ajaxRead).
2012-01-10 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* SoObjects/Appointments/SOGoAppointmentObject.m

View File

@ -42,10 +42,15 @@ Appointments_OBJC_FILES = \
SOGoAptMailUpdate.m \
SOGoAptMailReceipt.m \
\
SOGoEMailAlarmsManager.m
SOGoEMailAlarmsManager.m \
\
MSExchangeFreeBusySOAPRequest.m \
MSExchangeFreeBusy.m
Appointments_RESOURCE_FILES += \
product.plist \
\
MSExchangeFreeBusySOAPRequest.wo
Appointments_LANGUAGES = BrazilianPortuguese Catalan Czech Danish Dutch English French German Hungarian Icelandic Italian NorwegianBokmal NorwegianNynorsk Polish Russian SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
@ -53,6 +58,7 @@ Appointments_LOCALIZED_RESOURCE_FILES = Localizable.strings
ADDITIONAL_INCLUDE_DIRS += -I../../SOPE/
ADDITIONAL_LIB_DIRS += -L../../SOPE/GDLContentStore/obj/
ADDITIONAL_LDFLAGS += -lcurl -lgnutls
-include GNUmakefile.preamble
include $(GNUSTEP_MAKEFILES)/wobundle.make

View File

@ -0,0 +1,69 @@
/* MSExchangeFreeBusy.h - this file is part of SOGo
*
* Copyright (C) 2012 Inverse inc.
*
* Author: Francis Lachapelle <flachapelle@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef MSEXCHANGEFREEBUSY_H
#define MSEXCHANGEFREEBUSY_H
#include <Foundation/Foundation.h>
@class MSExchangeFreeBusyResponse;
@class MSExchangeFreeBusyView;
@interface MSExchangeFreeBusy : NSObject
{
NSMutableData *curlBody;
MSExchangeFreeBusyResponse *response;
}
- (size_t) curlWritePtr: (void *) inPtr
size: (size_t) inSize
number: (size_t) inNumber;
- (NSArray *) fetchFreeBusyInfosFrom: (NSCalendarDate *) startDate
to: (NSCalendarDate *) endDate
forEmail: (NSString *) email
inSource: (NSObject <SOGoDNSource> *) source
// fromServer: (NSString *) hostname
inContext: (WOContext *) context;
@end
@interface MSExchangeFreeBusyResponse : NSObject
{
MSExchangeFreeBusyView *view;
}
- (MSExchangeFreeBusyView *) view;
@end
@interface MSExchangeFreeBusyView : NSObject
{
NSString *freeBusyViewType;
NSString *mergedFreeBusy;
}
- (NSArray *) infosFrom: (NSCalendarDate *) startDate
to: (NSCalendarDate *) endDate;
@end
#endif /* MSEXCHANGEFREEBUSY_H */

View File

@ -0,0 +1,350 @@
/* MSExchangeFreeBusy.m - this file is part of SOGo
*
* Copyright (C) 2012 Inverse inc.
*
* Author: Francis Lachapelle <flachapelle@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <NGObjWeb/WOApplication.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WOResponse.h>
#import <NGExtensions/NSObject+Logs.h>
#import <SaxObjC/SaxObjC.h>
#import <SaxObjC/SaxMethodCallHandler.h>
#import <SaxObjC/SaxObjectDecoder.h>
#import <SaxObjC/SaxXMLReaderFactory.h>
#import <curl/curl.h>
#import <SOGo/SOGoSource.h>
#import "MSExchangeFreeBusySOAPRequest.h"
#import "MSExchangeFreeBusy.h"
size_t curlBodyFunction(void *ptr, size_t size, size_t nmemb, void *inSelf)
{
return [(MSExchangeFreeBusy *)inSelf curlWritePtr:ptr size:size number:nmemb];
}
@implementation MSExchangeFreeBusy
- (id) init
{
if ((self = [super init]))
{
curlBody = [[NSMutableData alloc] init];
}
return self;
}
- (void) dealloc
{
[curlBody release];
[super dealloc];
}
- (size_t) curlWritePtr:(void *)inPtr
size:(size_t)inSize
number:(size_t)inNumber
{
size_t written = inSize*inNumber;
NSData *data = [NSData dataWithBytes:inPtr length:written];
[curlBody appendData: data];
return written;
}
/**
* Fetch the user availability by sending a SOAP request to a MS Exchange server (EWS).
* @param startDate the beginning of the covered period
* @param endDate the ending of the covered period
* @param email the address of the user to query
* @param source the SOGo source of the user
* @param context the current WO context
* @return an array of dictionaries containing the start and end dates of each busy period
* @see <http://msdn.microsoft.com/en-us/library/aa563800(v=EXCHG.140).aspx>
*/
- (NSArray *) fetchFreeBusyInfosFrom: (NSCalendarDate *) startDate
to: (NSCalendarDate *) endDate
forEmail: (NSString *) email
inSource: (NSObject <SOGoDNSource> *) source
inContext: (WOContext *) context
{
static id<NSObject,SaxXMLReader> parser = nil;
static SaxObjectDecoder *sax = nil;
MSExchangeFreeBusySOAPRequest *soapRequest;
MSExchangeFreeBusyResponse *freeBusyResponse;
NSString *rawRequest, *url, *body, *hostname, *httpauth, *authname, *password;
NSArray *infos = nil;
NSDictionary *root;
CURL *curl;
struct curl_slist *headerlist=NULL;
CURLcode rc;
char error[CURL_ERROR_SIZE];
// Construct SOAP GetUserAvailabilityRequest from .wo template
soapRequest = [[WOApplication application] pageWithName: @"MSExchangeFreeBusySOAPRequest"
inContext: context];
[soapRequest setAddress: email
from: startDate
to: endDate];
rawRequest = [[soapRequest generateResponse] contentAsString];
if ([rawRequest length])
{
// Prepare HTTPS post using libcurl
curl_global_init(CURL_GLOBAL_SSL);
curl = curl_easy_init();
headerlist = curl_slist_append(headerlist, "Content-Type: text/xml; charset=utf-8");
if (curl)
{
hostname = [source MSExchangeHostname];
authname = [source lookupLoginByDN: [source bindDN]];
password = [source bindPassword];
error[0] = 0;
if ([authname length] && [password length])
{
httpauth = [NSString stringWithFormat: @"%@:%@", authname, password];
curl_easy_setopt(curl, CURLOPT_USERPWD, [httpauth UTF8String]);
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
}
url = [NSString stringWithFormat: @"https://%@/ews/Exchange.asmx", hostname];
curl_easy_setopt(curl, CURLOPT_URL, [url UTF8String]);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, [rawRequest UTF8String]);
//curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curlHeaderFunction);
//curl_easy_setopt(curl, CURLOPT_HEADER, 1);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlBodyFunction);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, self);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error);
// Perform SOAP request
rc = curl_easy_perform(curl);
if (rc != 0)
[self errorWithFormat: @"CURL error while accessing %@ (%d): ", url, rc, [NSString stringWithCString: error]];
curl_easy_cleanup(curl);
curl_slist_free_all(headerlist);
if ([curlBody length])
{
// Parse SOAP response
if (parser == nil)
{
parser = [[SaxXMLReaderFactory standardXMLReaderFactory]
createXMLReaderForMimeType:@"text/xml"];
[parser retain];
}
if (sax == nil && parser != nil)
{
sax = [[SaxObjectDecoder alloc] initWithMappingAtPath:@"./MSExchangeFreeBusySOAPResponseMap.plist"];
[parser setContentHandler:sax];
//[parser setErrorHandler:sax];
}
body = [[NSString alloc] initWithData:curlBody encoding:NSASCIIStringEncoding];
[body autorelease];
[parser parseFromSource: body];
root = [sax rootObject];
freeBusyResponse = [[root objectForKey: @"Body"] objectForKey: @"GetUserAvailabilityResponse"];
// Extract busy periods
infos = [[freeBusyResponse view] infosFrom: startDate to: endDate];
}
}
}
return infos;
}
@end
@implementation MSExchangeFreeBusyResponse
- (id) init
{
if ((self = [super init]))
{
view = nil;
}
return self;
}
- (void) dealloc
{
[view release];
[super dealloc];
}
- (MSExchangeFreeBusyView *) view
{
return self->view;
}
- (void) setFreeBusyResponseArray: (NSDictionary *) _value
{
NSString *responseCode;
NSArray *responses;
NSDictionary *response;
view = nil;
responses = (NSArray *) [_value objectForKey: @"responses"];
if ([responses count] != 1)
{
[self errorWithFormat: @"unexpected number of responses (%i) from SOAP request", [responses count]];
}
else
{
response = [responses objectAtIndex: 0];
responseCode = [[response objectForKey: @"ResponseMessage"] objectForKey: @"ResponseCode"];
if ([responseCode compare: @"NoError"] == NSOrderedSame)
{
view = [response objectForKey: @"FreeBusyView"];
[view retain];
}
}
[self logWithFormat: @"SOAP Response: %@", self->view];
}
@end
@implementation MSExchangeFreeBusyView
- (id) init
{
if ((self = [super init]))
{
freeBusyViewType = nil;
mergedFreeBusy = nil;
}
return self;
}
- (void) dealloc
{
[freeBusyViewType release];
[mergedFreeBusy release];
[super dealloc];
}
- (void) setFreeBusyViewType: (NSString *) _value
{
ASSIGN(freeBusyViewType, _value);
}
- (void) setMergedFreeBusy: (NSString *) _value
{
ASSIGN(mergedFreeBusy, _value);
}
/**
* Parse the "DetailedMerged" representation of the freebusy information and
* extract the busy periods.
* @param startDate the beginning of the covered period
* @param endDate the ending of the covered period
* @return an array of dictionaries containing the start and end dates of each busy period
* @see <http://msdn.microsoft.com/en-us/library/aa565898(v=EXCHG.140).aspx>
*/
- (NSArray *) infosFrom: (NSCalendarDate *) startDate
to: (NSCalendarDate *) endDate
{
NSMutableArray *infos;
NSCalendarDate *currentDate, *currentStartDate, *currentEndDate;
unsigned int count;
infos = [NSMutableArray array];
currentStartDate = nil;
currentDate = startDate;
count = 0;
while (([currentDate compare: endDate] == NSOrderedAscending ||
[currentDate compare: endDate] == NSOrderedSame) &&
[mergedFreeBusy length] > count)
{
switch ([mergedFreeBusy characterAtIndex: count])
{
case '0': // Free
if (currentStartDate)
{
currentEndDate = currentDate;
[infos addObject: [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool: YES], @"c_isopaque",
currentStartDate, @"startDate",
currentEndDate, @"endDate", nil]];
[self debugWithFormat: @"Busy period from %@ to %@", currentStartDate, currentEndDate];
currentStartDate = nil;
}
break;
case '1': // Tentative
case '2': // Busy
case '3': // Out of Office
if (currentStartDate == nil)
currentStartDate = currentDate;
break;
}
count++;
currentDate = [currentDate dateByAddingYears: 0 months: 0 days: 0
hours: 0 minutes: 15 seconds: 0];
}
if (currentStartDate)
{
currentEndDate = currentDate;
[infos addObject: [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool: YES], @"c_isopaque",
currentStartDate, @"startDate",
currentEndDate, @"endDate", nil]];
[self debugWithFormat: @"Busy period from %@ to %@", currentStartDate, currentEndDate];
}
return infos;
}
- (NSString *) description
{
NSMutableString *s;
s = [NSMutableString stringWithCapacity: 64];
[s appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
if (freeBusyViewType)
[s appendFormat:@" freeBusyViewType='%@'", freeBusyViewType];
if (mergedFreeBusy)
[s appendFormat:@" mergedFreeBusy='%@'", mergedFreeBusy];
[s appendString:@">"];
return s;
}
@end

View File

@ -0,0 +1,52 @@
/*
Copyright (C) 2012 Inverse inc.
This file is part of SOGo.
SOGo is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
SOGo is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public
License along with SOGo; see the file COPYING. If not, write to the
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
#ifndef __Appointments_MSExchangeFreeBusySOAPRequest_H_
#define __Appointments_MSExchangeFreeBusySOAPRequest_H_
#include <NGObjWeb/SoComponent.h>
@class NSCalendarDate;
@class NSMutableDictionary;
@class NSString;
@class NSTimeZone;
@class iCalEvent;
/*
* NOTE: We inherit from SoComponent in order to get the correct
* resourceManager required for this product
*/
@interface MSExchangeFreeBusySOAPRequest : SoComponent
{
NSString *address;
NSTimeZone *timeZone;
NSCalendarDate *startDate;
NSCalendarDate *endDate;
int interval;
}
- (void) setAddress: (NSString *) _address
from: (NSCalendarDate *) _startDate
to: (NSCalendarDate *) _endDate;
@end
#endif /* __Appointments_MSExchangeFreeBusySOAPRequest_H_ */

View File

@ -0,0 +1,105 @@
/*
Copyright (C) 2012 Inverse inc.
This file is part of SOGo.
SOGo is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
SOGo is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public
License along with SOGo; see the file COPYING. If not, write to the
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
#import <Foundation/NSCharacterSet.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSTimeZone.h>
#import <NGObjWeb/WOActionResults.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WOResponse.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGCards/iCalEvent.h>
#import <NGCards/iCalPerson.h>
#import <SOGo/NSDictionary+Utilities.h>
#import <SOGo/NSObject+Utilities.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoDateFormatter.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
#import "MSExchangeFreeBusySOAPRequest.h"
@implementation MSExchangeFreeBusySOAPRequest
- (id) init
{
if ((self = [super init]))
{
address = nil;
timeZone = [NSTimeZone timeZoneWithAbbreviation: @"GMT"];
[timeZone retain];
startDate = nil;
endDate = nil;
interval = 15;
}
return self;
}
- (void) dealloc
{
[address release];
[timeZone release];
[startDate release];
[endDate release];
[super dealloc];
}
- (void) setAddress: (NSString *) newAddress
from: (NSCalendarDate *) newStartDate
to: (NSCalendarDate *) newEndDate
{
ASSIGN(address, newAddress);
ASSIGN(startDate, newStartDate);
ASSIGN(endDate, newEndDate);
[startDate setTimeZone: timeZone];
[endDate setTimeZone: timeZone];
}
- (NSString *) serverVersion
{
return @"Exchange2007_SP1";
}
- (NSString *) address
{
return address;
}
- (NSString *) startTime
{
return [startDate descriptionWithCalendarFormat: @"%Y-%m-%dT%H:%M:%S"];
}
- (NSString *) endTime
{
return [endDate descriptionWithCalendarFormat: @"%Y-%m-%dT%H:%M:%S"];
}
- (NSString *) interval
{
return [NSString stringWithFormat: @"%i", interval];
}
@end

View File

@ -0,0 +1,45 @@
<?xml version="1.0" standalone="yes"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
<soap:Header>
<t:RequestServerVersion Version="<#serverVersion/>"/>
</soap:Header>
<soap:Body>
<GetUserAvailabilityRequest xmlns="http://schemas.microsoft.com/exchange/services/2006/messages"
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
<t:TimeZone xmlns="http://schemas.microsoft.com/exchange/services/2006/types">
<Bias>0</Bias>
<StandardTime>
<Bias>0</Bias>
<Time>00:00:00</Time>
<DayOrder>1</DayOrder>
<Month>1</Month>
<DayOfWeek>Sunday</DayOfWeek>
</StandardTime>
<DaylightTime>
<Bias>0</Bias>
<Time>00:00:00</Time>
<DayOrder>1</DayOrder>
<Month>1</Month>
<DayOfWeek>Sunday</DayOfWeek>
</DaylightTime>
</t:TimeZone>
<MailboxDataArray>
<t:MailboxData>
<t:Email>
<t:Address><#address/></t:Address>
</t:Email>
<t:AttendeeType>Required</t:AttendeeType>
<t:ExcludeConflicts>false</t:ExcludeConflicts>
</t:MailboxData>
</MailboxDataArray>
<t:FreeBusyViewOptions>
<t:TimeWindow>
<t:StartTime><#startTime/></t:StartTime>
<t:EndTime><#endTime/></t:EndTime>
</t:TimeWindow>
<t:MergedFreeBusyIntervalInMinutes>15</t:MergedFreeBusyIntervalInMinutes>
<t:RequestedView>DetailedMerged</t:RequestedView>
</t:FreeBusyViewOptions>
</GetUserAvailabilityRequest>
</soap:Body>
</soap:Envelope>

View File

@ -0,0 +1,24 @@
serverVersion: WOString {
value = serverVersion;
escapeHTML = NO;
}
address: WOString {
value = address;
escapeHTML = NO;
}
startTime: WOString {
value = startTime;
escapeHTML = NO;
}
endTime: WOString {
value = endTime;
escapeHTML = NO;
}
interval: WOString {
value = interval;
escapeHTML = NO;
}

View File

@ -0,0 +1,63 @@
{ /* -*-java-*- */
"http://schemas.xmlsoap.org/soap/envelope/" = {
Envelope = {
class = NSMutableDictionary;
};
Header = {
class = NSMutableDictionary;
attributes = {
serverVersionInfo = ServerVersionInfo;
};
};
Body = {
class = NSMutableDictionary;
};
};
"http://schemas.microsoft.com/exchange/services/2006/messages" = {
GetUserAvailabilityResponse = {
class = MSExchangeFreeBusyResponse;
attributes = {
FreeBusyResponseArray = FreeBusyResponseArray;
};
};
FreeBusyResponseArray = {
class = NSMutableDictionary;
ToManyRelationships = {
responses = ( FreeBusyResponse );
};
};
ResponseMessage = {
class = NSMutableDictionary;
};
ResponseCode = {
class = NSString;
};
FreeBusyResponse = {
class = NSMutableDictionary;
};
FreeBusyView = {
class = MSExchangeFreeBusyView;
attributes = {
FreeBusyViewType = freeBusyViewType;
MergedFreeBusy = mergedFreeBusy;
};
};
};
"http://schemas.microsoft.com/exchange/services/2006/types" = {
FreeBusyViewType = {
class = NSString;
};
MergedFreeBusy = {
class = NSString;
};
};
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2007-2011 Inverse inc.
Copyright (C) 2007-2012 Inverse inc.
Copyright (C) 2000-2004 SKYRIX Software AG
This file is part of SOGo
@ -38,8 +38,6 @@
@class iCalPerson;
@interface SOGoFreeBusyObject : SOGoObject
{
}
/* accessors */
@ -55,7 +53,9 @@
- (NSArray *) fetchFreeBusyInfosFrom: (NSCalendarDate *) _startDate
to: (NSCalendarDate *) _endDate;
- (NSArray *) fetchFreeBusyInfosFrom: (NSCalendarDate *) startDate
to: (NSCalendarDate *) endDate
forUser: (NSString *) uid;
@end
#endif /* __Appointments_SOGoFreeBusyObject_H_ */

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2007-2011 Inverse inc.
Copyright (C) 2007-2012 Inverse inc.
Copyright (C) 2000-2004 SKYRIX Software AG
This file is part of SOGo
@ -21,10 +21,12 @@
*/
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSData.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSValue.h>
#import <NGObjWeb/WOApplication.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WOResponse.h>
#import <NGExtensions/NSCalendarDate+misc.h>
@ -34,6 +36,7 @@
#import <SOGo/SOGoBuild.h>
#import <SOGo/SOGoDomainDefaults.h>
#import <SOGo/SOGoSource.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
#import <SOGo/SOGoUserManager.h>
@ -42,6 +45,8 @@
#import "SOGoAppointmentFolder.h"
#import "SOGoAppointmentFolders.h"
#import "MSExchangeFreeBusy.h"
#import "SOGoFreeBusyObject.h"
@interface SOGoFreeBusyObject (PrivateAPI)
@ -240,6 +245,60 @@
to: _endDate];
}
/**
* Fetch freebusy information for a user that exists in a contact source
* (not an authentication source) for which freebusy information is available
* (currently limited to a Microsoft Exchange server with Web Services enabled).
* @param startDate the beginning of the covered period
* @param endDate the ending of the covered period
* @param uid the ID of the user within the current domain
* @return an array of dictionaries containing the start and end dates of each busy period
* @see MSExchangeFreeBusy.m
*/
- (NSArray *) fetchFreeBusyInfosFrom: (NSCalendarDate *) startDate
to: (NSCalendarDate *) endDate
forUser: (NSString *) uid
{
if ([uid length])
{
SOGoUserManager *um;
NSArray *users;
NSString *domain, *email;
NSDictionary *user;
MSExchangeFreeBusy *exchangeFreeBusy;
NSObject <SOGoDNSource> *source;
um = [SOGoUserManager sharedUserManager];
domain = [[context activeUser] domain];
users = [um fetchContactsMatching: uid inDomain: domain];
if ([users count] == 1)
{
user = [users lastObject];
email = [user valueForKey: @"c_email"];
source = [user objectForKey: @"source"];
if ([email length])
{
exchangeFreeBusy = [[MSExchangeFreeBusy alloc] init];
[exchangeFreeBusy autorelease];
return [exchangeFreeBusy fetchFreeBusyInfosFrom: startDate
to: endDate
forEmail: email
inSource: source
inContext: context];
}
}
}
else
{
return [self fetchFreeBusyInfosFrom: startDate to: endDate];
}
// No freebusy information found
return nil;
}
- (NSArray *) fetchFreeBusyInfosFrom: (NSCalendarDate *) startDate
to: (NSCalendarDate *) endDate
{

View File

@ -74,6 +74,8 @@
/* resources handling */
NSString *kindField;
NSString *multipleBookingsField;
NSString *MSExchangeHostname;
}
- (void) setBindDN: (NSString *) newBindDN

View File

@ -1,6 +1,6 @@
/* LDAPSource.m - this file is part of SOGo
*
* Copyright (C) 2007-2011 Inverse inc.
* Copyright (C) 2007-2012 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Ludovic Marcotte <lmarcotte@inverse.ca>
@ -124,6 +124,8 @@ static NSArray *commonSearchFields;
@"serialnumber",
@"calfburl",
@"proxyaddresses",
// MS Exchange
@"msExchHomeServerName",
nil];
[commonSearchFields retain];
}
@ -181,6 +183,8 @@ static NSArray *commonSearchFields;
kindField = nil;
multipleBookingsField = nil;
MSExchangeHostname = nil;
_dnCache = [[NSMutableDictionary alloc] init];
}
@ -216,6 +220,7 @@ static NSArray *commonSearchFields;
[_dnCache release];
[kindField release];
[multipleBookingsField release];
[MSExchangeHostname release];
[super dealloc];
}
@ -249,7 +254,7 @@ static NSArray *commonSearchFields;
IMAPLoginField: [udSource objectForKey: @"IMAPLoginFieldName"]
bindFields: [udSource objectForKey: @"bindFields"]
kindField: [udSource objectForKey: @"KindFieldName"]
andMultipleBookingsField: [udSource objectForKey: @"MultipleBookingsFieldName"]];
andMultipleBookingsField: [udSource objectForKey: @"MultipleBookingsFieldName"]];
if ([sourceDomain length])
{
@ -286,6 +291,8 @@ static NSArray *commonSearchFields;
if ([udSource objectForKey: @"passwordPolicy"])
passwordPolicy = [[udSource objectForKey: @"passwordPolicy"] boolValue];
ASSIGN(MSExchangeHostname, [udSource objectForKey: @"MSExchangeHostname"]);
}
return self;
@ -297,11 +304,21 @@ static NSArray *commonSearchFields;
ASSIGN(bindDN, theDN);
}
- (NSString *) bindDN
{
return bindDN;
}
- (void) setBindPassword: (NSString *) thePassword
{
ASSIGN (password, thePassword);
}
- (NSString *) bindPassword
{
return password;
}
- (BOOL) bindAsCurrentUser
{
return _bindAsCurrentUser;
@ -888,6 +905,7 @@ andMultipleBookingsField: (NSString *) newMultipleBookingsField
id o;
contactEntry = [NSMutableDictionary dictionary];
[contactEntry setObject: self forKey: @"source"];
[contactEntry setObject: [ldapEntry dn] forKey: @"dn"];
attributes = [[self _searchAttributes] objectEnumerator];
@ -1225,4 +1243,9 @@ andMultipleBookingsField: (NSString *) newMultipleBookingsField
return baseDN;
}
- (NSString *) MSExchangeHostname
{
return MSExchangeHostname;
}
@end

View File

@ -1,6 +1,6 @@
/* SOGoSource.h - this file is part of SOGo
*
* Copyright (C) 2009-2010 Inverse inc.
* Copyright (C) 2009-2012 Inverse inc.
*
* Author: Ludovic Marcotte <lmarcotte@inverse.ca>
*
@ -63,13 +63,16 @@
@protocol SOGoDNSource <SOGoSource>
- (void) setBindDN: (NSString *) theDN;
- (NSString *) bindDN;
- (void) setBindPassword: (NSString *) thePassword;
- (NSString *) bindPassword;
- (BOOL) bindAsCurrentUser;
- (NSString *) lookupLoginByDN: (NSString *) theDN;
- (NSString *) lookupDNByLogin: (NSString *) theLogin;
- (NSString *) baseDN;
- (NSString *) MSExchangeHostname;
@end

View File

@ -60,7 +60,7 @@
SOGoUserFolder *homeFolder;
NSString *currentPassword;
NSString *loginInDomain;
NSString *language;
//NSString *language;
NSArray *allEmails;
NSMutableArray *mailAccounts;
NSString *cn;

View File

@ -234,7 +234,7 @@
[currentPassword release];
[cn release];
[loginInDomain release];
[language release];
//[language release];
[super dealloc];
}

View File

@ -91,15 +91,16 @@
return sharedUserManager;
}
- (void) _registerSource: (NSDictionary *) udSource
- (BOOL) _registerSource: (NSDictionary *) udSource
inDomain: (NSString *) domain
{
NSString *sourceID, *value, *type;
NSMutableDictionary *metadata;
NSObject <SOGoSource> *sogoSource;
BOOL isAddressBook;
BOOL isAddressBook, result;
Class c;
result = NO;
sourceID = [udSource objectForKey: @"id"];
if ([sourceID length] > 0)
{
@ -147,17 +148,20 @@
[metadata setObject: value forKey: @"SearchFieldNames"];
[_sourcesMetadata setObject: metadata forKey: sourceID];
result = YES;
}
}
else
[self errorWithFormat: @"attempted to register a contact/user source"
@" without id (skipped)"];
return result;
}
- (int) _registerSourcesInDomain: (NSString *) domain
{
NSArray *userSources;
unsigned int count, max;
unsigned int count, max, total;
SOGoDomainDefaults *dd;
if (domain)
@ -167,11 +171,13 @@
userSources = [dd userSources];
max = [userSources count];
total = 0;
for (count = 0; count < max; count++)
[self _registerSource: [userSources objectAtIndex: count]
inDomain: domain];
if ([self _registerSource: [userSources objectAtIndex: count]
inDomain: domain])
total++;
return max;
return total;
}
- (void) _prepareSources
@ -634,8 +640,7 @@
if ([userEntry objectForKey: @"numberOfSimultaneousBookings"])
[currentUser setObject: [userEntry objectForKey: @"numberOfSimultaneousBookings"]
forKey: @"numberOfSimultaneousBookings"];
}
}
}
if (!cn)
@ -824,8 +829,9 @@
{
returnContact = [NSMutableDictionary dictionary];
[returnContact setObject: uid forKey: @"c_uid"];
[compactContacts setObject: returnContact forKey: uid];
}
[returnContact setObject: [userEntry objectForKey: @"source"] forKey: @"source"];
[compactContacts setObject: returnContact forKey: uid];
}
if (![[returnContact objectForKey: @"c_name"] length])
[returnContact setObject: [userEntry objectForKey: @"c_name"]
forKey: @"c_name"];

View File

@ -158,6 +158,7 @@
- (NSString *) _freeBusyFromStartDate: (NSCalendarDate *) startDate
toEndDate: (NSCalendarDate *) endDate
forFreeBusy: (SOGoFreeBusyObject *) fb
andUser: (NSString *) user
{
NSMutableArray *freeBusy;
unsigned int *freeBusyItems;
@ -169,7 +170,7 @@
freeBusyItems = NSZoneCalloc (NULL, intervals, sizeof (int));
[self _fillFreeBusyItems: freeBusyItems count: intervals
withRecords: [fb fetchFreeBusyInfosFrom: startDate to: endDate]
withRecords: [fb fetchFreeBusyInfosFrom: startDate to: endDate forUser: user]
fromStartDate: startDate toEndDate: endDate];
freeBusy = [NSMutableArray arrayWithCapacity: intervals];
@ -184,15 +185,16 @@
- (id <WOActionResults>) readFreeBusyAction
{
WOResponse *response;
SOGoFreeBusyObject *co;
SOGoFreeBusyObject *freebusy;
NSCalendarDate *startDate, *endDate;
NSString *queryDay;
NSString *queryDay, *uid;
NSTimeZone *uTZ;
SOGoUser *user;
user = [context activeUser];
uTZ = [[user userDefaults] timeZone];
uid = [self queryParameterForKey: @"uid"];
queryDay = [self queryParameterForKey: @"sday"];
if ([queryDay length] == 8)
{
@ -211,13 +213,13 @@
andString: @"Start date is later than end date."];
else
{
co = [self clientObject];
freebusy = [self clientObject];
response
= [self responseWithStatus: 200
andString: [self
_freeBusyFromStartDate: startDate
toEndDate: endDate
forFreeBusy: co]];
andString: [self _freeBusyFromStartDate: startDate
toEndDate: endDate
forFreeBusy: freebusy
andUser: uid]];
}
}
else

View File

@ -219,7 +219,7 @@ function performSearchCallback(http) {
list.appendChild(node);
node.address = completeEmail;
// log("node.address: " + node.address);
node.uid = contact["c_uid"];
node.uid = (contact["isMSExchange"]? UserLogin + ":" : "") + contact["c_uid"];
node.isList = isList;
if (isList) {
node.cname = contact["c_name"];
@ -272,7 +272,7 @@ function performSearchCallback(http) {
if (data.contacts.length == 1) {
// Single result
var contact = data.contacts[0];
input.uid = contact["c_uid"];
input.uid = (contact["isMSExchange"]? UserLogin + ":" : "") + contact["c_uid"];
var isList = (contact["c_component"] &&
contact["c_component"] == "vlist");
if (isList) {
@ -997,11 +997,19 @@ freeBusyRequest.prototype = {
},
_performAjaxRequest: function fBR__performAjaxRequest(rqStart, rqEnd) {
var urlstr = (UserFolderURL + "../" + this.mUid
+ "/freebusy.ifb/ajaxRead?"
+ "sday=" + rqStart.getDayString()
+ "&eday=" + rqEnd.getDayString());
var urlstr = UserFolderURL + "../";
var uids = this.mUid.split(":");
if (uids.length > 1)
urlstr += (uids[0]
+ "/freebusy.ifb/ajaxRead?"
+ "uid=" + uids[1]
+ "&");
else
urlstr += (this.mUid
+ "/freebusy.ifb/ajaxRead?");
urlstr += ("sday=" + rqStart.getDayString()
+ "&eday=" + rqEnd.getDayString());
var thisRequest = this;
var callback = function fBR__performAjaxRequest_cb(http) {
if (http.readyState == 4) {