mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-04-24 14:29:28 +00:00
merge of '1239295b979f0ffa4eaaaac3d20eda7873f1606d'
and 'e750571b424fd6eb63b5c1e2704f0f04635a6e51' Monotone-Parent: 1239295b979f0ffa4eaaaac3d20eda7873f1606d Monotone-Parent: e750571b424fd6eb63b5c1e2704f0f04635a6e51 Monotone-Revision: 0ce8c0fe1af6188f22754102040d63f124d3761b Monotone-Author: flachapelle@inverse.ca Monotone-Date: 2010-07-15T18:30:07 Monotone-Branch: ca.inverse.sogo
This commit is contained in:
44
ChangeLog
44
ChangeLog
@@ -1,3 +1,47 @@
|
||||
2010-07-15 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* SoObjects/SOGo/SOGoUser.m (-personalCalendarFolderInContext:):
|
||||
we now make use of -[SOGoParentFolder
|
||||
lookupPersonalFolder:ignoringRights:] with @"personal" and YES as
|
||||
arguments.
|
||||
|
||||
* SoObjects/Appointments/SOGoAppointmentFolder.m
|
||||
(-lookupCalendarFolderForUID:): removed useless method, which can
|
||||
be replaced with -[SOGoUser personalCalendarFolderInContext:].
|
||||
|
||||
* UI/Scheduler/UIxCalListingActions.m
|
||||
(_aptFolder:withClientObject:): removed unused method.
|
||||
|
||||
* UI/WebServerResources/UIxAppointmentEditor.js
|
||||
(onComposeToAllAttendees): take the status image DIV into account
|
||||
when detecting the user fullnames.
|
||||
(onComposeToUndecidedAttendees): same as above.
|
||||
|
||||
* Tests/Integration/test-davacl.py
|
||||
(DAVCalendarPublicAclTest.testCollectionAccessNormalUser): print
|
||||
the amount of received hrefs.
|
||||
|
||||
* SoObjects/Appointments/SOGoAppointmentFolders.m
|
||||
(-folderObjectKeys): we now check the "AccessObject"
|
||||
right on the returned folders to determine whether their ICS or
|
||||
XML version should be accessible.
|
||||
|
||||
* SoObjects/SOGo/SOGoParentFolder.m
|
||||
(_fetchPersonalFolders:withChannel:): we no longer check access
|
||||
rights from here as this method is too low level and prevent other
|
||||
mechanisms from working properly.
|
||||
(-lookupPersonalFolder:ignoringRights:): new method enabling the
|
||||
lookup of a user's personal folders only and offering the choice
|
||||
of respecting (or not) the active user's permission before
|
||||
returning it.
|
||||
(-lookupName:inContext:acquire:): we now make use of the above
|
||||
method when looking up personal folders ("personal" or not).
|
||||
(-toManyRelationShipKeys): same as lookupName... above.
|
||||
|
||||
* SoObjects/SOGo/SOGoObject.m (-ignoreRights): new utility method
|
||||
that determines whether the current object must check access
|
||||
rights on subobjects.
|
||||
|
||||
2010-07-14 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* SoObjects/SOGo/SOGoGCSFolder.m (-aclSQLListingFilter): return an
|
||||
|
||||
45
Scripts/sql-update-1.2.2_to_1.3.0-mysql.sh
Executable file
45
Scripts/sql-update-1.2.2_to_1.3.0-mysql.sh
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
|
||||
# this script only works with MySQL
|
||||
|
||||
defaultusername=$USER
|
||||
defaulthostname=localhost
|
||||
defaultdatabase=$USER
|
||||
indextable=sogo_folder_info
|
||||
|
||||
read -p "Username ($defaultusername): " username
|
||||
read -p "Hostname ($defaulthostname): " hostname
|
||||
read -p "Database ($defaultdatabase): " database
|
||||
|
||||
if [ -z "$username" ]
|
||||
then
|
||||
username=$defaultusername
|
||||
fi
|
||||
|
||||
if [ -z "$hostname" ]
|
||||
then
|
||||
hostname=$defaulthostname
|
||||
fi
|
||||
|
||||
if [ -z "$database" ]
|
||||
then
|
||||
database=$defaultdatabase
|
||||
fi
|
||||
|
||||
sqlscript=""
|
||||
|
||||
function addField() {
|
||||
oldIFS="$IFS"
|
||||
IFS=" "
|
||||
part="`echo -e \"ALTER TABLE $table ADD COLUMN c_category VARCHAR(255);\\n\"`";
|
||||
sqlscript="$sqlscript$part"
|
||||
IFS="$oldIFS"
|
||||
}
|
||||
|
||||
tables=`mysql -p -N -B -u $username -h $hostname $database -e "select SUBSTRING_INDEX(c_quick_location, '/', -1) from $indextable where c_folder_type = 'Appointment';"`
|
||||
|
||||
for table in $tables;
|
||||
do
|
||||
addField
|
||||
done
|
||||
echo "$sqlscript" | mysql -p -s -u $username -h $hostname $database > /dev/null
|
||||
@@ -123,7 +123,6 @@ typedef enum {
|
||||
- (id) lookupHomeFolderForUID: (NSString *) _uid
|
||||
inContext: (id) _ctx;
|
||||
|
||||
- (SOGoAppointmentFolder *) lookupCalendarFolderForUID: (NSString *) uid;
|
||||
- (NSArray *) lookupCalendarFoldersForUID: (NSString *) theUID;
|
||||
- (NSArray *) lookupCalendarFoldersForUIDs: (NSArray *) _uids
|
||||
inContext: (id) _ctx;
|
||||
|
||||
@@ -2644,36 +2644,6 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// This method returns the personal calendar of a specific user.
|
||||
//
|
||||
- (SOGoAppointmentFolder *) lookupCalendarFolderForUID: (NSString *) uid
|
||||
{
|
||||
SOGoFolder *currentContainer;
|
||||
SOGoAppointmentFolders *parent;
|
||||
NSException *error;
|
||||
|
||||
currentContainer = [[container container] container];
|
||||
currentContainer = [currentContainer lookupName: uid
|
||||
inContext: context
|
||||
acquire: NO];
|
||||
parent = [currentContainer lookupName: @"Calendar" inContext: context
|
||||
acquire: NO];
|
||||
currentContainer = [parent lookupName: @"personal" inContext: context
|
||||
acquire: NO];
|
||||
if (!currentContainer)
|
||||
{
|
||||
error = [parent newFolderWithName: [parent defaultFolderName]
|
||||
andNameInContainer: @"personal"];
|
||||
if (!error)
|
||||
currentContainer = [parent lookupName: @"personal"
|
||||
inContext: context
|
||||
acquire: NO];
|
||||
}
|
||||
|
||||
return (SOGoAppointmentFolder *) currentContainer;
|
||||
}
|
||||
|
||||
//
|
||||
// This method returns an array containing all the calendar folders
|
||||
// of a specific user, excluding her/his subscriptions.
|
||||
@@ -2712,6 +2682,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||
NSMutableArray *folders;
|
||||
NSEnumerator *e;
|
||||
NSString *uid, *ownerLogin;
|
||||
SOGoUser *user;
|
||||
id folder;
|
||||
|
||||
ownerLogin = [self ownerInContext: context];
|
||||
@@ -2725,7 +2696,8 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||
folder = self;
|
||||
else
|
||||
{
|
||||
folder = [self lookupCalendarFolderForUID: uid];
|
||||
user = [SOGoUser userWithLogin: uid];
|
||||
folder = [user personalCalendarFolderInContext: context];
|
||||
if (![folder isNotNull])
|
||||
[self logWithFormat:@"Note: did not find folder for uid: '%@'", uid];
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
#import <NGObjWeb/WORequest+So.h>
|
||||
#import <NGObjWeb/NSException+HTTP.h>
|
||||
#import <NGObjWeb/SoSecurityManager.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
|
||||
#import <GDLAccess/EOAdaptorChannel.h>
|
||||
@@ -57,14 +58,48 @@
|
||||
|
||||
@interface SOGoParentFolder (Private)
|
||||
|
||||
- (NSException *) initSubscribedSubFolders;
|
||||
- (NSException *) _fetchPersonalFolders: (NSString *) sql
|
||||
withChannel: (EOAdaptorChannel *) fc;
|
||||
|
||||
@end
|
||||
|
||||
static SoSecurityManager *sm = nil;
|
||||
|
||||
@implementation SOGoAppointmentFolders
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (!sm)
|
||||
sm = [SoSecurityManager sharedSecurityManager];
|
||||
}
|
||||
|
||||
+ (SOGoWebDAVAclManager *) webdavAclManager
|
||||
{
|
||||
static SOGoWebDAVAclManager *aclManager = nil;
|
||||
|
||||
if (!aclManager)
|
||||
{
|
||||
aclManager = [[super webdavAclManager] copy];
|
||||
[aclManager
|
||||
registerDAVPermission: davElement (@"write", XMLNS_WEBDAV)
|
||||
abstract: NO
|
||||
withEquivalent: SoPerm_AddDocumentsImagesAndFiles
|
||||
asChildOf: davElement (@"all", XMLNS_WEBDAV)];
|
||||
[aclManager
|
||||
registerDAVPermission: davElement (@"write-properties", XMLNS_WEBDAV)
|
||||
abstract: YES
|
||||
withEquivalent: SoPerm_AddDocumentsImagesAndFiles
|
||||
asChildOf: davElement (@"write", XMLNS_WEBDAV)];
|
||||
[aclManager
|
||||
registerDAVPermission: davElement (@"write-content", XMLNS_WEBDAV)
|
||||
abstract: YES
|
||||
withEquivalent: SoPerm_AddDocumentsImagesAndFiles
|
||||
asChildOf: davElement (@"write", XMLNS_WEBDAV)];
|
||||
}
|
||||
|
||||
return aclManager;
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
@@ -166,9 +201,11 @@
|
||||
SOGoAppointmentFolder *folder;
|
||||
NSString *folderObjectKey;
|
||||
int count, max;
|
||||
BOOL ignoreRights;
|
||||
|
||||
if (!folderObjectKeys)
|
||||
{
|
||||
ignoreRights = [self ignoreRights];
|
||||
folders = [self subFolders];
|
||||
max = [folders count];
|
||||
folderObjectKeys = [[NSMutableArray alloc] initWithCapacity: max];
|
||||
@@ -176,7 +213,10 @@
|
||||
{
|
||||
folder = [folders objectAtIndex: count];
|
||||
if ([folder isMemberOfClass: [SOGoAppointmentFolder class]]
|
||||
&& ![folder isSubscription])
|
||||
&& ![folder isSubscription]
|
||||
&& (ignoreRights || ![sm validatePermission: SOGoPerm_AccessObject
|
||||
onObject: folder
|
||||
inContext: context]))
|
||||
{
|
||||
folderObjectKey = [NSString stringWithFormat: @"%@.ics",
|
||||
[folder nameInContainer]];
|
||||
@@ -475,33 +515,6 @@
|
||||
return error;
|
||||
}
|
||||
|
||||
+ (SOGoWebDAVAclManager *) webdavAclManager
|
||||
{
|
||||
static SOGoWebDAVAclManager *aclManager = nil;
|
||||
|
||||
if (!aclManager)
|
||||
{
|
||||
aclManager = [[super webdavAclManager] copy];
|
||||
[aclManager
|
||||
registerDAVPermission: davElement (@"write", XMLNS_WEBDAV)
|
||||
abstract: NO
|
||||
withEquivalent: SoPerm_AddDocumentsImagesAndFiles
|
||||
asChildOf: davElement (@"all", XMLNS_WEBDAV)];
|
||||
[aclManager
|
||||
registerDAVPermission: davElement (@"write-properties", XMLNS_WEBDAV)
|
||||
abstract: YES
|
||||
withEquivalent: SoPerm_AddDocumentsImagesAndFiles
|
||||
asChildOf: davElement (@"write", XMLNS_WEBDAV)];
|
||||
[aclManager
|
||||
registerDAVPermission: davElement (@"write-content", XMLNS_WEBDAV)
|
||||
abstract: YES
|
||||
withEquivalent: SoPerm_AddDocumentsImagesAndFiles
|
||||
asChildOf: davElement (@"write", XMLNS_WEBDAV)];
|
||||
}
|
||||
|
||||
return aclManager;
|
||||
}
|
||||
|
||||
- (BOOL) hasProxyCalendarsWithWriteAccess: (BOOL) write
|
||||
forUserWithLogin: (NSString *) userLogin
|
||||
{
|
||||
|
||||
@@ -163,7 +163,8 @@
|
||||
if (!object)
|
||||
{
|
||||
// Create the event in the user's personal calendar.
|
||||
folder = [container lookupCalendarFolderForUID: uid];
|
||||
folder = [[SOGoUser userWithLogin: uid]
|
||||
personalCalendarFolderInContext: context];
|
||||
object = [SOGoAppointmentObject objectWithName: nameInContainer
|
||||
inContainer: folder];
|
||||
[object setIsNew: YES];
|
||||
@@ -265,7 +266,8 @@
|
||||
|
||||
// Invitations are always written to the personal folder; it's not necessay
|
||||
// to look into all folders of the user
|
||||
folder = [container lookupCalendarFolderForUID: theUID];
|
||||
folder = [[SOGoUser userWithLogin: theUID]
|
||||
personalCalendarFolderInContext: context];
|
||||
object = [folder lookupName: nameInContainer
|
||||
inContext: context acquire: NO];
|
||||
if (![object isKindOfClass: [NSException class]])
|
||||
|
||||
@@ -739,9 +739,7 @@ static NSArray *childRecordFields = nil;
|
||||
NSDictionary *record;
|
||||
WORequest *request;
|
||||
|
||||
obj = [super lookupName: key
|
||||
inContext: localContext
|
||||
acquire: acquire];
|
||||
obj = [super lookupName: key inContext: localContext acquire: acquire];
|
||||
if (!obj)
|
||||
{
|
||||
record = [childRecords objectForKey: key];
|
||||
|
||||
@@ -98,6 +98,10 @@
|
||||
- (void) setOwner: (NSString *) newOwner;
|
||||
- (NSString *) ownerInContext: (id) _ctx;
|
||||
|
||||
/* a helper that determines whether access rights can be ignored on
|
||||
an object */
|
||||
- (BOOL) ignoreRights;
|
||||
|
||||
/* looking up shared objects */
|
||||
|
||||
- (SOGoUserFolder *) lookupUserFolder;
|
||||
|
||||
@@ -229,6 +229,25 @@
|
||||
return owner;
|
||||
}
|
||||
|
||||
- (BOOL) ignoreRights
|
||||
{
|
||||
SOGoUser *currentUser;
|
||||
NSString *login;
|
||||
BOOL ignoreRights;
|
||||
|
||||
if (activeUserIsOwner)
|
||||
ignoreRights = YES;
|
||||
else
|
||||
{
|
||||
currentUser = [context activeUser];
|
||||
login = [currentUser login];
|
||||
ignoreRights = ([login isEqualToString: [self ownerInContext: context]]
|
||||
|| [currentUser isSuperUser]);
|
||||
}
|
||||
|
||||
return ignoreRights;
|
||||
}
|
||||
|
||||
- (BOOL) isInPublicZone
|
||||
{
|
||||
if (!isInPublicZone)
|
||||
|
||||
@@ -54,6 +54,9 @@
|
||||
- (NSException *) newFolderWithName: (NSString *) name
|
||||
nameInContainer: (NSString **) newNameInContainer;
|
||||
|
||||
- (id) lookupPersonalFolder: (NSString *) name
|
||||
ignoringRights: (BOOL) ignoreRights;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SOGOPARENTFOLDERS_H */
|
||||
|
||||
@@ -175,26 +175,19 @@ static SoSecurityManager *sm = nil;
|
||||
{
|
||||
NSArray *attrs;
|
||||
NSDictionary *row;
|
||||
BOOL hasPersonal, ignoreRights;
|
||||
SOGoGCSFolder *folder;
|
||||
NSString *key, *login;
|
||||
NSException *error;
|
||||
SOGoUser *currentUser;
|
||||
SoSecurityManager *securityManager;
|
||||
|
||||
if (!subFolderClass)
|
||||
subFolderClass = [[self class] subFolderClass];
|
||||
|
||||
hasPersonal = NO;
|
||||
error = [fc evaluateExpressionX: sql];
|
||||
if (!error)
|
||||
{
|
||||
currentUser = [context activeUser];
|
||||
login = [currentUser login];
|
||||
ignoreRights = (activeUserIsOwner || [login isEqualToString: owner]
|
||||
|| [currentUser isSuperUser]);
|
||||
if (!ignoreRights)
|
||||
securityManager = [SoSecurityManager sharedSecurityManager];
|
||||
|
||||
attrs = [fc describeResults: NO];
|
||||
while ((row = [fc fetchAttributes: attrs withZone: NULL]))
|
||||
@@ -203,19 +196,13 @@ static SoSecurityManager *sm = nil;
|
||||
if ([key isKindOfClass: [NSString class]])
|
||||
{
|
||||
folder = [subFolderClass objectWithName: key inContainer: self];
|
||||
hasPersonal = (hasPersonal
|
||||
|| [key isEqualToString: @"personal"]);
|
||||
[folder setOCSPath: [NSString stringWithFormat: @"%@/%@",
|
||||
OCSPath, key]];
|
||||
if (ignoreRights
|
||||
|| ![securityManager validatePermission: SOGoPerm_AccessObject
|
||||
onObject: folder
|
||||
inContext: context])
|
||||
[subFolders setObject: folder forKey: key];
|
||||
[subFolders setObject: folder forKey: key];
|
||||
}
|
||||
}
|
||||
|
||||
if (ignoreRights && !hasPersonal)
|
||||
if (![subFolders objectForKey: @"personal"])
|
||||
[self _createPersonalFolder];
|
||||
}
|
||||
|
||||
@@ -405,16 +392,8 @@ static SoSecurityManager *sm = nil;
|
||||
obj = [super lookupName: name inContext: lookupContext acquire: NO];
|
||||
if (!obj)
|
||||
{
|
||||
// Lookup in personal folders
|
||||
error = [self initSubFolders];
|
||||
if (error)
|
||||
{
|
||||
[self errorWithFormat: @"a database error occured: %@", [error reason]];
|
||||
obj = [NSException exceptionWithHTTPStatus: 503];
|
||||
}
|
||||
else
|
||||
obj = [subFolders objectForKey: name];
|
||||
|
||||
obj = [self lookupPersonalFolder: name
|
||||
ignoringRights: NO];
|
||||
if (!obj)
|
||||
{
|
||||
// Lookup in subscribed folders
|
||||
@@ -432,6 +411,31 @@ static SoSecurityManager *sm = nil;
|
||||
return obj;
|
||||
}
|
||||
|
||||
- (id) lookupPersonalFolder: (NSString *) name
|
||||
ignoringRights: (BOOL) ignoreRights
|
||||
{
|
||||
NSException *error;
|
||||
id obj;
|
||||
|
||||
error = [self initSubFolders];
|
||||
if (error)
|
||||
{
|
||||
[self errorWithFormat: @"a database error occured: %@", [error reason]];
|
||||
obj = [NSException exceptionWithHTTPStatus: 503];
|
||||
}
|
||||
else
|
||||
{
|
||||
obj = [subFolders objectForKey: name];
|
||||
if (obj && !ignoreRights && ![self ignoreRights]
|
||||
&& [sm validatePermission: SOGoPerm_AccessObject
|
||||
onObject: obj
|
||||
inContext: context])
|
||||
obj = nil;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
- (NSArray *) subFolders
|
||||
{
|
||||
NSMutableArray *ma;
|
||||
@@ -475,7 +479,7 @@ static SoSecurityManager *sm = nil;
|
||||
|
||||
#warning check error here
|
||||
error = [self initSubFolders];
|
||||
|
||||
|
||||
subs = [subFolders allValues];
|
||||
count = [subs count];
|
||||
for (i = 0; !rc && i < count; i++)
|
||||
@@ -492,11 +496,20 @@ static SoSecurityManager *sm = nil;
|
||||
NSEnumerator *sortedSubFolders;
|
||||
NSMutableArray *keys;
|
||||
SOGoGCSFolder *currentFolder;
|
||||
BOOL ignoreRights;
|
||||
|
||||
ignoreRights = [self ignoreRights];
|
||||
|
||||
keys = [NSMutableArray array];
|
||||
sortedSubFolders = [[self subFolders] objectEnumerator];
|
||||
while ((currentFolder = [sortedSubFolders nextObject]))
|
||||
[keys addObject: [currentFolder nameInContainer]];
|
||||
{
|
||||
if (ignoreRights
|
||||
|| ![sm validatePermission: SOGoPerm_AccessObject
|
||||
onObject: currentFolder
|
||||
inContext: context])
|
||||
[keys addObject: [currentFolder nameInContainer]];
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
@@ -599,9 +599,8 @@
|
||||
- (SOGoAppointmentFolder *)
|
||||
personalCalendarFolderInContext: (WOContext *) context
|
||||
{
|
||||
return [[self calendarsFolderInContext: context] lookupName: @"personal"
|
||||
inContext: context
|
||||
acquire: NO];
|
||||
return [[self calendarsFolderInContext: context] lookupPersonalFolder: @"personal"
|
||||
ignoringRights: YES];
|
||||
}
|
||||
|
||||
// - (id) schedulingCalendarInContext: (id) _ctx
|
||||
|
||||
@@ -983,12 +983,12 @@ class DAVCalendarPublicAclTest(unittest.TestCase):
|
||||
self.subscriber_client.execute(propfind)
|
||||
hrefs = propfind.response["document"] \
|
||||
.findall("{DAV:}response/{DAV:}href")
|
||||
|
||||
self.assertEquals(len(hrefs), 1,
|
||||
"expected only one href in response")
|
||||
"expected 1 href in response instead of %d" % len(hrefs))
|
||||
self.assertEquals(hrefs[0].text, parentColl,
|
||||
"the href must be the 'Calendar' parent coll.")
|
||||
|
||||
|
||||
acl_utility = utilities.TestCalendarACLUtility(self,
|
||||
self.client,
|
||||
self.createdRsrc)
|
||||
|
||||
@@ -234,25 +234,6 @@ static NSArray *tasksFields = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (SOGoAppointmentFolder *) _aptFolder: (NSString *) folder
|
||||
withClientObject: (SOGoAppointmentFolder *) clientObject
|
||||
{
|
||||
SOGoAppointmentFolder *aptFolder;
|
||||
NSArray *folderParts;
|
||||
|
||||
if ([folder isEqualToString: @"/"])
|
||||
aptFolder = clientObject;
|
||||
else
|
||||
{
|
||||
folderParts = [folder componentsSeparatedByString: @":"];
|
||||
aptFolder
|
||||
= [clientObject lookupCalendarFolderForUID:
|
||||
[folderParts objectAtIndex: 0]];
|
||||
}
|
||||
|
||||
return aptFolder;
|
||||
}
|
||||
|
||||
- (void) _fixComponentTitle: (NSMutableDictionary *) component
|
||||
withType: (NSString *) type
|
||||
{
|
||||
|
||||
@@ -115,8 +115,15 @@ function onComposeToAllAttendees()
|
||||
var attendees = $$("DIV#attendeesMenu LI.attendee");
|
||||
var addresses = new Array();
|
||||
attendees.each(function(item) {
|
||||
var address = item.firstChild.nodeValue.trim() + " <" + item.readAttribute("email") + ">";
|
||||
addresses.push(address);
|
||||
var textChild = null;
|
||||
var childNodes = item.childNodes;
|
||||
for (var i = 0; !textChild && i < childNodes.length; i++) {
|
||||
if (childNodes[i].nodeType == 3) {
|
||||
textChild = childNodes[i];
|
||||
var address = textChild.nodeValue.trim() + " <" + item.readAttribute("email") + ">";
|
||||
addresses.push(address);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (window.opener)
|
||||
window.opener.openMailTo(addresses.join(","));
|
||||
@@ -130,8 +137,15 @@ function onComposeToUndecidedAttendees()
|
||||
var attendees = $$("DIV#attendeesMenu LI.attendee.needs-action");
|
||||
var addresses = new Array();
|
||||
attendees.each(function(item) {
|
||||
var address = item.firstChild.nodeValue.trim() + " <" + item.readAttribute("email") + ">";
|
||||
addresses.push(address);
|
||||
var textChild = null;
|
||||
var childNodes = item.childNodes;
|
||||
for (var i = 0; !textChild && i < childNodes.length; i++) {
|
||||
if (childNodes[i].nodeType == 3) {
|
||||
textChild = childNodes[i];
|
||||
var address = textChild.nodeValue.trim() + " <" + item.readAttribute("email") + ">";
|
||||
addresses.push(address);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (window.opener)
|
||||
window.opener.openMailTo(addresses.join(","));
|
||||
|
||||
1
debian/sogo.docs
vendored
1
debian/sogo.docs
vendored
@@ -2,3 +2,4 @@ NEWS
|
||||
README
|
||||
TODO
|
||||
Scripts/sql-update-1.2.2_to_1.3.0.sh
|
||||
Scripts/sql-update-1.2.2_to_1.3.0-mysql.sh
|
||||
|
||||
@@ -188,7 +188,7 @@ rm -fr ${RPM_BUILD_ROOT}
|
||||
|
||||
%config %{_sysconfdir}/httpd/conf.d/SOGo.conf
|
||||
%config %{_sysconfdir}/sysconfig/sogo
|
||||
%doc ChangeLog README NEWS Scripts/sql-update-20070724.sh Scripts/sql-update-20070822.sh Scripts/sql-update-20080303.sh Scripts/sql-update-101_to_102.sh Scripts/sql-update-1.2.2_to_1.3.0.sh
|
||||
%doc ChangeLog README NEWS Scripts/sql-update-20070724.sh Scripts/sql-update-20070822.sh Scripts/sql-update-20080303.sh Scripts/sql-update-101_to_102.sh Scripts/sql-update-1.2.2_to_1.3.0.sh sql-update-1.2.2_to_1.3.0-mysql.sh
|
||||
|
||||
%files -n sogo-tool
|
||||
%{prefix}/Tools/Admin/sogo-tool
|
||||
|
||||
Reference in New Issue
Block a user