See ChangeLog

Monotone-Parent: 1e01e7055612c8aa2f2c0e9151035ef348604b8e
Monotone-Revision: ab8b4a7a66ffdb6688f466f2cc301caf1fc40a66

Monotone-Author: ludovic@Sophos.ca
Monotone-Date: 2010-09-24T19:13:02
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
Ludovic Marcotte 2010-09-24 19:13:02 +00:00
parent 38af9bc66b
commit 3d2f08f678
25 changed files with 1 additions and 1485 deletions

View File

@ -3,6 +3,7 @@
* Added caching support for LDAP-based groups
* SoObjects/SOGo/LDAPSource.m
Improved SafeLDAPCriteria() to properly escape '%'
* Dropped lots of unnecessary and worthless files
2010-09-22 Francis Lachapelle <flachapelle@inverse.ca>

26
README
View File

@ -1,26 +0,0 @@
# $Id$
SOGo
====
The server project is organized in three major parts:
- SoObjects
- Main
- UI
SoObjects contains the objects being traversed using the URL.
Main contains the main server binary (.woa) and application wide objects
like authenticators.
UI contains the actual UI which is bound to the SoObjects as SOPE methods
NOTES
=====
mapping email <-> logins
usermanager -> part of SOGoLogic
Default to enable debugging output in the page:
SOGoUIxDebugEnabled YES|NO

View File

@ -1,117 +0,0 @@
Storage Backend
===============
The storage backend implements the "low level" folder abstraction, which is
basically an arbitary "BLOB" containing some document. The feature is that
we extract "quick access" / "searchable" attributes from the document content.
Further it contains the "folder management" API, as named folders can be stored
in different databases.
Note: we need a way to tell where "new" folders should be created
Note: to sync with LDAP we need to periodically delete or archive old folders
Folders have associated a type (like 'calendar') which defines the query
attributes and serialization format.
TODO
====
- fix some OCS naming
- defaults
- lookup directories
- hierarchies deeper than 4 (properly filter on path in OCS)
Open Questions
==============
System-meta-data in the blob-table or in the quick-table?
- master data belongs into the blob table
- could be regular 'NSxxx' keys to differentiate meta data from
Class Hierarchy
===============
[NSObject]
OCSContext - tracking context
OCSFolder - represents a single folder
OCSFolderManager - manages folders
OCSFolderType - the mapping info for a specific folder-type
OCSFieldInfo - mapping info for one 'quick field'
OCSChannelManager - maintains EOAdaptorChannel objects
TBD:
- field 'extractor'
- field 'value' (eg array values for participants?)
- BLOB archiver/unarchiver
Defaults
========
OCSFolderInfoURL - the DB URL where the folder-info table is located
eg: http://OGo:OGo@localhost/test/folder_info
OCSFolderManagerDebugEnabled - enable folder-manager debug logs
OCSFolderManagerSQLDebugEnabled - enable folder-manager SQL gen debug logs
OCSChannelManagerDebugEnabled - enable channel debug pooling logs
OCSChannelManagerPoolDebugEnabled - debug pool handle allocation
OCSChannelExpireAge - if that age in seconds is exceeded, a channel
will be removed from the pool
OCSChannelCollectionTimer - time in seconds. each n-seconds the pool will be
checked for channels too old
[PGDebugEnabled] - enable PostgreSQL adaptor debugging
URLs
====
"Database URLs"
We use the schema:
postgresql://[user]:[password]@[host]:[port]/[dbname]/[tablename]
Support Tools
=============
- tools we need:
- one to recreate a quick table based on the blob table
Notes
=====
- need to use http:// URLs for connect info, until generic URLs in
libFoundation are fixed (the parses breaks on the login/password parts)
QA
==
Q: Why do we use two tables, we could store the quick columns in the blob?
==
They could be in the same table. We considered using separate tables since the
quick table is likely to be recreated now and then if BLOB indexing
requirements change.
Actually one could even use different _quick tables which share a common BLOB
table.
(a quick table is nothing more than a database index and like with DB indexes
multiple ones for different requirements can make sense).
Further it might improve caching behaviour for row based caches (the quick
table is going to be queried much more often) - not sure whether this is
relevant with PostgreSQL, probably not?
Q: Can we use a VARCHAR primary key?
==
We asked in the postgres IRC channel and apparently the performance penalty of
string primary keys isn't big.
We could also use an 'internal' int sequence in addition (might be useful for
supporting ZideLook)
Motivation: the 'iCalendar' ID is a string and usually looks like a GUID.
Q: Why using VARCHAR instead of TEXT in the BLOB?
==
To quote PostgreSQL documentation:
"There are no performance differences between these three types, apart from
the increased storage size when using the blank-padded type."
So varchar(xx) is just a large TEXT. Since we intend to store mostly small
snippets of data (tiny XML fragments), we considered VARCHAR the more
appropriate type.

View File

@ -1,19 +0,0 @@
TODO: improve text
Objective-C classes for representing iCalendar entities as objects. To
actually parse iCalendar entities the sope-xml versitSaxDriver is used.
Note that this library doesn't make any use of the now deprecated libical but
rather relies on the SAX interface (SaxObjectDecoder is used).
Recurrences
===========
Recurrences are modeled via iCalRecurrenceRules and an iCalRecurrenceCalculator
which contains all the necessary logic according to RFC2445 to interpret
iCalRecurrenceRules. The calculator needs a referrence date for the first
instance of a recurrence which is usually provided by any of the repeatable
entity objects (i.e. iCalEvent).
Please note that recurrences are work in progress and far from being
complete/compliant with RFC2445. So far only the most simple cases are done
properly.

View File

@ -1,9 +0,0 @@
sope-ical/samples
This directory contains sample programs for the sope-ical libraries.
Tools
=====
ical2 - uses SaxObjectDecoder with NGiCal.xmap
ical3 - uses iCalDataSource to run queries on iCal files

View File

@ -1,8 +0,0 @@
This folder contains unit tests for the NGiCal project.
It uses SEN:TE's OCUnit project which can be found at
http://www.sente.ch/software/ocunit/
I used OCUnitRoot v38, later versions might work as well.
NOTE: This is currently provided in Xcode only.

View File

@ -1,53 +0,0 @@
Overview
========
Two SaxObjC drivers for iCalendar and vCard files, initially written by
Max Berger <max@berger.name>.
VSiCalSaxDriver basically maps iCal 2.0 components, properties and parameters
to the XML events according to the xCal 02 draft (iCal 3.0).
Having a SAX driver for iCal might seem strange and a bit inefficient at
first look, but the time saved for the application-level developer is
significant, since he only needs to learn (or usually already knows) the
SAX or DOM APIs and any XML API based on them (like XPATH, XQUERY).
The VSiCalSaxDriver is aimed to be a replacement for the older (but better
tested as of now) iCalSaxDriver. However, the iCalSaxDriver depends on the
abandoned and hardly maintainable libical, which itself is an additional
dependency to the OGo project and thus a welcome candidate for replacement.
The VSSaxDriver attempts to follow RFC2445 closely, however the parser is
written to be robust when it comes to parsing real life content. Currently,
unescaping is done for more characters then it MUST according to RFC2445, but
this is probably not a bad idea - wrongly escaped characters will still be
parsed according to the original intent. Also, the VSSaxDriver supports Unix
style terminated lines/folding.
ToDo
====
- improve error handling (SaxExceptions !)
- make the driver fully xCal compliant
Defaults
========
Name Type Description
------------------------------------------------------------------------------
VSSaxDriverDebugEnabled BOOL YES -> log some debug information
via NSLog
Examples
========
To "convert" an iCalendar to xCal (the test programs print out some XML):
saxxml -XMLReader VSiCalSaxDriver test1.ics
domxml -XMLReader VSiCalSaxDriver -xml test1.ics
To "convert" an iCalendar to PYX:
domxml -XMLReader VSiCalSaxDriver -pyx test1.ics

View File

@ -6,7 +6,6 @@ WOBUNDLE_NAME = Appointments
Appointments_PRINCIPAL_CLASS = SOGoAppointmentsProduct
# SOGoGroupAppointmentFolder.m
Appointments_OBJC_FILES = \
Product.m \
NSArray+Appointments.m \

View File

@ -1,52 +0,0 @@
/*
Copyright (C) 2004 SKYRIX Software AG
This file is part of OpenGroupware.org.
OGo 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.
OGo 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 OGo; see the file COPYING. If not, write to the
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
// $Id: SOGoAppointmentFolder.h 137 2004-07-02 17:42:14Z helge $
#ifndef __Appointments_SOGoGroupAppointmentFolder_H__
#define __Appointments_SOGoGroupAppointmentFolder_H__
#include "SOGoAppointmentFolder.h"
/*
SOGoGroupAppointmentFolder
Parent object: an SOGoGroupFolder (or subclass)
Child objects: SOGoAppointmentObject
Note: this is only a subclass of SOGoAppointmentFolder to inherit all the
SOPE methods (it provides the same API). It is not an ocsFolder but
rather looks up the "child" folders for aggregation using regular SOPE
techniques.
=> hm, do we need "aspects" in SOPE? ;-)
Note: this class retains appointment folders looked up, so watch out for
reference cycles!
*/
@class NSMutableDictionary;
@interface SOGoGroupAppointmentFolder : SOGoAppointmentFolder
{
NSMutableDictionary *uidToFolder;
}
@end
#endif /* __Appointments_SOGoGroupAppointmentFolder_H__ */

View File

@ -1,254 +0,0 @@
/*
Copyright (C) 2004-2005 SKYRIX Software AG
This file is part of OpenGroupware.org.
OGo 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.
OGo 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 OGo; see the file COPYING. If not, write to the
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSException.h>
#import <NGObjWeb/SoSecurityManager.h>
#import <NGExtensions/NSNull+misc.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGCards/iCalEntityObject.h>
#import <SOGo/SOGoGroupFolder.h>
#import <SOGo/SOGoPermissions.h>
#import "SOGoGroupAppointmentFolder.h"
@implementation SOGoGroupAppointmentFolder
+ (int)version {
return [super version] + 0 /* v1 */;
}
+ (void)initialize {
NSAssert2([super version] == 1,
@"invalid superclass (%@) version %i !",
NSStringFromClass([self superclass]), [super version]);
}
- (void)dealloc {
[self->uidToFolder release];
[super dealloc];
}
/* looking up shared objects */
- (SOGoGroupsFolder *)lookupGroupsFolder {
return [[self container] lookupGroupsFolder];
}
/* selection */
- (NSArray *)calendarUIDs {
return [[self container] valueForKey:@"uids"];
}
/* folders */
- (void)resetFolderCaches {
[self->uidToFolder release]; self->uidToFolder = nil;
}
- (SOGoAppointmentFolder *)folderForUID:(NSString *)_uid {
if (self->uidToFolder == nil) {
// TODO: can we trigger a fetch?
[self errorWithFormat:
@"called -folderForUID method before fetchCoreInfos .."];
return nil;
}
return [self->uidToFolder objectForKey:_uid];
}
/* merging */
- (BOOL)doesRecord:(NSDictionary *)_rec conflictWith:(NSDictionary *)_other {
if (_rec == _other)
return NO;
if ([_rec isEqual:_other])
return NO;
return YES;
}
- (NSDictionary *)_registerConflictingRecord:(NSDictionary *)_other
inRecord:(NSDictionary *)_record
{
NSMutableArray *conflicts;
if (_record == nil) return _other;
if (_other == nil) return _record;
if ((conflicts = [_record objectForKey:@"conflicts"]) == nil) {
NSMutableDictionary *md;
md = [[_record mutableCopy] autorelease];
conflicts = [NSMutableArray arrayWithCapacity:4];
[md setObject:conflicts forKey:@"conflicts"];
_record = md;
}
[conflicts addObject:_other];
return _record;
}
/* functionality */
- (SOGoAppointmentFolder *)calendarFolderForMemberFolder:(id)_folder {
SOGoAppointmentFolder *aptFolder;
if (![_folder isNotNull])
return nil;
aptFolder = [_folder lookupName:@"Calendar" inContext:nil acquire:NO];
if (![aptFolder isNotNull])
return nil;
if (![aptFolder respondsToSelector:@selector(fetchCoreInfosFrom:to:component:)]) {
[self errorWithFormat:@"folder does not implemented required API: %@",
_folder];
return nil;
}
return aptFolder;
}
/* overridden */
- (NSArray *) fetchFields: (NSArray *) _fields
from: (NSCalendarDate *) _startDate
to: (NSCalendarDate *) _endDate
component: (id) _component
{
NSArray *folders;
NSMutableArray *result;
NSMutableDictionary *uidToRecord;
unsigned i, count;
SoSecurityManager *securityManager;
securityManager = [SoSecurityManager sharedSecurityManager];
folders = [[self container] memberFolders];
[self resetFolderCaches];
if ((count = [folders count]) == 0)
return [NSArray array];
if (self->uidToFolder == nil)
self->uidToFolder = [[NSMutableDictionary alloc] initWithCapacity:7*count];
else
[self->uidToFolder removeAllObjects];
uidToRecord = [NSMutableDictionary dictionaryWithCapacity:(7 * count)];
result = [NSMutableArray arrayWithCapacity:(7 * count)];
for (i = 0; i < count; i++) {
SOGoAppointmentFolder *aptFolder;
id results;
NSDictionary *record;
aptFolder = [self calendarFolderForMemberFolder:
[folders objectAtIndex:i]];
if (![aptFolder isNotNull]) {
[self debugWithFormat:@"did not find a Calendar folder in folder: %@",
[folders objectAtIndex:i]];
continue;
}
if ([securityManager validatePermission: SoPerm_AccessContentsInformation
onObject: aptFolder
inContext: context]) {
[self debugWithFormat:@"no permission to read the content of calendar: %@",
[folders objectAtIndex:i]];
continue;
}
results = [aptFolder fetchFields: _fields
from: _startDate
to: _endDate
title: nil
component: _component];
if (![results isNotNull]) continue;
results = [results objectEnumerator];
while ((record = [results nextObject])) {
NSString *uid;
NSDictionary *existingRecord;
uid = [record objectForKey:@"uid"];
if (![uid isNotNull]) {
[self warnWithFormat:@"record without uid: %@", result];
[result addObject:record];
continue;
}
if ((existingRecord = [uidToRecord objectForKey:uid]) == nil) {
/* record not yet in result set */
[uidToRecord setObject:record forKey:uid];
[result addObject:record];
[self->uidToFolder setObject:aptFolder forKey:uid];
}
else if ([self doesRecord:existingRecord conflictWith:record]) {
/* record already registered and it conflicts (diff values) */
NSDictionary *newRecord;
int idx;
newRecord = [self _registerConflictingRecord:record
inRecord:existingRecord];
[uidToRecord setObject:newRecord forKey:uid];
if ((idx = [result indexOfObject:existingRecord]) != NSNotFound)
[result replaceObjectAtIndex:idx withObject:newRecord];
}
else {
/* record already registered, but values in sync, nothing to do */
}
}
}
return result;
}
/* URL generation */
- (NSString *)baseURLForAptWithUID:(NSString *)_uid inContext:(id)_ctx {
/* Note: fetchCore must have been called before this works */
SOGoAppointmentFolder *folder;
if ([_uid length] == 0) {
[self errorWithFormat:@"got invalid UID."];
return nil;
}
if ((folder = [self folderForUID:_uid]) == nil) {
[self errorWithFormat:@"did not find a folder containing UID: '%@'",
_uid];
return nil;
}
if (![folder respondsToSelector:_cmd]) {
[self errorWithFormat:@"found folder cannot construct UID URLs: %@",
folder];
return nil;
}
[self debugWithFormat:@"found ID %@ in folder: %@", _uid, folder];
return [folder baseURLForAptWithUID:_uid inContext:_ctx];
}
@end /* SOGoGroupAppointmentFolder */

View File

@ -1,58 +0,0 @@
We can basically store anything we want in the property list. But we should
watch inetOrgPerson and vCard person compatibility in case we want to move
to vCard storage later on.
inetOrgPerson fields
====================
businessCategory
carLicense
departmentNumber
destinationIndicator
employeeNumber
employeeType
facsimileTelephoneNumber
givenName
homePostalAddress
initials
jpegPhoto
l
mail
manager
mobile
o
objectClass
ou
pager
physicalDeliveryOfficeName
postOfficeBox
postalCode
preferredLanguage
registeredAddress
roomNumber
secretary
seeAlso
sn
street
telephoneNumber
teletexTerminalIdentifier
title
uid
userCertificate
userPKCS12
userPassword
x121Address
audio
cn
description
displayName
homePhone
internationaliSDNNumber
labeledURI
photo
postalAddress
preferredDeliveryMethod
st
telexNumber
userSMIMECertificate
x500uniqueIdentifier

View File

@ -1,60 +0,0 @@
# README for Mailer SoObjects
Class Overview
==============
SOGoMailManager
- backend class connecting to NGImap4, will probably move to SOGoLogic
Class Hierarchy
===============
[NSObject]
SOGoMailerProduct
<SOGoObject>
SOGoMailAccounts
SOGoMailBaseObject
SOGoDraftObject
SOGoDraftsFolder
SOGoMailAccount
SOGoSharedMailAccount
SOGoMailBodyPart
SOGoImageMailBodyPart
SOGoMessageMailBodyPart
SOGoMailFolder
SOGoSharedInboxFolder
SOGoMailObject
[EODataSource]
SOGoMailFolderDataSource
Defaults
========
SOGoEnableIMAP4Debug YES|NO - enable/disable debugging in SOGoMailManager
SOGoDisableIMAP4Pooling YES|NO - disable IMAP4 connection pooling
SOGoMailSpoolPath path - FS path where mail drafts are stored
SOGoNoDraftDeleteAfterSend YES|NO - makes the draft's -delete method a NOOP
SOGoSpecialFoldersInRoot YES|NO - do special folders live under INBOX?
- corresponds to the Cyrus setting: "altnamespace: yes"
SOGoEnableSieveFolder YES|NO - should the Sieve folder be visible?
SOGoSharedFolderName IMAP4-Name
- corresponds to the Cyrus setting: sharedprefix
SOGoOtherUsersFolderName IMAP4-Name
- corresponds to the Cyrus setting: userprefix
SOGoInternetMailSuffix String-Pattern
- suffix to add to mails sent via Internet
- eg: -SOGoInternetMailSuffix \
'"*** This email was composed using SOGo on the public Internet ***"'
you can access request values inside the pattern, eg:
"$headers.host$"
SOGoDoNotFetchMailHeader YES|NO - whether or not to fetch the mail header
- the mail header is ~4KB to fetch, a slowdown of ~13ms on the dev system
- the header gives much more information about the mail
- eg: spam status
- parsing the mail header takes time
SOGoMailDisableETag YES|NO - whether or not to check/deliver an etag

View File

@ -1,9 +0,0 @@
# $Id$
SoObjects
=========
The SoObjects directory contains SOPE "path controller" objects, those objects
which are bound to the URL traversal path.
Also contained is a common library for such objects (libSOGo).

View File

@ -11,9 +11,6 @@ SOGo_INSTALL_DIR = $(SOGO_LIBDIR)
SOGo_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
# SOGoCustomGroupFolder.h \
# SOGoGroupsFolder.h \
# SOGoGroupFolder.h
SOGo_HEADER_FILES = \
SOGoBuild.h \
SOGoProductLoader.h \
@ -72,9 +69,6 @@ SOGo_HEADER_FILES = \
all::
@touch SOGoBuild.m
# SOGoCustomGroupFolder.m \
# SOGoGroupsFolder.m \
# SOGoGroupFolder.m
SOGo_OBJC_FILES = \
SOGoBuild.m \
SOGoProductLoader.m \

View File

@ -1,22 +0,0 @@
libSOGo
=======
Common SOGo objects.
NOTE: the SOPE objects are registered by the Main bundle products.plist.
Class Hierarchy
===============
[NSObject]
SOGoObject
SOGoContentObject
SOGoFolder
SOGoUserFolder - the "home" directory
SOGoGroupsFolder - intermediate folder
SOGoGroupFolder - a folder representing a set of people
SOGoCustomGroupFolder - a custom group (eg '_custom_helge,znek')
TODO
====
- why is SOGoUserFolder an OCS folder?

View File

@ -1,59 +0,0 @@
/*
Copyright (C) 2004 SKYRIX Software AG
This file is part of OpenGroupware.org.
OGo 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.
OGo 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 OGo; see the file COPYING. If not, write to the
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
// $Id: SOGoCustomGroupFolder.h 107 2004-06-30 10:26:46Z helge $
#ifndef __SOGo_SOGoCustomGroupFolder_H__
#define __SOGo_SOGoCustomGroupFolder_H__
#include <SOGo/SOGoGroupFolder.h>
/*
SOGoCustomGroupFolder
same parent/child like SOGoGroupFolder
Note: parent folder can be different if instantiated for internal use.
Note: you can use this folder for internal handling of groups! Eg aggregate
Calendar fetches.
This is a specific group folder for 'custom' groups. Group members are
currently encoded as the folder name in the URL like
_custom_znek,helge
*/
@class NSArray;
@interface SOGoCustomGroupFolder : SOGoGroupFolder
{
NSArray *uids;
}
- (id)initWithUIDs:(NSArray *)_uids inContainer:(id)_container;
/* accessors */
- (NSArray *)uids;
/* pathes */
@end
#endif /* __SOGo_SOGoCustomGroupFolder_H__ */

View File

@ -1,111 +0,0 @@
/*
Copyright (C) 2004 SKYRIX Software AG
This file is part of OpenGroupware.org.
OGo 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.
OGo 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 OGo; see the file COPYING. If not, write to the
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSString.h>
#import <NGExtensions/NSObject+Logs.h>
#import "SOGoCustomGroupFolder.h"
@implementation SOGoCustomGroupFolder
static NSString *SOGoUIDSeparator = @",";
- (id)initWithUIDs:(NSArray *)_uids inContainer:(id)_container {
if ((self = [self initWithName:nil inContainer:_container])) {
self->uids = [_uids copy];
}
return self;
}
- (void)dealloc {
[self->uids release];
[super dealloc];
}
/* accessors */
- (NSArray *)unescapeURLComponents:(NSArray *)_parts {
// #warning TODO: implement URL UID unescaping if necessary
// TODO: who calls this for what?
// Note: remember URL encoding!
return _parts;
}
- (NSArray *)uids {
NSArray *a;
NSString *s;
if (self->uids != nil)
return self->uids;
s = [self nameInContainer];
if (![s hasPrefix:@"_custom_"]) {
[self logWithFormat:@"WARNING: incorrect custom group folder name: '%@'",
s];
return nil;
}
s = [s substringFromIndex:8];
a = [s componentsSeparatedByString:SOGoUIDSeparator];
a = [self unescapeURLComponents:a];
self->uids = [a copy];
if ([self->uids count] < 2)
[self debugWithFormat:@"Note: less than two custom group members!"];
return self->uids;
}
/* display name */
- (NSString *)davDisplayName {
NSArray *a;
unsigned count;
a = [self uids];
if ((count = [a count]) == 0)
return @"empty";
if (count == 1)
return [a objectAtIndex:0];
if (count < 6) {
NSMutableString *ms;
unsigned i;
ms = [NSMutableString stringWithCapacity:64];
for (i = 0; i < count; i++) {
if (i != 0) [ms appendString:@"|"];
[ms appendString:[a objectAtIndex:i]];
if ([ms length] > 60) {
ms = nil;
break;
}
}
if (ms != nil) return ms;
}
// TODO: localize 'members' (UI component task?)
return [NSString stringWithFormat:@"Members: %d", count];
}
@end /* SOGoCustomGroupFolder */

View File

@ -1,58 +0,0 @@
/*
Copyright (C) 2004 SKYRIX Software AG
This file is part of OpenGroupware.org.
OGo 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.
OGo 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 OGo; see the file COPYING. If not, write to the
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
// $Id: SOGoGroupFolder.h 107 2004-06-30 10:26:46Z helge $
#ifndef __SOGo_SOGoGroupFolder_H__
#define __SOGo_SOGoGroupFolder_H__
#include <SOGo/SOGoObject.h>
/*
SOGoGroupFolder
Parent object: the SOGoGroupsFolder
Child objects:
*/
@class NSArray, NSDictionary;
@interface SOGoGroupFolder : SOGoObject
{
NSDictionary *uidToFolder;
NSArray *folders;
}
/* accessors */
- (NSArray *)uids;
/* folder management */
- (NSArray *)memberFolders;
- (id)folderForUID:(NSString *)_uid;
- (void)resetFolderCaches;
- (void)sleep;
/* pathes */
@end
#endif /* __SOGo_SOGoGroupFolder_H__ */

View File

@ -1,225 +0,0 @@
/*
Copyright (C) 2004 SKYRIX Software AG
This file is part of OpenGroupware.org.
OGo 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.
OGo 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 OGo; see the file COPYING. If not, write to the
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSString.h>
#import <NGObjWeb/WOContext.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/NSException+HTTP.h>
#import <NGExtensions/NGLogger.h>
#import <NGExtensions/NGLoggerManager.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSNull+misc.h>
#import "SOGoGroupFolder.h"
@implementation SOGoGroupFolder
static NGLogger *logger = nil;
+ (void) initialize
{
NGLoggerManager *lm;
if (!logger)
{
lm = [NGLoggerManager defaultLoggerManager];
logger = [lm loggerForDefaultKey:@"SOGoGroupFolderDebugEnabled"];
}
}
- (void) dealloc
{
[uidToFolder release];
[folders release];
[super dealloc];
}
/* logging */
- (id)debugLogger {
return logger;
}
/* accessors */
- (NSArray *)uids {
[self errorWithFormat:@"instantiated abstract Group folder class!"];
return nil;
}
/* folder management */
- (id)_primaryLookupFolderForUID:(NSString *)_uid inContext:(id)_ctx {
NSException *error = nil;
NSArray *path;
id ctx, result;
/* create subcontext, so that we don't destroy our environment */
if ((ctx = [_ctx createSubContext]) == nil) {
[self errorWithFormat:@"could not create SOPE subcontext!"];
return nil;
}
/* build path */
path = _uid != nil ? [NSArray arrayWithObjects:&_uid count:1] : nil;
/* traverse path */
result = [[ctx application] traversePathArray:path inContext:ctx
error:&error acquire:NO];
if (error != nil) {
[self errorWithFormat:@"folder lookup failed (uid=%@): %@",
_uid, error];
return nil;
}
if (logger)
[self debugWithFormat:@"Note: got folder for uid %@ path %@: %@",
_uid, [path componentsJoinedByString:@"=>"], result];
return result;
}
- (void)_setupFolders {
NSMutableDictionary *md;
NSMutableArray *ma;
NSArray *luids;
unsigned i, count;
if (uidToFolder != nil)
return;
if ((luids = [self uids]) == nil)
return;
#warning we should populate "uidToFolder" directly
count = [luids count];
ma = [NSMutableArray arrayWithCapacity:count + 1];
md = [NSMutableDictionary dictionaryWithCapacity:count];
for (i = 0; i < count; i++) {
NSString *uid;
id folder;
uid = [luids objectAtIndex:i];
folder = [self _primaryLookupFolderForUID:uid inContext: context];
if ([folder isNotNull]) {
[md setObject:folder forKey:uid];
[ma addObject:folder];
}
else
[ma addObject:[NSNull null]];
}
/* fix results */
uidToFolder = [md copy];
folders = [[NSArray alloc] initWithArray:ma];
}
- (NSArray *)memberFolders {
[self _setupFolders];
return folders;
}
- (id)folderForUID:(NSString *)_uid {
[self _setupFolders];
if ([_uid length] == 0)
return nil;
return [uidToFolder objectForKey:_uid];
}
- (void) resetFolderCaches
{
[uidToFolder release];
uidToFolder = nil;
[folders release];
folders = nil;
}
- (void) sleep
{
[self resetFolderCaches];
[super sleep];
}
/* SOPE */
- (BOOL) isFolderish
{
return YES;
}
/* looking up shared objects */
- (SOGoGroupsFolder *) lookupGroupsFolder
{
return [[self container] lookupGroupsFolder];
}
/* pathes */
/* name lookup */
- (id) groupCalendar: (NSString *) _key
inContext: (id) _ctx
{
static Class calClass = Nil;
id calendar;
if (calClass == Nil)
calClass = NSClassFromString(@"SOGoGroupAppointmentFolder");
if (calClass == Nil) {
[self errorWithFormat:@"missing SOGoGroupAppointmentFolder class!"];
return nil;
}
calendar = [[calClass alloc] initWithName:_key inContainer:self];
// TODO: should we pass over the uids in questions or should the
// appointment folder query its container for that info?
return [calendar autorelease];
}
- (id) lookupName: (NSString *) _key
inContext: (id) _ctx
acquire: (BOOL) _flag
{
id obj;
/* first check attributes directly bound to the application */
if ((obj = [super lookupName:_key inContext:_ctx acquire:NO]))
return obj;
if ([_key isEqualToString:@"Calendar"])
return [self groupCalendar:_key inContext:_ctx];
/* return 404 to stop acquisition */
return [NSException exceptionWithHTTPStatus:404 /* Not Found */];
}
@end /* SOGoGroupFolder */

View File

@ -1,59 +0,0 @@
/*
Copyright (C) 2004 SKYRIX Software AG
This file is part of OpenGroupware.org.
OGo 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.
OGo 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 OGo; see the file COPYING. If not, write to the
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
// $Id: SOGoGroupsFolder.h 107 2004-06-30 10:26:46Z helge $
#ifndef __SOGo_SOGoGroupsFolder_H__
#define __SOGo_SOGoGroupsFolder_H__
#include <SOGo/SOGoObject.h>
/*
SOGoGroupsFolder
Parent object: the SOGoUserFolder
Child objects: SOGoGroupFolder objects
'_custom_*': SOGoCustomGroupFolder
This object represents a collection of groups, its the "Groups" in such a
path:
/SOGo/so/znek/Groups/sales
It also acts as a factory for the proper group folders, eg "custom" groups
(arbitary person collections) or later on cookie based configured groups or
groups stored in LDAP.
*/
@class NSString;
@interface SOGoGroupsFolder : SOGoObject
{
}
/* accessors */
/* looking up shared objects */
- (SOGoGroupsFolder *)lookupGroupsFolder;
/* pathes */
@end
#endif /* __SOGo_SOGoGroupsFolder_H__ */

View File

@ -1,91 +0,0 @@
/*
Copyright (C) 2004 SKYRIX Software AG
This file is part of OpenGroupware.org.
OGo 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.
OGo 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 OGo; see the file COPYING. If not, write to the
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
#import <NGObjWeb/NSException+HTTP.h>
#import <NGExtensions/NSObject+Logs.h>
#import "SOGoGroupsFolder.h"
@implementation SOGoGroupsFolder
// - (void)dealloc {
// [super dealloc];
// }
/* accessors */
/* SOPE */
- (BOOL) isFolderish
{
return YES;
}
/* looking up shared objects */
- (SOGoGroupsFolder *) lookupGroupsFolder
{
return self;
}
/* pathes */
/* name lookup */
- (id) customGroup: (NSString *) _key
inContext: (id) _ctx
{
static Class groupClass = Nil;
id group;
if (!groupClass)
groupClass = NSClassFromString(@"SOGoCustomGroupFolder");
if (!groupClass)
{
[self logWithFormat:@"ERROR: missing SOGoCustomGroupFolder class!"];
group = nil;
}
else
group = [groupClass objectWithName: _key inContainer: self];
return group;
}
- (id) lookupName: (NSString *) _key
inContext: (id) _ctx
acquire: (BOOL) _flag
{
id obj;
/* first check attributes directly bound to the application */
obj = [super lookupName: _key inContext: _ctx acquire: NO];
if (!obj)
{
if ([_key hasPrefix: @"_custom_"])
obj = [self customGroup: _key inContext: _ctx];
else
obj = [NSException exceptionWithHTTPStatus:404 /* Not Found */];
}
return obj;
}
@end /* SOGoGroupsFolder */

View File

@ -324,11 +324,6 @@
return [container lookupUserFolder];
}
// - (SOGoGroupsFolder *) lookupGroupsFolder
// {
// return [[self lookupUserFolder] lookupGroupsFolder];
// }
- (void) sleep
{
if ([self doesRetainContainer])

View File

@ -28,7 +28,6 @@
SOGoUserFolder
Parent object: the root object (SoApplication object)
Child objects:
'Groups': SOGoGroupsFolder
'Calendar': SOGoAppointmentFolder
The SOGoUserFolder is the "home directory" of the user where all his

View File

@ -1,178 +0,0 @@
SOGO Mailer UI
==============
- own (Thunderbird styled) frame
- component for tree
TODO
====
- a lot ;->
- SOPE: does not recognize <input type="button"> !
Components
==========
UIxMailAccountView.wox
UIxMailAccountsView.wox
UIxMailEditor.wox
UIxMailToSelection.wox
UIxMailListView.wox
UIxMailMainFrame.wox
UIxMailTree.wox
UIxMailView.wox
Class Hierarchy
===============
[NSObject]
MailerUIProduct
[WOComponent]
[SoComponent]
<UIxComponent>
UIxFilterList
UIxMailAccountView
UIxMailAccountsView
UIxMailAddressbook
UIxMailEditor
(Scheduler_Privates)
UIxMailListView
UIxMailMainFrame
UIxMailToSelection
UIxMailToolbar
UIxMailTree
UIxMailView
UIxMailSortableTableHeader
UIxMailEditorAttach.m
UIxMailFilterPanel
UIxMailMoveToPopUp
UIxMailWindowCloser
[WODirectAction]
UIxMailEditorAction
UIxMailForwardAction
UIxMailReplyAction
[NSFormatter]
UIxMailFormatter
UIxMailDateFormatter
UIxSubjectFormatter
UIxEnvelopeAddressFormatter
UIxMailTreeBlock
[WOContext]
(UIxMailer)
Defaults
========
SOGoShowInternetMarker - bool
- show a marker in the editor that the request is from the outside
SOGoInternetDetectQualifier - string
- an EOQualifier to detect whether a set of HTTP headers is from the outside,
eg: "NOT (minequprovenance = 'intranet')"
-SOGoInternetDetectQualifier '"NOT (minequprovenance = \"intranet\")"'
Note: all header field names are lowercase
SOGoInternetMailHeaders - dictionary
- if a request was detected as coming from the Internet, add the mail headers
specified in this default
eg: { received = "sogo depuis internet"; }
-SOGoInternetMailHeaders "{received=\"sogo depuis internet\"; }"
SOGoMailEditorKeepTmpFile
- for debugging, if a mail was send, keep the file containing the MIME in the
temporary directory for review instead of deleting it
SOGoMailTreeRootClass
- configure the root class of the mail tree, eg:
- SOGoMailAccounts - standard view, show all IMAP4 accounts
- SOGoMailAccount - just show the standard mail account (tree at Inbox!)
- SoApplication - stop at the application object (show all folders)
SOGoDontUseETagsForMailViewer - YES|NO
- when enable SOGo won't tag mail viewers with an entity-tag (HTTP etag)
- the etag ensures that the viewer will only get resend to the browser when
it changed. In the case of IMAP4 this is never because URLs are one-time
IDs in the IMAP4 server and messages cannot be edited in IMAP4
- use the default for debugging (otherwise you won't see changes ...)
SOGoUseLocationBasedSentFolder - YES | NO
- when enable SOGo looks up the Sent folder by traversing the lookup-path
until it finds a SOGoMailAccount object and then asks the account for the
Sent folder.
Notes
=====
- we might want to bind the content viewers as SOPE methods to the mail class?
eg "viewTextPlain"
- this would not return a WOComponent, but a SoPageInvocation
- caching might be more difficult
- some 'reuse component' support in SoPageInvocation for stateless
components?
- watch nested calls
- for this we would need to add support for embedded calling of SOPE methods
<var:component method="viewTextPlain" /> ?
Bodystructures
==============
Multiparts: multipart/MIXED, multipart/SIGNED
Feature: we fetch all plain/text bodies in a single run by traversing the
body structure.
Sample Bodystructure (GPG):
---snip---
{
parts = (
{
bodyId = "";
description = "";
encoding = "QUOTED-PRINTABLE";
lines = 22;
parameterList = {};
size = 731;
subtype = PLAIN;
type = text;
},
{
bodyId = "";
description = "Esta parte del mensaje";
encoding = 7BIT;
parameterList = {name = "signature.asc"; };
size = 196;
subtype = "PGP-SIGNATURE";
type = application;
}
);
subtype = SIGNED;
type = multipart;
}
---snap---
Sample Body Structure (Image):
---snip---
{
parts = (
{
bodyId = "";
description = "";
encoding = BASE64;
parameterList = {name = "PoseChau.jpg"; "x-unix-mode" = 0644; };
size = 58370;
subtype = JPEG;
type = image;
},
{
bodyId = "";
description = "";
encoding = 7BIT;
lines = 2;
parameterList = {charset = "US-ASCII"; format = flowed; };
size = 57;
subtype = PLAIN;
type = text;
}
);
subtype = MIXED;
type = multipart;
}
---snap---

View File

@ -1,4 +0,0 @@
MainUI
======
TODO: document